@starci/hfs 4.3.0 → 4.4.1

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 (538) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/README.md +1 -1
  3. package/db/migrate.mjs +361 -0
  4. package/db/post-cutover.mjs +136 -0
  5. package/emit/contracts.mjs +2 -2
  6. package/emit/db-types.mjs +12 -3
  7. package/lint/run.mjs +3 -3
  8. package/package.json +4 -1
  9. package/release/gate.mjs +298 -0
  10. package/release/index.mjs +103 -0
  11. package/release/push.mjs +110 -0
  12. package/report/sonar.mjs +1 -1
  13. package/runtime/config.example.yaml +7 -6
  14. package/runtime/engine/config.mjs +10 -18
  15. package/runtime/engine/removed-vocabulary.mjs +0 -2
  16. package/runtime/knowledge/hfs/canon-pins.yaml +11 -11
  17. package/runtime/knowledge/hfs/fe-stack.yaml +22 -1
  18. package/runtime/knowledge/hfs/rules.yaml +2855 -163
  19. package/runtime/knowledge/hfs/slots.yaml +333 -62
  20. package/runtime/knowledge/patterns/be/api.yaml +32 -5
  21. package/runtime/knowledge/patterns/be/cli.yaml +14 -4
  22. package/runtime/knowledge/patterns/be/event-bus.yaml +3 -3
  23. package/runtime/knowledge/patterns/be/jobs.yaml +20 -2
  24. package/runtime/knowledge/patterns/be/projections.yaml +4 -2
  25. package/runtime/knowledge/patterns/be/queues.yaml +11 -3
  26. package/runtime/knowledge/patterns/be/reactors.yaml +20 -1
  27. package/runtime/knowledge/patterns/be/realtime.yaml +25 -3
  28. package/runtime/knowledge/patterns/be/saga.yaml +20 -3
  29. package/runtime/knowledge/patterns/be/webhooks.yaml +23 -4
  30. package/runtime/knowledge/patterns/fe/folder.yaml +1 -0
  31. package/runtime/knowledge/sonar-gate.yaml +1 -1
  32. package/runtime/modules/kernel/failure-codes.yaml +3091 -43
  33. package/runtime/modules/kernel/removed-vocabulary.yaml +30 -0
  34. package/runtime/modules/models/runtimes.yaml +5 -7
  35. package/runtime/modules/schemas/application-stacks.schema.yaml +663 -0
  36. package/runtime/packages/cli/src/catalog.generated.mjs +13769 -0
  37. package/runtime/packages/cli/src/validate-args.mjs +213 -0
  38. package/runtime/scripts/api/git/add.mjs +5 -0
  39. package/runtime/scripts/api/git/init.mjs +7 -0
  40. package/runtime/scripts/api/git/lib.mjs +4 -1
  41. package/runtime/scripts/api/git/tag.mjs +5 -0
  42. package/runtime/scripts/api/node/lib.mjs +20 -0
  43. package/runtime/scripts/api/node/run-node.mjs +6 -0
  44. package/runtime/scripts/api/sops/lib.mjs +42 -1
  45. package/runtime/scripts/api/sops/selected-age-recipient.mjs +7 -0
  46. package/runtime/scripts/api/supabase/database-dump.mjs +5 -0
  47. package/runtime/scripts/api/supabase/database-query.mjs +5 -0
  48. package/runtime/scripts/api/supabase/lib.mjs +44 -0
  49. package/runtime/scripts/api/supabase/migration-repair.mjs +5 -0
  50. package/runtime/scripts/hfs/app-wiring.mjs +201 -0
  51. package/runtime/scripts/hfs/architecture/backend-app-files.mjs +1 -8
  52. package/runtime/scripts/hfs/architecture/backend.mjs +2 -7
  53. package/runtime/scripts/hfs/architecture/client-reaches-server.mjs +6 -3
  54. package/runtime/scripts/hfs/architecture/config.mjs +1 -1
  55. package/runtime/scripts/hfs/architecture/dead-exports-bindings.mjs +149 -0
  56. package/runtime/scripts/hfs/architecture/dead-exports.mjs +9 -41
  57. package/runtime/scripts/hfs/architecture/default-deny.mjs +8 -6
  58. package/runtime/scripts/hfs/architecture/frontend-world.mjs +1 -1
  59. package/runtime/scripts/hfs/architecture/function-spec-providers.mjs +153 -0
  60. package/runtime/scripts/hfs/architecture/hfs.mjs +3 -3
  61. package/runtime/scripts/hfs/architecture/index.mjs +1 -1
  62. package/runtime/scripts/hfs/architecture/module-per-transport.mjs +28 -13
  63. package/runtime/scripts/hfs/architecture/next-data-inference.mjs +176 -0
  64. package/runtime/scripts/hfs/architecture/next-data-symbols.mjs +26 -0
  65. package/runtime/scripts/hfs/architecture/next-data.mjs +31 -23
  66. package/runtime/scripts/hfs/architecture/reachability.mjs +14 -0
  67. package/runtime/scripts/hfs/architecture/register-once.mjs +2 -2
  68. package/runtime/scripts/hfs/architecture/source-names.mjs +48 -3
  69. package/runtime/scripts/hfs/architecture/supabase-ast.mjs +211 -11
  70. package/runtime/scripts/hfs/architecture/supabase-be.mjs +1 -1
  71. package/runtime/scripts/hfs/architecture/supabase.mjs +59 -21
  72. package/runtime/scripts/hfs/architecture/surface.mjs +2 -1
  73. package/runtime/scripts/hfs/architecture/tiers.mjs +4 -4
  74. package/runtime/scripts/hfs/architecture/unit-spec-providers.mjs +8 -2
  75. package/runtime/scripts/hfs/architecture.mjs +1 -1
  76. package/runtime/scripts/hfs/check-results.mjs +28 -0
  77. package/runtime/scripts/hfs/check.mjs +46 -47
  78. package/runtime/scripts/hfs/coverage-from.mjs +70 -0
  79. package/runtime/scripts/hfs/coverage-scope.mjs +1 -1
  80. package/runtime/scripts/hfs/db-baseline-verb.mjs +276 -0
  81. package/runtime/scripts/hfs/db-plan-verb.mjs +254 -0
  82. package/runtime/scripts/hfs/db-restamp-verb.mjs +60 -0
  83. package/runtime/scripts/hfs/declaration-shape.mjs +39 -3
  84. package/runtime/scripts/hfs/doc-commands.mjs +367 -0
  85. package/runtime/scripts/hfs/edition-slots.mjs +2 -2
  86. package/runtime/scripts/hfs/example-secrets.mjs +158 -0
  87. package/runtime/scripts/hfs/manifest-shape.mjs +69 -9
  88. package/runtime/scripts/hfs/param-names.mjs +1 -1
  89. package/runtime/scripts/hfs/refusal-codes.mjs +6 -0
  90. package/runtime/scripts/hfs/rule-catalog.mjs +158 -11
  91. package/runtime/scripts/hfs/rule-params-shape.mjs +22 -10
  92. package/runtime/scripts/hfs/rules/a15-findings.mjs +88 -0
  93. package/runtime/scripts/hfs/rules/app-env-required.mjs +20 -0
  94. package/runtime/scripts/hfs/rules/app-root.mjs +2 -2
  95. package/runtime/scripts/hfs/rules/assets.mjs +79 -0
  96. package/runtime/scripts/hfs/rules/boot-proof.mjs +16 -0
  97. package/runtime/scripts/hfs/rules/canon-copy-drift.mjs +59 -0
  98. package/runtime/scripts/hfs/rules/cli.mjs +1 -1
  99. package/runtime/scripts/hfs/rules/contract-compat.mjs +1 -1
  100. package/runtime/scripts/hfs/rules/contract.mjs +67 -6
  101. package/runtime/scripts/hfs/rules/coverage-below.mjs +230 -0
  102. package/runtime/scripts/hfs/rules/database-access.mjs +343 -0
  103. package/runtime/scripts/hfs/rules/database-baseline.mjs +142 -0
  104. package/runtime/scripts/hfs/rules/database-config.mjs +250 -2
  105. package/runtime/scripts/hfs/rules/database-constants.mjs +9 -0
  106. package/runtime/scripts/hfs/rules/database-migrations.mjs +286 -7
  107. package/runtime/scripts/hfs/rules/database-plpgsql.mjs +119 -9
  108. package/runtime/scripts/hfs/rules/database-queue-sources.mjs +176 -0
  109. package/runtime/scripts/hfs/rules/database-queues.mjs +361 -0
  110. package/runtime/scripts/hfs/rules/database-sql.mjs +91 -9
  111. package/runtime/scripts/hfs/rules/database.mjs +9 -0
  112. package/runtime/scripts/hfs/rules/deploy-scan.mjs +192 -0
  113. package/runtime/scripts/hfs/rules/deploy-workflow.mjs +219 -0
  114. package/runtime/scripts/hfs/rules/doc-fresh.mjs +286 -0
  115. package/runtime/scripts/hfs/rules/docker-health.mjs +249 -0
  116. package/runtime/scripts/hfs/rules/docker.mjs +24 -7
  117. package/runtime/scripts/hfs/rules/edition.mjs +9 -8
  118. package/runtime/scripts/hfs/rules/env-parity.mjs +373 -0
  119. package/runtime/scripts/hfs/rules/env-value-shape.mjs +113 -0
  120. package/runtime/scripts/hfs/rules/event-bus.mjs +3 -2
  121. package/runtime/scripts/hfs/rules/event-tables.mjs +100 -0
  122. package/runtime/scripts/hfs/rules/fe-contract-documents.mjs +115 -15
  123. package/runtime/scripts/hfs/rules/fe-stack.mjs +57 -0
  124. package/runtime/scripts/hfs/rules/feature-files.mjs +28 -0
  125. package/runtime/scripts/hfs/rules/frontend-tree.mjs +54 -35
  126. package/runtime/scripts/hfs/rules/integration-specs.mjs +3 -2
  127. package/runtime/scripts/hfs/rules/lexicon.mjs +62 -0
  128. package/runtime/scripts/hfs/rules/lite-proof-lane.mjs +89 -0
  129. package/runtime/scripts/hfs/rules/monorepo.mjs +14 -1
  130. package/runtime/scripts/hfs/rules/pipeline.mjs +8 -1
  131. package/runtime/scripts/hfs/rules/release-provenance.mjs +211 -0
  132. package/runtime/scripts/hfs/rules/saga-delivery.mjs +66 -0
  133. package/runtime/scripts/hfs/rules/saga.mjs +8 -16
  134. package/runtime/scripts/hfs/rules/script-hygiene.mjs +151 -0
  135. package/runtime/scripts/hfs/rules/secret-custody-only.mjs +65 -0
  136. package/runtime/scripts/hfs/rules/secrets.mjs +13 -0
  137. package/runtime/scripts/hfs/rules/services.mjs +4 -4
  138. package/runtime/scripts/hfs/rules/stack-tooling.mjs +93 -0
  139. package/runtime/scripts/hfs/rules/stacks-deploy.mjs +76 -0
  140. package/runtime/scripts/hfs/rules/stacks-ingress.mjs +87 -0
  141. package/runtime/scripts/hfs/rules/stacks-lite-backing.mjs +111 -0
  142. package/runtime/scripts/hfs/rules/stacks-release.mjs +366 -0
  143. package/runtime/scripts/hfs/rules/stacks-runtime.mjs +41 -1
  144. package/runtime/scripts/hfs/rules/stacks-swarm.mjs +417 -0
  145. package/runtime/scripts/hfs/rules/supabase-secrets.mjs +2 -2
  146. package/runtime/scripts/hfs/rules/supply-chain.mjs +167 -0
  147. package/runtime/scripts/hfs/rules/unused-symbol-flow.mjs +101 -0
  148. package/runtime/scripts/hfs/rules/unused-symbol-ledger.mjs +77 -0
  149. package/runtime/scripts/hfs/rules/unused-symbol-translators.mjs +165 -0
  150. package/runtime/scripts/hfs/rules/unused-symbol-values.mjs +103 -0
  151. package/runtime/scripts/hfs/rules/unused-symbol.mjs +320 -0
  152. package/runtime/scripts/hfs/runtime-rules/source-ast.mjs +185 -0
  153. package/runtime/scripts/hfs/runtime-rules/workflow-source.mjs +19 -0
  154. package/runtime/scripts/hfs/sealed-members.mjs +101 -0
  155. package/runtime/scripts/hfs/secret-bootstrap-crypto.mjs +200 -0
  156. package/runtime/scripts/hfs/secret-edit.mjs +170 -0
  157. package/runtime/scripts/hfs/secret-init.mjs +127 -19
  158. package/runtime/scripts/hfs/secret-sops.mjs +38 -6
  159. package/runtime/scripts/hfs/secret-store.mjs +56 -54
  160. package/runtime/scripts/hfs/secret.mjs +34 -5
  161. package/runtime/scripts/hfs/slot-imports.mjs +18 -5
  162. package/runtime/scripts/hfs/slots.mjs +3 -2
  163. package/runtime/scripts/hfs/stack-config-kit.mjs +34 -0
  164. package/runtime/scripts/hfs/stack-deploy-config.mjs +313 -0
  165. package/runtime/scripts/hfs/stack-ingress-config.mjs +237 -0
  166. package/runtime/scripts/hfs/stacks-gate.mjs +414 -0
  167. package/runtime/scripts/hfs/starcistacks-runtime.mjs +61 -0
  168. package/runtime/scripts/hfs/typescript-programs.mjs +0 -8
  169. package/runtime/scripts/lib/command-tokens.mjs +126 -0
  170. package/runtime/scripts/lib/compose-values.mjs +11 -0
  171. package/runtime/scripts/lib/deployment-findings.mjs +7 -0
  172. package/runtime/scripts/lib/env.mjs +2 -2
  173. package/runtime/scripts/lib/git.mjs +1 -1
  174. package/runtime/scripts/lib/i18n.mjs +0 -2
  175. package/runtime/scripts/lib/json-clone.mjs +61 -0
  176. package/runtime/scripts/lib/language.mjs +1 -1
  177. package/runtime/scripts/lib/list.mjs +4 -0
  178. package/runtime/scripts/lib/roots.mjs +2 -4
  179. package/runtime/scripts/lib/runtime-example.mjs +13 -0
  180. package/runtime/scripts/lib/secret-patterns.mjs +60 -5
  181. package/runtime/scripts/lib/sql-ast.mjs +32 -0
  182. package/runtime/scripts/lib/stack-services.mjs +1 -1
  183. package/runtime/scripts/lib/swarm-stack.mjs +5 -18
  184. package/runtime/scripts/lib/trim-end.mjs +8 -0
  185. package/runtime/scripts/lib/ts-analysis.mjs +5 -2
  186. package/runtime/scripts/lib/ts-ast.mjs +27 -2
  187. package/runtime/scripts/lib/workflow-events.mjs +8 -0
  188. package/scaffold/add-app.mjs +77 -59
  189. package/scaffold/add-cli-lite.mjs +14 -6
  190. package/scaffold/add-compose.mjs +79 -0
  191. package/scaffold/add-database-lite.mjs +14 -0
  192. package/scaffold/add-fe-overlay.mjs +1 -0
  193. package/scaffold/add-fe-page.mjs +1 -0
  194. package/scaffold/add-inbox-lite.mjs +74 -42
  195. package/scaffold/add-table.mjs +110 -87
  196. package/scaffold/add.mjs +159 -44
  197. package/scaffold/app.mjs +124 -39
  198. package/scaffold/edition-gate.mjs +3 -3
  199. package/scaffold/lite-exports.mjs +2 -1
  200. package/scaffold/service.mjs +2 -2
  201. package/scaffold/supabase-ports.mjs +1 -1
  202. package/src/main.mjs +229 -116
  203. package/stack/age-install.mjs +37 -0
  204. package/stack/backup.mjs +100 -0
  205. package/stack/build-args.mjs +42 -0
  206. package/stack/build.mjs +173 -0
  207. package/stack/cli.mjs +130 -0
  208. package/stack/config.mjs +57 -0
  209. package/stack/context.mjs +57 -0
  210. package/stack/converge.mjs +107 -0
  211. package/stack/deploy.mjs +301 -0
  212. package/stack/digest.mjs +16 -0
  213. package/stack/docker-transport.mjs +53 -0
  214. package/stack/edge-alias.mjs +118 -0
  215. package/stack/errors.mjs +21 -0
  216. package/stack/image-scan.mjs +152 -0
  217. package/stack/ingress-create.mjs +114 -0
  218. package/stack/ingress-publish.mjs +273 -0
  219. package/stack/ingress.mjs +706 -0
  220. package/stack/jobs.mjs +51 -0
  221. package/stack/live-restore.mjs +177 -0
  222. package/stack/prepare.mjs +266 -0
  223. package/stack/private-file.mjs +22 -0
  224. package/stack/provision.mjs +90 -0
  225. package/stack/prune.mjs +46 -0
  226. package/stack/release-store.mjs +87 -0
  227. package/stack/remote.mjs +205 -0
  228. package/stack/render.mjs +149 -0
  229. package/stack/retire.mjs +47 -0
  230. package/stack/sealed.mjs +149 -0
  231. package/stack/task.mjs +42 -0
  232. package/stack/verify.mjs +99 -0
  233. package/sync/ci-commands.mjs +13 -0
  234. package/sync/format.mjs +1 -1
  235. package/sync/hygiene.mjs +1 -1
  236. package/sync/index.mjs +110 -54
  237. package/sync/stack-images.mjs +127 -0
  238. package/templates/app/ci-workflows/github/workflows/ci.yml +5 -1
  239. package/templates/app/ci-workflows/github/workflows/images.yml +15 -3
  240. package/templates/app/ci-workflows/github/workflows/stack-deploy.yml +148 -0
  241. package/templates/app/ci-workflows-lite/github/workflows/ci.yml +7 -3
  242. package/templates/app/ci-workflows-lite/github/workflows/db-deploy.yml +38 -6
  243. package/templates/app/ci-workflows-lite/github/workflows/images.yml +14 -2
  244. package/templates/app/ci-workflows-lite/github/workflows/stack-deploy.yml +148 -0
  245. package/templates/app/codegen-graphql.mjs.partial +13 -2
  246. package/templates/app/codegen-lite/scripts/codegen.mjs +6 -1
  247. package/templates/app/codegen-prelude.mjs.partial +8 -0
  248. package/templates/app/gitignore +3 -0
  249. package/templates/app/gitignore-lite +3 -0
  250. package/templates/app/package-scripts/package.json +1 -0
  251. package/templates/app/package-scripts/supabase.json +7 -0
  252. package/templates/app/package-scripts-lite/package.json +1 -7
  253. package/templates/app/skeleton/.editorconfig +1 -0
  254. package/templates/app/skeleton/.gitattributes +7 -1
  255. package/templates/app/skeleton/.github/dependabot.yml +17 -0
  256. package/templates/app/skeleton/.nvmrc +1 -1
  257. package/templates/app/skeleton/.starcistacks/application-stacks.yaml +134 -1
  258. package/templates/app/skeleton/.starcistacks/dev/README.md +16 -0
  259. package/templates/app/skeleton/.starcistacks/dev/environment.json +5 -0
  260. package/templates/app/skeleton/.starcistacks/dev/infra/compose/stack.yaml +71 -0
  261. package/templates/app/skeleton/.starcistacks/dev/runtime/env/KEYS.md +14 -0
  262. package/templates/app/skeleton/.starcistacks/production/README.md +37 -0
  263. package/templates/app/skeleton/.starcistacks/production/environment.json +5 -0
  264. package/templates/app/skeleton/.starcistacks/production/infra/swarm/Caddyfile +15 -0
  265. package/templates/app/skeleton/.starcistacks/production/infra/swarm/owner-actions.md +11 -0
  266. package/templates/app/skeleton/.starcistacks/production/infra/swarm/recovery/restore-proof.md +7 -0
  267. package/templates/app/skeleton/.starcistacks/production/infra/swarm/releases/current.yaml +6 -0
  268. package/templates/app/skeleton/.starcistacks/production/infra/swarm/releases/images.lock.yaml +9 -0
  269. package/templates/app/skeleton/.starcistacks/production/infra/swarm/releases/previous.yaml +6 -0
  270. package/templates/app/skeleton/.starcistacks/production/infra/swarm/stack.yaml +142 -0
  271. package/templates/app/skeleton/.starcistacks/production/runtime/env/KEYS.md +14 -0
  272. package/templates/app/skeleton/README.md +6 -6
  273. package/templates/app/skeleton/scripts/codegen.mjs +1 -2
  274. package/templates/app/skeleton-lite/.editorconfig +16 -0
  275. package/templates/app/skeleton-lite/.gitattributes +8 -0
  276. package/templates/app/skeleton-lite/.github/dependabot.yml +17 -0
  277. package/templates/app/skeleton-lite/.nvmrc +1 -0
  278. package/templates/app/skeleton-lite/.sops.yaml +3 -2
  279. package/templates/app/skeleton-lite/.starcistacks/application-stacks.yaml +178 -1
  280. package/templates/app/skeleton-lite/.starcistacks/dev/README.md +20 -0
  281. package/templates/app/skeleton-lite/.starcistacks/dev/environment.json +2 -1
  282. package/templates/app/skeleton-lite/.starcistacks/dev/infra/swarm/Caddyfile +16 -0
  283. package/templates/app/skeleton-lite/.starcistacks/dev/infra/swarm/owner-actions.md +11 -0
  284. package/templates/app/skeleton-lite/.starcistacks/dev/infra/swarm/recovery/restore-proof.md +7 -0
  285. package/templates/app/skeleton-lite/.starcistacks/dev/infra/swarm/releases/current.yaml +6 -0
  286. package/templates/app/skeleton-lite/.starcistacks/dev/infra/swarm/releases/images.lock.yaml +8 -0
  287. package/templates/app/skeleton-lite/.starcistacks/dev/infra/swarm/releases/previous.yaml +6 -0
  288. package/templates/app/skeleton-lite/.starcistacks/dev/infra/swarm/stack.yaml +120 -0
  289. package/templates/app/skeleton-lite/.starcistacks/dev/runtime/env/KEYS.md +18 -0
  290. package/templates/app/skeleton-lite/.starcistacks/production/README.md +38 -0
  291. package/templates/app/skeleton-lite/.starcistacks/production/environment.json +6 -0
  292. package/templates/app/skeleton-lite/.starcistacks/production/infra/swarm/Caddyfile +11 -0
  293. package/templates/app/skeleton-lite/.starcistacks/production/infra/swarm/owner-actions.md +11 -0
  294. package/templates/app/skeleton-lite/.starcistacks/production/infra/swarm/recovery/restore-proof.md +7 -0
  295. package/templates/app/skeleton-lite/.starcistacks/production/infra/swarm/releases/current.yaml +6 -0
  296. package/templates/app/skeleton-lite/.starcistacks/production/infra/swarm/releases/images.lock.yaml +8 -0
  297. package/templates/app/skeleton-lite/.starcistacks/production/infra/swarm/releases/previous.yaml +6 -0
  298. package/templates/app/skeleton-lite/.starcistacks/production/infra/swarm/stack.yaml +121 -0
  299. package/templates/app/skeleton-lite/.starcistacks/production/runtime/env/KEYS.md +21 -0
  300. package/templates/app/skeleton-lite/.starciwork/brand/index.yaml +12 -0
  301. package/templates/app/skeleton-lite/README.md +5 -3
  302. package/templates/app/skeleton-lite/supabase/config.toml +8 -1
  303. package/templates/app/skeleton-lite/supabase/migrations/__timestamp___baseline.sql +15 -6
  304. package/templates/app/upgrade-full/.starcistacks/dev/README.md +13 -7
  305. package/templates/be/image/worker/Dockerfile +1 -1
  306. package/templates/be/inbox/database-client.spec.ts.tpl +17 -18
  307. package/templates/be/inbox/database-client.ts.tpl +12 -11
  308. package/templates/be/inbox/delivery-recorded.event.ts.tpl +36 -0
  309. package/templates/be/inbox/event-index.ts.tpl +1 -0
  310. package/templates/be/inbox/events.json.tpl +10 -0
  311. package/templates/be/inbox/migration.sql.tpl +1 -0
  312. package/templates/be/inbox/platform/event-bus/event-bus.contracts.ts.tpl +42 -0
  313. package/templates/be/inbox/platform/event-bus/event-bus.decorators.ts.tpl +9 -0
  314. package/templates/be/inbox/platform/event-bus/event-bus.module-definition.ts.tpl +6 -0
  315. package/templates/be/inbox/platform/event-bus/event-bus.module.ts.tpl +19 -0
  316. package/templates/be/inbox/platform/event-bus/event-bus.options.ts.tpl +2 -0
  317. package/templates/be/inbox/platform/event-bus/event-bus.port.ts.tpl +16 -0
  318. package/templates/be/inbox/platform/event-bus/event-bus.service.spec.ts.tpl +45 -0
  319. package/templates/be/inbox/platform/event-bus/event-bus.service.ts.tpl +15 -0
  320. package/templates/be/inbox/platform/event-bus/index.ts.tpl +5 -0
  321. package/templates/be/inbox/platform/event-bus/persistence/event-bus.sql.ts.tpl +5 -0
  322. package/templates/be/inbox/platform/inbox/inbox.decorators.ts.tpl +9 -0
  323. package/templates/be/inbox/platform/inbox/inbox.module-definition.ts.tpl +6 -0
  324. package/templates/be/inbox/platform/inbox/inbox.module.ts.tpl +19 -0
  325. package/templates/be/inbox/platform/inbox/inbox.options.ts.tpl +2 -0
  326. package/templates/be/inbox/platform/inbox/inbox.port.ts.tpl +10 -0
  327. package/templates/be/inbox/platform/inbox/inbox.service.spec.ts.tpl +41 -0
  328. package/templates/be/inbox/platform/inbox/inbox.service.ts.tpl +19 -0
  329. package/templates/be/inbox/platform/inbox/index.ts.tpl +3 -0
  330. package/templates/be/inbox/platform/inbox/persistence/inbox.sql.ts.tpl +7 -0
  331. package/templates/be/inbox/platform/migration.sql.tpl +48 -0
  332. package/templates/be/inbox/service.spec.ts.tpl +42 -9
  333. package/templates/be/inbox/service.ts.tpl +23 -8
  334. package/templates/be/inbox/webhook-door.spec.ts.tpl +1 -1
  335. package/templates/be/inbox/webhook-door.ts.tpl +2 -2
  336. package/templates/be/patterns/api/feature.module-definition.ts.tpl +6 -0
  337. package/templates/be/patterns/api/feature.module.ts.tpl +2 -1
  338. package/templates/be/patterns/api/feature.options.ts.tpl +2 -0
  339. package/templates/be/patterns/api/graphql.module-definition.ts.tpl +6 -0
  340. package/templates/be/patterns/api/graphql.module.ts.tpl +3 -2
  341. package/templates/be/patterns/api/graphql.options.ts.tpl +2 -0
  342. package/templates/be/patterns/cli/group.module-definition.ts.tpl +6 -0
  343. package/templates/be/patterns/cli/group.module.ts.tpl +2 -1
  344. package/templates/be/patterns/cli/group.options.ts.tpl +2 -0
  345. package/templates/be/patterns/event-bus/platform/errors/event-bus.error.ts.tpl +0 -3
  346. package/templates/be/patterns/event-bus/platform/messages/event-bus.messages.ts.tpl +0 -2
  347. package/templates/be/patterns/jobs/job.module-definition.ts.tpl +6 -0
  348. package/templates/be/patterns/jobs/job.module.ts.tpl +2 -1
  349. package/templates/be/patterns/jobs/job.options.ts.tpl +2 -0
  350. package/templates/be/patterns/jobs/job.queue.module-definition.ts.tpl +6 -0
  351. package/templates/be/patterns/jobs/job.queue.module.ts.tpl +6 -3
  352. package/templates/be/patterns/jobs/job.queue.options.ts.tpl +2 -0
  353. package/templates/be/patterns/jobs/platform/fenced.processor.spec.ts.tpl +3 -1
  354. package/templates/be/patterns/outbox/platform/outbox-relay.policy.spec.ts.tpl +25 -9
  355. package/templates/be/patterns/queues/platform/queue.config.ts.tpl +1 -1
  356. package/templates/be/patterns/queues/platform/queue.index.ts.tpl +1 -1
  357. package/templates/be/patterns/queues/platform/queue.module-definition.ts.tpl +2 -2
  358. package/templates/be/patterns/queues/platform/queue.module.ts.tpl +11 -0
  359. package/templates/be/patterns/queues/platform/queue.options.ts.tpl +10 -0
  360. package/templates/be/patterns/queues/queue.module-definition.ts.tpl +6 -0
  361. package/templates/be/patterns/queues/queue.module.ts.tpl +2 -1
  362. package/templates/be/patterns/queues/queue.options.ts.tpl +2 -0
  363. package/templates/be/patterns/reactors/message.module-definition.ts.tpl +6 -0
  364. package/templates/be/patterns/reactors/message.module.ts.tpl +6 -3
  365. package/templates/be/patterns/reactors/message.options.ts.tpl +2 -0
  366. package/templates/be/patterns/reactors/reactor.module-definition.ts.tpl +6 -0
  367. package/templates/be/patterns/reactors/reactor.module.ts.tpl +2 -1
  368. package/templates/be/patterns/reactors/reactor.options.ts.tpl +2 -0
  369. package/templates/be/patterns/realtime/channel.gateway.spec.ts.tpl +188 -0
  370. package/templates/be/patterns/realtime/channel.gateway.ts.tpl +22 -0
  371. package/templates/be/patterns/realtime/channel.graphql.module-definition.ts.tpl +6 -0
  372. package/templates/be/patterns/realtime/channel.graphql.module.ts.tpl +2 -1
  373. package/templates/be/patterns/realtime/channel.graphql.options.ts.tpl +2 -0
  374. package/templates/be/patterns/realtime/channel.websocket.module-definition.ts.tpl +6 -0
  375. package/templates/be/patterns/realtime/channel.websocket.module.ts.tpl +110 -0
  376. package/templates/be/patterns/realtime/channel.websocket.options.ts.tpl +7 -0
  377. package/templates/be/patterns/saga/saga.message.module-definition.ts.tpl +6 -0
  378. package/templates/be/patterns/saga/saga.message.module.ts.tpl +6 -3
  379. package/templates/be/patterns/saga/saga.message.options.ts.tpl +2 -0
  380. package/templates/be/patterns/saga/saga.module-definition.ts.tpl +6 -0
  381. package/templates/be/patterns/saga/saga.module.ts.tpl +2 -1
  382. package/templates/be/patterns/saga/saga.options.ts.tpl +2 -0
  383. package/templates/be/patterns/webhooks/webhook.http.module-definition.ts.tpl +6 -0
  384. package/templates/be/patterns/webhooks/webhook.http.module.ts.tpl +2 -1
  385. package/templates/be/patterns/webhooks/webhook.http.options.ts.tpl +2 -0
  386. package/templates/be/platform/graphql/localize-errors.mapper.spec.ts +80 -26
  387. package/templates/be/platform/graphql/localize-errors.mapper.ts +2 -5
  388. package/templates/be/skeleton/apps/__app__/src/app.module.ts +11 -9
  389. package/templates/be/skeleton/apps/__app__/src/compose/api.ts +4 -0
  390. package/templates/be/skeleton/apps/__app__/src/compose/domain.ts +11 -0
  391. package/templates/be/skeleton/apps/__app__/src/compose/platform.ts +2 -0
  392. package/templates/be/skeleton/apps/__app__/src/compose/system.ts +5 -0
  393. package/templates/be/skeleton/apps/__app__/src/compose/webhooks.ts +4 -0
  394. package/templates/be/skeleton/apps/__app__/src/main.ts +15 -1
  395. package/templates/be/skeleton/apps/cli/src/app.module.ts +3 -13
  396. package/templates/be/skeleton/apps/cli/src/cli.options.ts +6 -14
  397. package/templates/be/skeleton/apps/cli/src/compose/cli.ts +5 -0
  398. package/templates/be/skeleton/apps/cli/src/compose/platform.ts +24 -0
  399. package/templates/be/skeleton/src/features/api/system-health/application/check-readiness.contracts.ts +2 -0
  400. package/templates/be/skeleton/src/features/api/system-health/application/check-readiness.handler.ts +22 -0
  401. package/templates/be/skeleton/src/features/api/system-health/application/check-readiness.query.ts +11 -0
  402. package/templates/be/skeleton/src/features/api/system-health/system-health.module-definition.ts +6 -0
  403. package/templates/be/skeleton/src/features/api/system-health/system-health.module.ts +5 -3
  404. package/templates/be/skeleton/src/features/api/system-health/system-health.options.ts +2 -0
  405. package/templates/be/skeleton/src/features/api/system-health/transport/http/ready.controller.ts +19 -0
  406. package/templates/be/skeleton/src/features/api/system-health/transport/http/system-health-http.module-definition.ts +6 -0
  407. package/templates/be/skeleton/src/features/api/system-health/transport/http/system-health-http.module.ts +8 -3
  408. package/templates/be/skeleton/src/features/api/system-health/transport/http/system-health-http.options.ts +2 -0
  409. package/templates/be/skeleton/src/features/cli/cli.module-definition.ts +6 -0
  410. package/templates/be/skeleton/src/features/cli/cli.module.ts +3 -2
  411. package/templates/be/skeleton/src/features/cli/cli.options.ts +2 -0
  412. package/templates/be/skeleton/src/features/cli/migrate/migrate.module-definition.ts +6 -0
  413. package/templates/be/skeleton/src/features/cli/migrate/migrate.module.ts +2 -1
  414. package/templates/be/skeleton/src/features/cli/migrate/migrate.options.ts +2 -0
  415. package/templates/be/skeleton/src/features/cli/seed/seed.module-definition.ts +6 -0
  416. package/templates/be/skeleton/src/features/cli/seed/seed.module.ts +2 -1
  417. package/templates/be/skeleton/src/features/cli/seed/seed.options.ts +2 -0
  418. package/templates/be/skeleton/src/features/cli/seed/subs/run.cli.spec.ts +5 -6
  419. package/templates/be/skeleton/src/modules/domain/identity/admission.policy.spec.ts +56 -4
  420. package/templates/be/skeleton/src/modules/domain/identity/admission.policy.ts +36 -5
  421. package/templates/be/skeleton/src/modules/domain/identity/auth.guard.spec.ts +39 -8
  422. package/templates/be/skeleton/src/modules/domain/identity/auth.guard.ts +14 -8
  423. package/templates/be/skeleton/src/modules/domain/identity/credential.contracts.ts +26 -0
  424. package/templates/be/skeleton/src/modules/domain/identity/credential.guard.spec.ts +119 -0
  425. package/templates/be/skeleton/src/modules/domain/identity/credential.guard.ts +43 -0
  426. package/templates/be/skeleton/src/modules/domain/identity/identity.contracts.ts +16 -0
  427. package/templates/be/skeleton/src/modules/domain/identity/identity.decorators.ts +18 -1
  428. package/templates/be/skeleton/src/modules/domain/identity/identity.module.ts +22 -4
  429. package/templates/be/skeleton/src/modules/domain/identity/identity.options.ts +8 -2
  430. package/templates/be/skeleton/src/modules/domain/identity/index.ts +1 -0
  431. package/templates/be/skeleton/src/modules/platform/database/connection-source.client.spec.ts +11 -4
  432. package/templates/be/skeleton/src/modules/platform/database/database-probe.service.spec.ts +32 -0
  433. package/templates/be/skeleton/src/modules/platform/database/database-probe.service.ts +14 -0
  434. package/templates/be/skeleton/src/modules/platform/database/database.module.ts +7 -1
  435. package/templates/be/skeleton/src/modules/platform/database/index.ts +2 -0
  436. package/templates/be/skeleton/src/modules/platform/database/primary.decorators.ts +8 -0
  437. package/templates/be/skeleton/src/modules/platform/database/seed-connections.client.spec.ts +25 -6
  438. package/templates/be/skeleton/src/modules/platform/errors/errors.filter.spec.ts +16 -6
  439. package/templates/be/skeleton/src/modules/platform/http-security/edge-security.service.spec.ts +130 -0
  440. package/templates/be/skeleton/src/modules/platform/http-security/edge-security.service.ts +58 -0
  441. package/templates/be/skeleton/src/modules/platform/http-security/errors/http-security.error.ts +3 -0
  442. package/templates/be/skeleton/src/modules/platform/http-security/execution-request.mapper.spec.ts +16 -4
  443. package/templates/be/skeleton/src/modules/platform/http-security/http-security.config.ts +16 -10
  444. package/templates/be/skeleton/src/modules/platform/http-security/http-security.module.ts +3 -1
  445. package/templates/be/skeleton/src/modules/platform/http-security/http-security.options.ts +2 -0
  446. package/templates/be/skeleton/src/modules/platform/http-security/index.ts +5 -0
  447. package/templates/be/skeleton/src/modules/platform/http-security/messages/http-security.messages.ts +12 -5
  448. package/templates/be/skeleton/src/modules/platform/http-security/rate-limit.guard.spec.ts +13 -8
  449. package/templates/be/skeleton/src/modules/platform/http-security/readiness.contracts.ts +5 -0
  450. package/templates/be/skeleton/src/modules/platform/http-security/readiness.decorators.ts +7 -0
  451. package/templates/be/skeleton/src/modules/platform/http-security/readiness.service.spec.ts +86 -0
  452. package/templates/be/skeleton/src/modules/platform/http-security/readiness.service.ts +39 -0
  453. package/templates/be/skeleton/src/modules/platform/http-security/webhook-signature.service.spec.ts +139 -131
  454. package/templates/be/skeleton/src/modules/platform/i18n/index.ts +1 -1
  455. package/templates/be/skeleton/src/modules/platform/logging/json-logger.service.spec.ts +91 -67
  456. package/templates/be/skeleton/src/modules/platform/logging/json-logger.service.ts +5 -4
  457. package/templates/be/skeleton/src/modules/platform/logging/logging.log-events.ts +0 -2
  458. package/templates/be/skeleton/src/modules/platform/primitives/outcome.mapper.spec.ts +20 -6
  459. package/templates/be/skeleton/src/modules/platform/primitives/sequence.policy.spec.ts +16 -4
  460. package/templates/be/skeleton/src/modules/platform/retry/index.ts +3 -0
  461. package/templates/be/skeleton/src/modules/platform/retry/retry.decorators.ts +9 -0
  462. package/templates/be/skeleton/src/modules/platform/retry/retry.module-definition.ts +7 -0
  463. package/templates/be/skeleton/src/modules/platform/retry/retry.module.ts +19 -0
  464. package/templates/be/skeleton/src/modules/platform/retry/retry.options.ts +2 -0
  465. package/templates/be/skeleton/src/modules/platform/retry/retry.port.ts +11 -0
  466. package/templates/be/skeleton/src/modules/platform/retry/system-timer.service.spec.ts +36 -0
  467. package/templates/be/skeleton/src/modules/platform/retry/system-timer.service.ts +10 -0
  468. package/templates/be/skeleton/src/tests/contract/http-security/http-security.contract-spec.ts +54 -0
  469. package/templates/be/skeleton-lite/apps/api/src/app.module.ts +14 -18
  470. package/templates/be/skeleton-lite/apps/api/src/compose/api.ts +4 -0
  471. package/templates/be/skeleton-lite/apps/api/src/compose/domain.ts +10 -0
  472. package/templates/be/skeleton-lite/apps/api/src/compose/integrations.ts +16 -0
  473. package/templates/be/skeleton-lite/apps/api/src/compose/platform.ts +2 -0
  474. package/templates/be/skeleton-lite/apps/api/src/compose/system.ts +5 -0
  475. package/templates/be/skeleton-lite/apps/api/src/compose/webhooks.ts +4 -0
  476. package/templates/be/skeleton-lite/apps/api/src/main.ts +2 -3
  477. package/templates/be/skeleton-lite/apps/cli/src/compose/platform.ts +12 -0
  478. package/templates/be/skeleton-lite/src/modules/domain/identity/admission.policy.spec.ts +71 -5
  479. package/templates/be/skeleton-lite/src/modules/domain/identity/admission.policy.ts +29 -2
  480. package/templates/be/skeleton-lite/src/modules/domain/identity/auth.guard.spec.ts +68 -15
  481. package/templates/be/skeleton-lite/src/modules/domain/identity/auth.guard.ts +14 -9
  482. package/templates/be/skeleton-lite/src/modules/domain/identity/identity.contracts.ts +9 -2
  483. package/templates/be/skeleton-lite/src/modules/domain/identity/identity.decorators.ts +16 -1
  484. package/templates/be/skeleton-lite/src/modules/domain/identity/identity.module.ts +19 -4
  485. package/templates/be/skeleton-lite/src/modules/domain/identity/identity.options.ts +5 -1
  486. package/templates/be/skeleton-lite/src/modules/domain/identity/index.ts +2 -1
  487. package/templates/be/skeleton-lite/src/modules/integrations/supabase/errors/supabase.error.ts +0 -3
  488. package/templates/be/skeleton-lite/src/modules/integrations/supabase/supabase.client.spec.ts +17 -5
  489. package/templates/be/skeleton-lite/src/modules/platform/database/database.module.ts +24 -13
  490. package/templates/be/skeleton-lite/src/modules/platform/database/database.port.ts +5 -0
  491. package/templates/be/skeleton-lite/src/modules/platform/database/errors/database.error.ts +16 -0
  492. package/templates/be/skeleton-lite/src/modules/platform/database/index.ts +3 -0
  493. package/templates/be/skeleton-lite/src/modules/platform/http-security/http-security.module.ts +5 -2
  494. package/templates/be/skeleton-lite/src/modules/platform/http-security/index.ts +4 -1
  495. package/templates/be/skeleton-lite/src/modules/platform/i18n/index.ts +1 -1
  496. package/templates/be/skeleton-lite/src/modules/platform/logging/logging.log-events.ts +7 -0
  497. package/templates/be/skeleton-lite/src/tests/fixtures/builders/api.builder.ts +29 -0
  498. package/templates/be/skeleton-lite/src/tests/fixtures/builders/cli.builder.ts +16 -0
  499. package/templates/be/table/api/feature.module-definition.ts.tpl +6 -0
  500. package/templates/be/table/api/feature.module.ts.tpl +2 -1
  501. package/templates/be/table/api/feature.options.ts.tpl +2 -0
  502. package/templates/be/table/api/graphql.module-definition.ts.tpl +6 -0
  503. package/templates/be/table/api/graphql.module.ts.tpl +3 -2
  504. package/templates/be/table/api/graphql.options.ts.tpl +2 -0
  505. package/templates/be/table/migration.sql.tpl +1 -0
  506. package/templates/be/upgrade-full/apps/cli/src/app.module.ts +4 -6
  507. package/templates/be/upgrade-full/apps/cli/src/cli.env.ts +7 -0
  508. package/templates/be/upgrade-full/apps/cli/src/compose/cli.ts +5 -0
  509. package/templates/be/upgrade-full/apps/cli/src/compose/platform.ts +9 -0
  510. package/templates/be/upgrade-full/apps/cli/src/main.ts +3 -0
  511. package/templates/be/upgrade-full/src/features/cli/cli.module.ts +3 -2
  512. package/templates/fe/auth/supabase-client.ts.tpl +34 -0
  513. package/templates/fe/skeleton/apps/__app__/src/app/auth/callback/route.ts +11 -0
  514. package/templates/fe/skeleton/apps/__app__/src/components/blocks/SignInForm/index.tsx +6 -1
  515. package/templates/fe/skeleton/apps/__app__/src/components/leaves/Icon/index.tsx +4 -0
  516. package/templates/fe/skeleton/apps/__app__/src/features/overlays/AppGuideOverlay/component.tsx +31 -0
  517. package/templates/fe/skeleton/apps/__app__/src/features/overlays/AppGuideOverlay/index.tsx +24 -0
  518. package/templates/fe/skeleton/apps/__app__/src/hooks/auth/useSession.ts +6 -1
  519. package/templates/fe/skeleton/apps/__app__/src/hooks/auth/useSignOut.ts +3 -4
  520. package/templates/fe/skeleton/apps/__app__/src/hooks/zustand/appGuide/index.ts +1 -0
  521. package/templates/fe/skeleton/apps/__app__/src/hooks/zustand/appGuide/store.ts +15 -0
  522. package/templates/fe/skeleton/apps/__app__/src/modules/auth/pkce-client.ts +18 -0
  523. package/templates/fe/skeleton/apps/__app__/src/modules/auth/server.ts +19 -0
  524. package/templates/fe/skeleton/apps/app/src/features/pages/AppHomePage/index.tsx +7 -1
  525. package/templates/fe/skeleton/apps/app/src/modules/i18n/messages/en.json +57 -0
  526. package/templates/fe/skeleton/apps/app/src/modules/i18n/messages/vi.json +6 -0
  527. package/templates/fe/skeleton/apps/landing/src/modules/i18n/messages/en.json +31 -0
  528. package/templates/fe/skeleton/packages/__project__-i18n/src/routing.ts +1 -1
  529. package/templates/fe/skeleton/packages/__project__-ui/src/index.ts +1 -0
  530. package/templates/fe/skeleton-lite/apps/__app__/src/modules/auth/client.ts +1 -34
  531. package/templates/fe/skeleton-lite/apps/web/src/features/pages/AppHomePage/index.tsx +7 -1
  532. package/templates/fe/skeleton-lite/apps/web/src/modules/i18n/messages/en.json +57 -0
  533. package/templates/fe/skeleton-lite/apps/web/src/modules/i18n/messages/vi.json +30 -24
  534. package/templates/fe/skeleton-lite/apps/web/src/modules/i18n/routing.ts +1 -1
  535. package/templates/fe/transport/graphql/clients/clients/auth.ts +1 -1
  536. package/templates/fe/transport/graphql/clients/links/locale.ts +2 -2
  537. package/upgrade/check.mjs +3 -1
  538. package/upgrade/index.mjs +54 -41
@@ -0,0 +1,663 @@
1
+ schema: starci/schema@1
2
+ id: starci/application-stacks@1
3
+ title: Application stack declaration
4
+ description: >-
5
+ Static, repository-owned inventory for reproducible environments. It declares intended topology,
6
+ custody and runbook location; it is not evidence that a stack ran. This is the machine form of
7
+ modules/schemas/stacks-layout.yaml's CONTENT half - the layout governs the TREE, this document governs the
8
+ fields inside application-stacks.yaml. Runtime and edition content rules require the applicable
9
+ deployment declarations; optional schema fields preserve compatibility with older inventories.
10
+ type: object
11
+ additionalProperties: false
12
+ required: [schema, components, environments, k8s]
13
+ properties:
14
+ schema: {type: string, minLength: 1}
15
+ sources:
16
+ type: array
17
+ minItems: 1
18
+ items:
19
+ type: object
20
+ additionalProperties: false
21
+ required: [repository]
22
+ properties:
23
+ repository: {type: string, minLength: 1}
24
+ components:
25
+ type: object
26
+ minProperties: 1
27
+ additionalProperties:
28
+ type: object
29
+ additionalProperties: false
30
+ required: [role]
31
+ properties:
32
+ role:
33
+ description: >-
34
+ Component classification, including service, stateful, observability, ingress, scheduler
35
+ and job. Free text preserves older declarations.
36
+ type: string
37
+ minLength: 1
38
+ image: {type: string, minLength: 1}
39
+ app:
40
+ description: Back-end app id whose composition the component runs.
41
+ type: string
42
+ minLength: 1
43
+ compose: {type: string, minLength: 1}
44
+ purpose: {type: string}
45
+ required: {type: boolean}
46
+ stateful: {type: boolean}
47
+ database:
48
+ description: A sidecar's declared database adapter and persistent volume.
49
+ type: object
50
+ additionalProperties: false
51
+ required: [provider]
52
+ properties:
53
+ provider: {type: string, minLength: 1}
54
+ volume: {type: string, minLength: 1}
55
+ volumes:
56
+ description: Named persistent volumes owned by this component.
57
+ type: array
58
+ uniqueItems: true
59
+ items: {type: string, minLength: 1}
60
+ mode: {enum: [service, replicated-job], default: service}
61
+ scheduler:
62
+ description: Component id of the declared scheduler that triggers a replicated-job.
63
+ type: string
64
+ minLength: 1
65
+ schedule:
66
+ description: Cron expression consumed by the declared scheduler.
67
+ type: string
68
+ minLength: 1
69
+ release:
70
+ description: Release gates of the app (starci app release gate and push); packages/hfs/release/gate.mjs is the authority for the fields.
71
+ type: object
72
+ database:
73
+ description: Database cutover data (starci app db migrate and post-cutover); packages/hfs/db/migrate.mjs is the authority for the fields.
74
+ type: object
75
+ jobs:
76
+ description: Application-owned schedules, bound to their back-end CLI commands.
77
+ type: object
78
+ additionalProperties:
79
+ type: object
80
+ additionalProperties: false
81
+ required: [schedule, command]
82
+ properties:
83
+ component: {type: string, minLength: 1}
84
+ schedule: {type: string, minLength: 1}
85
+ command: {type: string, minLength: 1}
86
+ backing:
87
+ description: Managed backing services declared as dependencies, never run as stack components.
88
+ type: object
89
+ additionalProperties:
90
+ type: object
91
+ additionalProperties: false
92
+ required: [provider, managed]
93
+ properties:
94
+ provider: {type: string, minLength: 1}
95
+ managed: {const: true}
96
+ environments:
97
+ type: object
98
+ minProperties: 1
99
+ additionalProperties: {$ref: '#/$defs/environment'}
100
+ k8s:
101
+ type: object
102
+ additionalProperties: false
103
+ required: [status, reason]
104
+ properties:
105
+ status: {enum: [deferred, supported]}
106
+ reason: {type: string, minLength: 1}
107
+ services:
108
+ description: >-
109
+ The delivery, quality and platform services this repository's code and CI use - NOT Compose
110
+ services (those are `components`). One entry per service id from the closed catalog below; a
111
+ service the repository does not use is still declared `mode: disabled` when its CI or config
112
+ mentions it. Owner ruling 2026-09-24: every product states these unambiguously so no Kernel or
113
+ op misreads them and asks the owner again. Optional in this schema so older declarations
114
+ stay loadable; scripts/gates/starcistacks.mjs requires it for a new repository or a
115
+ new leg (contract change starcistacks-services) and reports its absence as a suspect with a
116
+ planned follow-up everywhere else.
117
+ type: object
118
+ minProperties: 1
119
+ additionalProperties: false
120
+ properties:
121
+ sonar: {$ref: '#/$defs/service'}
122
+ container-registry: {$ref: '#/$defs/service'}
123
+ analytics: {$ref: '#/$defs/service'}
124
+ error-tracking: {$ref: '#/$defs/service'}
125
+ $defs:
126
+ service:
127
+ type: object
128
+ additionalProperties: false
129
+ required: [provider, mode, ci, ownerAction]
130
+ properties:
131
+ provider:
132
+ description: >-
133
+ Closed per service id (check-starcistacks.mjs PROVIDERS): sonar sonarqube|sonarcloud,
134
+ container-registry ghcr|dockerhub|ecr|gar, analytics posthog|plausible|umami|google-analytics,
135
+ error-tracking sentry|glitchtip.
136
+ type: string
137
+ minLength: 1
138
+ mode:
139
+ description: >-
140
+ local - a server a stack runs (stack and host.local required); hosted - a SaaS or remote
141
+ server (host.public required); disabled - not used (reason required, CI must not call it).
142
+ enum: [local, hosted, disabled]
143
+ purpose: {type: string, minLength: 1}
144
+ reason: {type: string, minLength: 1}
145
+ qualityGate:
146
+ description: >-
147
+ sonar only: the name of the one quality gate the repository is held to. The thresholds are not restated
148
+ here - knowledge/sonar-gate.yaml owns them and scripts/gates/starcistacks.mjs refuses any other name
149
+ (STACKS_QUALITY_GATE_DRIFT).
150
+ type: string
151
+ pattern: '^[a-z][a-z0-9-]*$'
152
+ host:
153
+ type: object
154
+ additionalProperties: false
155
+ properties:
156
+ local: {type: string, pattern: '^https?://[^\s]+$'}
157
+ public: {type: string, pattern: '^https://[^\s]+$'}
158
+ fromCredential:
159
+ description: A hosted endpoint carried inside a credential (a Sentry DSN) - the credential id, never the value.
160
+ type: string
161
+ pattern: '^[a-z][a-z0-9-]*$'
162
+ stack: {$ref: '#/$defs/serviceStack'}
163
+ auth:
164
+ description: >-
165
+ How a client authenticates - token (a credential in custody), oidc (GitHub OIDC, no stored
166
+ secret), github-token (the workflow's automatic GITHUB_TOKEN, no stored secret), none.
167
+ enum: [token, oidc, github-token, none]
168
+ projects:
169
+ type: array
170
+ items:
171
+ type: object
172
+ additionalProperties: false
173
+ required: [repository, key]
174
+ properties:
175
+ repository: {type: string, pattern: '^[A-Za-z0-9._-]+$'}
176
+ key: {type: string, minLength: 1}
177
+ name: {type: string, minLength: 1}
178
+ credentials:
179
+ type: array
180
+ items: {$ref: '#/$defs/serviceCredential'}
181
+ runtimeSecrets:
182
+ description: >-
183
+ An app that lives inside the runtime repository (an example) holds no custody: it names the variables of the runtime's untracked
184
+ .claude/secret.env it reads (and, in CI, the repository secret or variable of the same name). A product declares credentials instead;
185
+ scripts/gates/starcistacks.mjs refuses each form for the other kind (STACKS_EXAMPLE_FORM, STACKS_PRODUCT_FORM).
186
+ type: array
187
+ minItems: 1
188
+ items: {type: string, pattern: '^[A-Z][A-Z0-9_]*$'}
189
+ ci: {$ref: '#/$defs/serviceCi'}
190
+ ownerAction:
191
+ description: >-
192
+ none - nothing about this service is ever asked of the owner (the default and the only
193
+ value allowed while every credential is in custody). Otherwise the one thing only the owner
194
+ can give, named exactly.
195
+ anyOf:
196
+ - {const: none}
197
+ - type: object
198
+ additionalProperties: false
199
+ required: [needed, reason]
200
+ properties:
201
+ needed: {type: string, minLength: 1}
202
+ reason: {type: string, minLength: 1}
203
+ serviceStack:
204
+ description: >-
205
+ Which stack defines a local service - either a project-owned .starcistacks stack
206
+ ({repository, root: .starcistacks, environment, compose}) or a host-owned runtime
207
+ extension ({owner: host, root: .claude/ext/<service>, environment, compose}).
208
+ anyOf:
209
+ - $ref: '#/$defs/serviceStackProject'
210
+ - $ref: '#/$defs/serviceStackHost'
211
+ serviceStackProject:
212
+ description: A local service one repository's own .starcistacks runs.
213
+ type: object
214
+ additionalProperties: false
215
+ required: [repository, root, environment, compose]
216
+ properties:
217
+ repository: {type: string, pattern: '^[A-Za-z0-9._-]+$'}
218
+ root: {const: .starcistacks}
219
+ environment: {type: string, pattern: '^[a-z][a-z0-9-]*$'}
220
+ compose: {type: string, minLength: 1}
221
+ container: {type: string, minLength: 1}
222
+ publishedBy: {type: string, minLength: 1}
223
+ serviceStackHost:
224
+ description: >-
225
+ A shared service the host's installed .claude tree runs once for every routed project
226
+ (SonarQube at .claude/ext/sonar). `root` is a path inside the runtime tree; `environment`
227
+ names the environment slot the extension serves and is not a path segment - the Compose
228
+ file resolves at <root>/<compose>. The runtime tree carries the extension, so no
229
+ repository is named.
230
+ type: object
231
+ additionalProperties: false
232
+ required: [owner, root, environment, compose]
233
+ properties:
234
+ owner: {const: host}
235
+ root: {type: string, pattern: '^\.claude/ext/[a-z][a-z0-9-]*$'}
236
+ environment: {type: string, pattern: '^[a-z][a-z0-9-]*$'}
237
+ compose: {type: string, minLength: 1}
238
+ container: {type: string, minLength: 1}
239
+ publishedBy: {type: string, minLength: 1}
240
+ serviceCredential:
241
+ description: >-
242
+ A custody reference, never a value - the repository whose stack holds it and the plaintext
243
+ member's path from that repository's root; the tracked <path>.enc twin must exist. The field env is the
244
+ variable the consuming tool reads; `key` is the field inside a structured custody file (app.yaml)
245
+ when the application reads the file itself. At least one of env and key is named. Sonar
246
+ convention (scripts/gates/sonar-local.mjs reads it): id `admin` creates projects and mints
247
+ tokens; a credential whose id is a project key is that project's analysis token.
248
+ type: object
249
+ additionalProperties: false
250
+ required: [id, custody]
251
+ properties:
252
+ id: {type: string, pattern: '^[a-z][a-z0-9-]*$'}
253
+ purpose: {type: string, minLength: 1}
254
+ env: {type: string, pattern: '^[A-Z][A-Z0-9_]*$'}
255
+ key: {type: string, minLength: 1}
256
+ custody:
257
+ type: object
258
+ additionalProperties: false
259
+ required: [repository, path]
260
+ properties:
261
+ repository: {type: string, pattern: '^[A-Za-z0-9._-]+$'}
262
+ path: {type: string, pattern: '^(\.starcistacks/[a-z][a-z0-9-]*/(runtime/files|runtime/env|secrets)/[^\s]+|\.claude/ext/[a-z][a-z0-9-]*/secrets/[^\s]+)$'}
263
+ serviceCi:
264
+ description: >-
265
+ How GitHub CI gets the service. wiring required - CI calls it now and the named secrets and
266
+ variables must exist; optional-follow-up - CI may call it, and a Kernel (never the owner) sets
267
+ the secrets and variables from custody when it chooses to; not-used - CI does not call it.
268
+ type: object
269
+ additionalProperties: false
270
+ required: [wiring]
271
+ properties:
272
+ wiring: {enum: [required, optional-follow-up, not-used]}
273
+ workflow: {type: string, minLength: 1}
274
+ permissions: {type: array, items: {type: string, minLength: 1}}
275
+ secrets:
276
+ type: array
277
+ items:
278
+ type: object
279
+ additionalProperties: false
280
+ required: [name, credential]
281
+ properties:
282
+ name: {type: string, pattern: '^[A-Z][A-Z0-9_]*$'}
283
+ credential: {type: string, pattern: '^[a-z][a-z0-9-]*$'}
284
+ vars:
285
+ type: array
286
+ items:
287
+ type: object
288
+ additionalProperties: false
289
+ required: [name, value]
290
+ properties:
291
+ name: {type: string, pattern: '^[A-Z][A-Z0-9_]*$'}
292
+ value: {type: string, minLength: 1}
293
+ provisioning: {type: string, minLength: 1}
294
+ environment:
295
+ type: object
296
+ additionalProperties: false
297
+ required: [status, runtime, composeFiles, components, runbook, secrets]
298
+ properties:
299
+ status: {const: supported}
300
+ runtime: {enum: [docker-compose, docker-swarm]}
301
+ composeFiles: {type: array, minItems: 1, items: {type: string, minLength: 1}}
302
+ renderedModel:
303
+ description: Tracked rendered model relative to .starcistacks/<environment>, such as infra/swarm/rendered.yaml.
304
+ type: string
305
+ minLength: 1
306
+ components:
307
+ type: object
308
+ additionalProperties:
309
+ type: object
310
+ additionalProperties: {type: number}
311
+ runbook: {type: string, minLength: 1}
312
+ secrets: {type: array, items: {$ref: '#/$defs/secret'}}
313
+ deploy: {$ref: '#/$defs/deploy'}
314
+ ingress:
315
+ description: "The one selected ingress component and the hosts it routes, or external with the stack name when the ingress is a shared stack outside this one (then no component; rule R275 judges which of the two is declared)."
316
+ type: object
317
+ additionalProperties: false
318
+ required: [hosts]
319
+ properties:
320
+ component: {type: string, minLength: 1}
321
+ external:
322
+ description: "The shared ingress stack (its own docker stack) that serves the hosts; this stack renders no ingress and publishes no port."
323
+ type: object
324
+ additionalProperties: false
325
+ required: [stack]
326
+ properties:
327
+ stack: {type: string, minLength: 1}
328
+ hosts:
329
+ type: array
330
+ minItems: 1
331
+ uniqueItems: true
332
+ items: {type: string, minLength: 1}
333
+ dns:
334
+ description: Owner-run DNS prerequisites, one declaration per ingress host.
335
+ type: array
336
+ items:
337
+ type: object
338
+ additionalProperties: false
339
+ required: [host, owner, receipt]
340
+ properties:
341
+ host: {type: string, minLength: 1}
342
+ owner: {type: string, minLength: 1}
343
+ receipt: {type: string, minLength: 1}
344
+ tls:
345
+ description: Ownership and receipt for TLS issuance and persistent certificate custody.
346
+ type: object
347
+ additionalProperties: false
348
+ required: [owner, receipt]
349
+ properties:
350
+ owner: {type: string, minLength: 1}
351
+ receipt: {type: string, minLength: 1}
352
+ release:
353
+ description: Immutable image inventory, active and previous release pointers, and health assertions.
354
+ type: object
355
+ additionalProperties: false
356
+ required: [imagesLock, pointer, previous, healthAssertions]
357
+ properties:
358
+ imagesLock: {type: string, minLength: 1}
359
+ pointer: {type: string, minLength: 1}
360
+ previous: {type: string, minLength: 1}
361
+ healthAssertions:
362
+ type: array
363
+ minItems: 1
364
+ items: {type: string, minLength: 1}
365
+ backup:
366
+ description: Backup ownership and restore evidence for each stateful component.
367
+ type: array
368
+ items:
369
+ type: object
370
+ additionalProperties: false
371
+ required: [component, target, retention, owner, restoreProof]
372
+ properties:
373
+ component: {type: string, minLength: 1}
374
+ target: {type: string, minLength: 1}
375
+ retention: {type: string, minLength: 1}
376
+ owner: {type: string, minLength: 1}
377
+ restoreProof: {type: string, minLength: 1}
378
+ deploy:
379
+ description: >-
380
+ The Swarm deploy configuration `starci app stack` verbs read (optional; rule R294 judges it). It holds names, paths and shapes
381
+ only, never a value: sealed members and keys are references into .starcistacks/<environment>/secrets. The authority is
382
+ scripts/hfs/stack-deploy-config.mjs, which normalises exactly this shape (service, volume and member names, paths
383
+ inside the environment directory and the existence of the files they name are checked there, not here).
384
+ type: object
385
+ additionalProperties: false
386
+ properties:
387
+ stack: {$ref: '#/$defs/deployName'}
388
+ remote: {$ref: '#/$defs/deployRemote'}
389
+ images:
390
+ description: Service -> the image the deploy injects; the managed workflow builds one per entry.
391
+ type: object
392
+ propertyNames: {$ref: '#/$defs/deployName'}
393
+ additionalProperties: {$ref: '#/$defs/deployImage'}
394
+ volumes:
395
+ description: External volumes prepare creates and doctor checks.
396
+ type: array
397
+ items: {$ref: '#/$defs/deployVolumeName'}
398
+ secrets: {$ref: '#/$defs/deploySecrets'}
399
+ environment:
400
+ description: Service -> plain environment merged into the generated override.
401
+ type: object
402
+ additionalProperties: {$ref: '#/$defs/deployServiceEnvironment'}
403
+ configs:
404
+ description: Non-secret files mounted into services, versioned by content digest; config names are unique (checked by the normaliser).
405
+ type: array
406
+ items: {$ref: '#/$defs/deployConfig'}
407
+ passEnv:
408
+ description: Host variable names interpolated into the rendered stack (names only).
409
+ type: array
410
+ items: {$ref: '#/$defs/deployKey'}
411
+ verify: {$ref: '#/$defs/deployVerify'}
412
+ jobs: {$ref: '#/$defs/deployJobs'}
413
+ tasks: {$ref: '#/$defs/deployTasks'}
414
+ backup: {$ref: '#/$defs/deployBackup'}
415
+ registry: {$ref: '#/$defs/deployRegistry'}
416
+ ingress:
417
+ description: The shared host ingress (stack-ingress-config.mjs is the authority for the fields; starci app check R294 judges them).
418
+ type: object
419
+ deployName:
420
+ type: string
421
+ pattern: '^[a-z][a-z0-9-]*$'
422
+ deployKey:
423
+ type: string
424
+ pattern: '^[A-Z][A-Z0-9_]*$'
425
+ deployVolumeName:
426
+ type: string
427
+ pattern: '^[A-Za-z0-9][A-Za-z0-9_.-]*$'
428
+ deployTreePath:
429
+ description: A relative path inside .starcistacks/<environment>/ (forward slashes, no .. segment).
430
+ type: string
431
+ pattern: '^(?!/)(?!.*\\)(?!(?:.*/)?\.\.(?:/|$)).+$'
432
+ deployAbsolutePath:
433
+ description: An absolute path on the host without .. segments.
434
+ type: string
435
+ pattern: '^/(?!.*\.\.)[A-Za-z0-9._/-]+$'
436
+ deployKeyList:
437
+ type: array
438
+ minItems: 1
439
+ items: {$ref: '#/$defs/deployKey'}
440
+ deployMemberKeys:
441
+ description: A sealed member and the keys taken from it.
442
+ type: object
443
+ additionalProperties: false
444
+ required: [member, keys]
445
+ properties:
446
+ member: {$ref: '#/$defs/deployName'}
447
+ keys: {$ref: '#/$defs/deployKeyList'}
448
+ deployRemote:
449
+ type: object
450
+ additionalProperties: false
451
+ properties:
452
+ host:
453
+ description: ssh alias used for DOCKER_HOST=ssh://<host> and the release records (default vps).
454
+ type: string
455
+ pattern: '^[A-Za-z0-9][A-Za-z0-9._-]*$'
456
+ releasesBase: {$ref: '#/$defs/deployAbsolutePath'}
457
+ sealed:
458
+ description: 'Owner-machine session for prepare and doctor: members of .starcistacks/<environment>/secrets.'
459
+ type: object
460
+ additionalProperties: false
461
+ required: [ops, sshKey, knownHosts]
462
+ properties:
463
+ ops: {$ref: '#/$defs/deployName'}
464
+ sshKey: {$ref: '#/$defs/deployName'}
465
+ knownHosts: {$ref: '#/$defs/deployName'}
466
+ deployImage:
467
+ type: object
468
+ additionalProperties: false
469
+ required: [app]
470
+ properties:
471
+ app: {$ref: '#/$defs/deployName'}
472
+ buildArgs:
473
+ description: Public build values (they reach the browser by design), literals and the public keys of a sealed member.
474
+ type: object
475
+ additionalProperties: false
476
+ properties:
477
+ values:
478
+ type: object
479
+ propertyNames: {$ref: '#/$defs/deployKey'}
480
+ additionalProperties: {type: string}
481
+ sealed: {$ref: '#/$defs/deployMemberKeys'}
482
+ deploySecrets:
483
+ type: object
484
+ additionalProperties: false
485
+ properties:
486
+ grants:
487
+ description: Which sealed keys become which Swarm secrets, granted to which services.
488
+ type: array
489
+ items: {$ref: '#/$defs/deployGrant'}
490
+ settings: {$ref: '#/$defs/deployMemberKeys'}
491
+ deployGrant:
492
+ type: object
493
+ additionalProperties: false
494
+ required: [service, from]
495
+ properties:
496
+ service: {$ref: '#/$defs/deployName'}
497
+ filePointers:
498
+ description: Also set <KEY>_FILE=/run/secrets/<KEY> in the service environment.
499
+ type: boolean
500
+ from:
501
+ type: array
502
+ minItems: 1
503
+ items: {$ref: '#/$defs/deployGrantSource'}
504
+ deployGrantSource:
505
+ type: object
506
+ additionalProperties: false
507
+ required: [member]
508
+ properties:
509
+ member: {$ref: '#/$defs/deployName'}
510
+ keys: {$ref: '#/$defs/deployKeyList'}
511
+ required: {type: boolean}
512
+ fill:
513
+ description: Never override a key an earlier source of the same service gave.
514
+ type: boolean
515
+ if:
516
+ required: [required]
517
+ properties:
518
+ required: {const: true}
519
+ then:
520
+ required: [keys]
521
+ deployServiceEnvironment:
522
+ type: object
523
+ additionalProperties: false
524
+ properties:
525
+ files:
526
+ description: KEY=VALUE files, relative to .starcistacks/<environment>/.
527
+ type: array
528
+ items: {$ref: '#/$defs/deployTreePath'}
529
+ values:
530
+ type: object
531
+ propertyNames: {$ref: '#/$defs/deployKey'}
532
+ additionalProperties: {type: string}
533
+ settings:
534
+ type: object
535
+ propertyNames: {$ref: '#/$defs/deployKey'}
536
+ additionalProperties: {$ref: '#/$defs/deploySetting'}
537
+ deploySetting:
538
+ type: object
539
+ additionalProperties: false
540
+ required: [key]
541
+ properties:
542
+ key: {$ref: '#/$defs/deployKey'}
543
+ default: {description: 'A literal default: a string, number or boolean.'}
544
+ deployConfig:
545
+ type: object
546
+ additionalProperties: false
547
+ required: [name, file, env]
548
+ properties:
549
+ name: {$ref: '#/$defs/deployName'}
550
+ file: {$ref: '#/$defs/deployTreePath'}
551
+ env: {$ref: '#/$defs/deployKey'}
552
+ deployVerify:
553
+ type: object
554
+ additionalProperties: false
555
+ properties:
556
+ http:
557
+ type: array
558
+ items: {$ref: '#/$defs/deployHttpCheck'}
559
+ exec:
560
+ type: array
561
+ items: {$ref: '#/$defs/deployExecCheck'}
562
+ deployHttpCheck:
563
+ type: object
564
+ additionalProperties: false
565
+ required: [name, url]
566
+ properties:
567
+ name: {type: string, minLength: 1}
568
+ url: {type: string, pattern: '^https?://[^\s]+$'}
569
+ method: {enum: [GET, POST]}
570
+ body: {type: string}
571
+ status: {type: integer, minimum: 100, maximum: 599}
572
+ json:
573
+ description: Expected fields of the JSON response.
574
+ type: object
575
+ contains: {type: string}
576
+ retry: {type: boolean}
577
+ deployExecCheck:
578
+ type: object
579
+ additionalProperties: false
580
+ required: [name, service, command]
581
+ properties:
582
+ name: {type: string, minLength: 1}
583
+ service: {$ref: '#/$defs/deployName'}
584
+ command: {$ref: '#/$defs/deployCommand'}
585
+ stdout:
586
+ description: Regular expression the standard output must match.
587
+ type: string
588
+ deployCommand:
589
+ description: An argument vector run inside a task; every argument is a plain word (no shell syntax).
590
+ type: array
591
+ minItems: 1
592
+ items:
593
+ type: string
594
+ pattern: '^[A-Za-z0-9_@%+=:,./-]+$'
595
+ deployJobs:
596
+ type: object
597
+ additionalProperties: false
598
+ required: [service, command]
599
+ properties:
600
+ service: {$ref: '#/$defs/deployName'}
601
+ command: {$ref: '#/$defs/deployCommand'}
602
+ deployTasks:
603
+ description: One-off commands `starci app stack task <name>` runs inside a running task of the declared service.
604
+ type: object
605
+ propertyNames:
606
+ pattern: '^[a-z][a-z0-9-]{0,40}$'
607
+ additionalProperties:
608
+ type: object
609
+ additionalProperties: false
610
+ required: [service, command]
611
+ properties:
612
+ service: {$ref: '#/$defs/deployName'}
613
+ command: {$ref: '#/$defs/deployCommand'}
614
+ deployBackup:
615
+ type: object
616
+ additionalProperties: false
617
+ required: [image, volumes]
618
+ properties:
619
+ image:
620
+ description: The tar helper image, pinned by a non-placeholder digest.
621
+ type: string
622
+ pattern: '^[a-z0-9./_-]+(?::[A-Za-z0-9._-]+)?@sha256:(?!0{64}$)[0-9a-f]{64}$'
623
+ keepDays: {type: integer, minimum: 1, maximum: 3650}
624
+ dir: {$ref: '#/$defs/deployAbsolutePath'}
625
+ volumes:
626
+ type: array
627
+ minItems: 1
628
+ items: {$ref: '#/$defs/deployBackupVolume'}
629
+ deployRegistry:
630
+ description: >-
631
+ The image registry and the visibility the app's packages are meant to have. The canon scaffold writes `public`; the value then belongs to the app.
632
+ While the effective value is `public`, `stack build --push` scans every image for secret material before the push and checks the real
633
+ visibility afterwards. Omitted: ghcr.io and public.
634
+ type: object
635
+ additionalProperties: false
636
+ properties:
637
+ host: {type: string, pattern: '^[a-z0-9][a-z0-9.-]*(?::[0-9]{1,5})?$', default: ghcr.io}
638
+ visibility: {enum: [public, private], default: public}
639
+ deployBackupVolume:
640
+ type: object
641
+ additionalProperties: false
642
+ required: [name, volume]
643
+ properties:
644
+ name: {$ref: '#/$defs/deployName'}
645
+ volume: {$ref: '#/$defs/deployVolumeName'}
646
+ secret:
647
+ type: object
648
+ additionalProperties: false
649
+ required: [name, where, recipientPolicy, keyCustody]
650
+ properties:
651
+ name: {type: string, pattern: '^[a-z][a-z0-9.-]*$'}
652
+ runtimeName:
653
+ description: Immutable external Swarm secret name, ending in -v followed by its version.
654
+ type: string
655
+ pattern: '^[a-z][a-z0-9.-]*-v[1-9][0-9]*$'
656
+ version:
657
+ description: Positive version matching the immutable runtimeName suffix.
658
+ anyOf:
659
+ - {type: integer, minimum: 1}
660
+ - {type: string, pattern: '^[1-9][0-9]*$'}
661
+ where: {type: string, minLength: 1}
662
+ recipientPolicy: {type: string, minLength: 1, description: "Which age recipient the envelope is encrypted to: the one shared master recipient every project uses."}
663
+ keyCustody: {type: string, minLength: 1, description: "Where the shared decrypting identity is held; docs/host-secrets.md owns host custody and its execution prerequisites."}