rcf-lite 0.24.0 → 0.26.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 (313) hide show
  1. package/CHANGELOG.md +36 -0
  2. package/blueprints/application-account-settings/docs/topics.md +4 -1
  3. package/blueprints/application-admin-console/docs/topics.md +4 -1
  4. package/blueprints/application-api-rest/docs/topics.md +4 -1
  5. package/blueprints/application-charts/docs/topics.md +4 -1
  6. package/blueprints/application-dashboard/docs/topics.md +4 -1
  7. package/blueprints/application-datatable/docs/topics.md +4 -1
  8. package/blueprints/application-empty-error-states/docs/topics.md +4 -1
  9. package/blueprints/application-error-handling/docs/topics.md +4 -1
  10. package/blueprints/application-file-upload/docs/topics.md +4 -1
  11. package/blueprints/application-forms-wizard/docs/topics.md +4 -1
  12. package/blueprints/application-notifications-in-app/docs/topics.md +4 -1
  13. package/blueprints/application-onboarding-tour/docs/topics.md +4 -1
  14. package/blueprints/application-spa/docs/topics.md +4 -1
  15. package/blueprints/delivery-ci-workflows/docs/topics.md +4 -1
  16. package/blueprints/deploy-cloudflare-workers/docs/topics.md +4 -1
  17. package/blueprints/deploy-hetzner-server/CHANGELOG.md +55 -0
  18. package/blueprints/deploy-hetzner-server/README.md +202 -0
  19. package/blueprints/deploy-hetzner-server/blueprint.json +233 -0
  20. package/blueprints/deploy-hetzner-server/contributions/adrs/adr-3801-deploy-hetzner-server-cloud-host-contract.json +14 -0
  21. package/blueprints/deploy-hetzner-server/contributions/adrs/adr-3802-deploy-hetzner-server-snapshot-cadence.json +14 -0
  22. package/blueprints/deploy-hetzner-server/contributions/adrs/adr-3803-deploy-hetzner-server-provisioning-tool.json +20 -0
  23. package/blueprints/deploy-hetzner-server/contributions/adrs/adr-3804-deploy-hetzner-server-hardening-baseline.json +14 -0
  24. package/blueprints/deploy-hetzner-server/contributions/probes/cloud-init-render-lint.mjs +71 -0
  25. package/blueprints/deploy-hetzner-server/contributions/probes/hcloud-dry-run-mock.mjs +164 -0
  26. package/blueprints/deploy-hetzner-server/contributions/probes/manifest-schema-validate.mjs +182 -0
  27. package/blueprints/deploy-hetzner-server/contributions/probes/probe-utils.mjs +112 -0
  28. package/blueprints/deploy-hetzner-server/contributions/probes/real-account-cloud-init-hardened.mjs +64 -0
  29. package/blueprints/deploy-hetzner-server/contributions/probes/real-account-snapshot-on-demand.mjs +60 -0
  30. package/blueprints/deploy-hetzner-server/contributions/probes/real-account-throwaway-server-provision.mjs +58 -0
  31. package/blueprints/deploy-hetzner-server/contributions/probes/run-cloud-init-render-lint.mjs +9 -0
  32. package/blueprints/deploy-hetzner-server/contributions/probes/run-hcloud-dry-run-mock.mjs +9 -0
  33. package/blueprints/deploy-hetzner-server/contributions/probes/run-manifest-schema-validate.mjs +9 -0
  34. package/blueprints/deploy-hetzner-server/contributions/probes/run-real-account-cloud-init-hardened.mjs +9 -0
  35. package/blueprints/deploy-hetzner-server/contributions/probes/run-real-account-snapshot-on-demand.mjs +9 -0
  36. package/blueprints/deploy-hetzner-server/contributions/probes/run-real-account-throwaway-server-provision.mjs +9 -0
  37. package/blueprints/deploy-hetzner-server/contributions/requirements/deploy-hetzner-server-req-001.json +18 -0
  38. package/blueprints/deploy-hetzner-server/contributions/requirements/deploy-hetzner-server-req-002.json +18 -0
  39. package/blueprints/deploy-hetzner-server/contributions/requirements/deploy-hetzner-server-req-003.json +18 -0
  40. package/blueprints/deploy-hetzner-server/contributions/requirements/deploy-hetzner-server-req-004.json +18 -0
  41. package/blueprints/deploy-hetzner-server/contributions/requirements/deploy-hetzner-server-req-005.json +18 -0
  42. package/blueprints/deploy-hetzner-server/contributions/requirements/deploy-hetzner-server-req-006.json +18 -0
  43. package/blueprints/deploy-hetzner-server/contributions/schemas/hetzner-server.schema.json +108 -0
  44. package/blueprints/deploy-hetzner-server/contributions/tacs/tac-3801-deploy-hetzner-server-provisioner.json +27 -0
  45. package/blueprints/deploy-hetzner-server/contributions/tacs/tac-3802-deploy-hetzner-server-manifest-schema.json +26 -0
  46. package/blueprints/deploy-hetzner-server/contributions/tacs/tac-3803-deploy-hetzner-server-cloud-init-template.json +26 -0
  47. package/blueprints/deploy-hetzner-server/contributions/tacs/tac-3804-deploy-hetzner-server-firewall-shape.json +25 -0
  48. package/blueprints/deploy-hetzner-server/contributions/templates/cloud-init.yaml.tmpl +113 -0
  49. package/blueprints/deploy-hetzner-server/contributions/user-stories/deploy-hetzner-server-us-37101.json +24 -0
  50. package/blueprints/deploy-hetzner-server/contributions/user-stories/deploy-hetzner-server-us-37102.json +24 -0
  51. package/blueprints/deploy-hetzner-server/contributions/user-stories/deploy-hetzner-server-us-37103.json +25 -0
  52. package/blueprints/deploy-hetzner-server/contributions/user-stories/deploy-hetzner-server-us-37104.json +24 -0
  53. package/blueprints/deploy-hetzner-server/contributions/user-stories/deploy-hetzner-server-us-37105.json +24 -0
  54. package/blueprints/deploy-hetzner-server/contributions/user-stories/deploy-hetzner-server-us-37106.json +25 -0
  55. package/blueprints/deploy-hetzner-server/contributions/user-stories/deploy-hetzner-server-us-37107.json +24 -0
  56. package/blueprints/deploy-hetzner-server/contributions/user-stories/deploy-hetzner-server-us-37108.json +24 -0
  57. package/blueprints/deploy-hetzner-server/contributions/user-stories/deploy-hetzner-server-us-37109.json +24 -0
  58. package/blueprints/deploy-hetzner-server/docs/topics.md +48 -0
  59. package/blueprints/deploy-hetzner-server/guide/deploy-hetzner-server.md +180 -0
  60. package/blueprints/edge-cloudflare-access/docs/topics.md +4 -1
  61. package/blueprints/edge-cloudflare-rate-limiting/docs/topics.md +4 -1
  62. package/blueprints/edge-cloudflare-tunnel/CHANGELOG.md +23 -0
  63. package/blueprints/edge-cloudflare-tunnel/README.md +257 -0
  64. package/blueprints/edge-cloudflare-tunnel/blueprint.json +168 -0
  65. package/blueprints/edge-cloudflare-tunnel/contributions/adrs/adr-4001-edge-cloudflare-tunnel-ingress-bridge-contract.json +23 -0
  66. package/blueprints/edge-cloudflare-tunnel/contributions/adrs/adr-4002-edge-cloudflare-tunnel-connector-runtime.json +19 -0
  67. package/blueprints/edge-cloudflare-tunnel/contributions/adrs/adr-4003-edge-cloudflare-tunnel-hostname-mode.json +19 -0
  68. package/blueprints/edge-cloudflare-tunnel/contributions/probes/aud-presence-check.mjs +114 -0
  69. package/blueprints/edge-cloudflare-tunnel/contributions/probes/cloudflared-config-lint.mjs +80 -0
  70. package/blueprints/edge-cloudflare-tunnel/contributions/probes/manifest-schema-validate.mjs +237 -0
  71. package/blueprints/edge-cloudflare-tunnel/contributions/probes/probe-utils.mjs +231 -0
  72. package/blueprints/edge-cloudflare-tunnel/contributions/probes/real-account-connector-healthy.mjs +143 -0
  73. package/blueprints/edge-cloudflare-tunnel/contributions/probes/real-account-tunnel-hostname-routes.mjs +166 -0
  74. package/blueprints/edge-cloudflare-tunnel/contributions/probes/run-aud-presence-check.mjs +4 -0
  75. package/blueprints/edge-cloudflare-tunnel/contributions/probes/run-cloudflared-config-lint.mjs +4 -0
  76. package/blueprints/edge-cloudflare-tunnel/contributions/probes/run-manifest-schema-validate.mjs +4 -0
  77. package/blueprints/edge-cloudflare-tunnel/contributions/probes/run-real-account-connector-healthy.mjs +4 -0
  78. package/blueprints/edge-cloudflare-tunnel/contributions/probes/run-real-account-tunnel-hostname-routes.mjs +4 -0
  79. package/blueprints/edge-cloudflare-tunnel/contributions/probes/tunnel-manifest.schema.json +55 -0
  80. package/blueprints/edge-cloudflare-tunnel/contributions/requirements/edge-cloudflare-tunnel-req-001.json +18 -0
  81. package/blueprints/edge-cloudflare-tunnel/contributions/requirements/edge-cloudflare-tunnel-req-002.json +18 -0
  82. package/blueprints/edge-cloudflare-tunnel/contributions/requirements/edge-cloudflare-tunnel-req-003.json +18 -0
  83. package/blueprints/edge-cloudflare-tunnel/contributions/requirements/edge-cloudflare-tunnel-req-004.json +18 -0
  84. package/blueprints/edge-cloudflare-tunnel/contributions/requirements/edge-cloudflare-tunnel-req-005.json +18 -0
  85. package/blueprints/edge-cloudflare-tunnel/contributions/tacs/tac-4001-edge-cloudflare-tunnel-connector-shape.json +26 -0
  86. package/blueprints/edge-cloudflare-tunnel/contributions/tacs/tac-4002-edge-cloudflare-tunnel-manifest-schema.json +26 -0
  87. package/blueprints/edge-cloudflare-tunnel/contributions/tacs/tac-4003-edge-cloudflare-tunnel-access-binding.json +25 -0
  88. package/blueprints/edge-cloudflare-tunnel/contributions/user-stories/edge-cloudflare-tunnel-us-39101.json +24 -0
  89. package/blueprints/edge-cloudflare-tunnel/contributions/user-stories/edge-cloudflare-tunnel-us-39102.json +24 -0
  90. package/blueprints/edge-cloudflare-tunnel/contributions/user-stories/edge-cloudflare-tunnel-us-39103.json +24 -0
  91. package/blueprints/edge-cloudflare-tunnel/contributions/user-stories/edge-cloudflare-tunnel-us-39104.json +24 -0
  92. package/blueprints/edge-cloudflare-tunnel/contributions/user-stories/edge-cloudflare-tunnel-us-39105.json +24 -0
  93. package/blueprints/edge-cloudflare-tunnel/contributions/user-stories/edge-cloudflare-tunnel-us-39106.json +24 -0
  94. package/blueprints/edge-cloudflare-tunnel/contributions/user-stories/edge-cloudflare-tunnel-us-39107.json +24 -0
  95. package/blueprints/edge-cloudflare-tunnel/contributions/user-stories/edge-cloudflare-tunnel-us-39108.json +24 -0
  96. package/blueprints/edge-cloudflare-tunnel/docs/topics.md +72 -0
  97. package/blueprints/edge-cloudflare-tunnel/guide/edge-cloudflare-tunnel.md +204 -0
  98. package/blueprints/edge-cloudflare-turnstile/docs/topics.md +4 -1
  99. package/blueprints/email-smtp-resend/docs/topics.md +4 -1
  100. package/blueprints/jobs-background/docs/topics.md +4 -1
  101. package/blueprints/messaging-queue-cloudflare/CHANGELOG.md +19 -0
  102. package/blueprints/messaging-queue-cloudflare/README.md +2 -2
  103. package/blueprints/messaging-queue-cloudflare/blueprint.json +1 -1
  104. package/blueprints/messaging-queue-cloudflare/contributions/probes/real-account-concurrency-smoke.mjs +192 -37
  105. package/blueprints/messaging-queue-cloudflare/docs/topics.md +4 -1
  106. package/blueprints/object-storage-s3/CHANGELOG.md +11 -0
  107. package/blueprints/object-storage-s3/README.md +14 -1
  108. package/blueprints/object-storage-s3/blueprint.json +12 -1
  109. package/blueprints/object-storage-s3/contributions/adrs/adr-2905-object-storage-s3-hetzner-object-storage-provider.json +30 -0
  110. package/blueprints/object-storage-s3/contributions/probes/hetzner-object-storage-round-trip.mjs +136 -0
  111. package/blueprints/object-storage-s3/contributions/probes/run-hetzner-object-storage-round-trip.mjs +11 -0
  112. package/blueprints/object-storage-s3/contributions/requirements/object-storage-s3-req-101.json +18 -0
  113. package/blueprints/object-storage-s3/contributions/tacs/tac-2904-object-storage-s3-hetzner-endpoint-helper.json +34 -0
  114. package/blueprints/object-storage-s3/contributions/user-stories/object-storage-s3-us-28110.json +25 -0
  115. package/blueprints/object-storage-s3/docs/topics.md +4 -1
  116. package/blueprints/object-storage-s3/guide/object-storage-s3.md +36 -0
  117. package/blueprints/observability-essentials/docs/topics.md +4 -1
  118. package/blueprints/observability-logging/docs/topics.md +4 -1
  119. package/blueprints/observability-probe-endpoints/docs/topics.md +4 -1
  120. package/blueprints/persistence-data-d1/docs/topics.md +4 -1
  121. package/blueprints/persistence-data-postgres/docs/topics.md +4 -1
  122. package/blueprints/persistence-data-sqlite/docs/topics.md +4 -1
  123. package/blueprints/platform-cloudflare-cron-triggers/docs/topics.md +4 -1
  124. package/blueprints/platform-cloudflare-durable-objects/CHANGELOG.md +15 -0
  125. package/blueprints/platform-cloudflare-durable-objects/blueprint.json +1 -1
  126. package/blueprints/platform-cloudflare-durable-objects/contributions/probes/namespace-facade-ready.mjs +3 -3
  127. package/blueprints/platform-cloudflare-durable-objects/contributions/probes/probe-utils.mjs +28 -14
  128. package/blueprints/platform-cloudflare-durable-objects/contributions/probes/real-account-storage-smoke.mjs +132 -26
  129. package/blueprints/platform-cloudflare-durable-objects/contributions/probes/sole-reader-scan.mjs +40 -39
  130. package/blueprints/platform-cloudflare-durable-objects/contributions/probes/storage-round-trip.mjs +26 -16
  131. package/blueprints/platform-cloudflare-durable-objects/contributions/probes/websocket-hub-broadcast.mjs +31 -34
  132. package/blueprints/platform-cloudflare-durable-objects/docs/topics.md +4 -1
  133. package/blueprints/platform-cloudflare-kv/CHANGELOG.md +40 -1
  134. package/blueprints/platform-cloudflare-kv/README.md +41 -13
  135. package/blueprints/platform-cloudflare-kv/blueprint.json +1 -1
  136. package/blueprints/platform-cloudflare-kv/contributions/probes/cache-aside-hit-then-miss.mjs +26 -26
  137. package/blueprints/platform-cloudflare-kv/contributions/probes/event-secrecy.mjs +49 -31
  138. package/blueprints/platform-cloudflare-kv/contributions/probes/facade-round-trip.mjs +58 -16
  139. package/blueprints/platform-cloudflare-kv/contributions/probes/list-with-prefix.mjs +6 -5
  140. package/blueprints/platform-cloudflare-kv/contributions/probes/real-account-eventual-consistency-smoke.mjs +131 -67
  141. package/blueprints/platform-cloudflare-kv/docs/topics.md +4 -1
  142. package/blueprints/platform-docker-compose-host/CHANGELOG.md +12 -0
  143. package/blueprints/platform-docker-compose-host/README.md +76 -0
  144. package/blueprints/platform-docker-compose-host/blueprint.json +209 -0
  145. package/blueprints/platform-docker-compose-host/contributions/adrs/adr-3901-platform-docker-compose-host-contract.json +14 -0
  146. package/blueprints/platform-docker-compose-host/contributions/adrs/adr-3902-platform-docker-compose-host-reverse-proxy.json +14 -0
  147. package/blueprints/platform-docker-compose-host/contributions/adrs/adr-3903-platform-docker-compose-host-reject-coolify.json +14 -0
  148. package/blueprints/platform-docker-compose-host/contributions/adrs/adr-3904-platform-docker-compose-host-log-driver.json +14 -0
  149. package/blueprints/platform-docker-compose-host/contributions/probes/caddyfile-validate.mjs +108 -0
  150. package/blueprints/platform-docker-compose-host/contributions/probes/compose-config-lint.mjs +231 -0
  151. package/blueprints/platform-docker-compose-host/contributions/probes/probe-utils.mjs +185 -0
  152. package/blueprints/platform-docker-compose-host/contributions/probes/real-account-minimal-stack-up.mjs +41 -0
  153. package/blueprints/platform-docker-compose-host/contributions/probes/real-account-reload-burst.mjs +36 -0
  154. package/blueprints/platform-docker-compose-host/contributions/probes/run-caddyfile-validate.mjs +5 -0
  155. package/blueprints/platform-docker-compose-host/contributions/probes/run-compose-config-lint.mjs +5 -0
  156. package/blueprints/platform-docker-compose-host/contributions/probes/run-real-account-minimal-stack-up.mjs +5 -0
  157. package/blueprints/platform-docker-compose-host/contributions/probes/run-real-account-reload-burst.mjs +5 -0
  158. package/blueprints/platform-docker-compose-host/contributions/probes/run-secrets-as-files-scan.mjs +5 -0
  159. package/blueprints/platform-docker-compose-host/contributions/probes/secrets-as-files-scan.mjs +116 -0
  160. package/blueprints/platform-docker-compose-host/contributions/requirements/platform-docker-compose-host-req-001.json +18 -0
  161. package/blueprints/platform-docker-compose-host/contributions/requirements/platform-docker-compose-host-req-002.json +18 -0
  162. package/blueprints/platform-docker-compose-host/contributions/requirements/platform-docker-compose-host-req-003.json +18 -0
  163. package/blueprints/platform-docker-compose-host/contributions/requirements/platform-docker-compose-host-req-004.json +18 -0
  164. package/blueprints/platform-docker-compose-host/contributions/requirements/platform-docker-compose-host-req-005.json +18 -0
  165. package/blueprints/platform-docker-compose-host/contributions/requirements/platform-docker-compose-host-req-006.json +18 -0
  166. package/blueprints/platform-docker-compose-host/contributions/tacs/tac-3901-platform-docker-compose-host-compose-layout.json +26 -0
  167. package/blueprints/platform-docker-compose-host/contributions/tacs/tac-3902-platform-docker-compose-host-secrets-mount.json +26 -0
  168. package/blueprints/platform-docker-compose-host/contributions/tacs/tac-3903-platform-docker-compose-host-healthcheck-lint.json +26 -0
  169. package/blueprints/platform-docker-compose-host/contributions/tacs/tac-3904-platform-docker-compose-host-reverse-proxy-artefact.json +26 -0
  170. package/blueprints/platform-docker-compose-host/contributions/user-stories/platform-docker-compose-host-us-38101.json +24 -0
  171. package/blueprints/platform-docker-compose-host/contributions/user-stories/platform-docker-compose-host-us-38102.json +24 -0
  172. package/blueprints/platform-docker-compose-host/contributions/user-stories/platform-docker-compose-host-us-38103.json +24 -0
  173. package/blueprints/platform-docker-compose-host/contributions/user-stories/platform-docker-compose-host-us-38104.json +24 -0
  174. package/blueprints/platform-docker-compose-host/contributions/user-stories/platform-docker-compose-host-us-38105.json +25 -0
  175. package/blueprints/platform-docker-compose-host/contributions/user-stories/platform-docker-compose-host-us-38106.json +24 -0
  176. package/blueprints/platform-docker-compose-host/contributions/user-stories/platform-docker-compose-host-us-38107.json +24 -0
  177. package/blueprints/platform-docker-compose-host/contributions/user-stories/platform-docker-compose-host-us-38108.json +24 -0
  178. package/blueprints/platform-docker-compose-host/contributions/user-stories/platform-docker-compose-host-us-38109.json +24 -0
  179. package/blueprints/platform-docker-compose-host/docs/topics.md +71 -0
  180. package/blueprints/platform-docker-compose-host/guide/platform-docker-compose-host.md +94 -0
  181. package/blueprints/security-auth-clerk/docs/topics.md +4 -1
  182. package/blueprints/security-auth-keycloak/docs/topics.md +4 -1
  183. package/blueprints/security-auth-magic-link/docs/topics.md +4 -1
  184. package/blueprints/security-auth-oauth2/docs/topics.md +4 -1
  185. package/blueprints/security-secrets-management/docs/topics.md +4 -1
  186. package/fixtures/canary-manifest.json +9 -9
  187. package/guidance/harness-template.md +67 -0
  188. package/guidance/managed/agent-instructions-block.hash +1 -1
  189. package/guidance/managed/agent-instructions-block.md +67 -0
  190. package/package.json +2 -2
  191. package/rcf/adrs/adr-3801-deploy-hetzner-server-cloud-host-contract.json +13 -0
  192. package/rcf/adrs/adr-3802-deploy-hetzner-server-snapshot-cadence.json +13 -0
  193. package/rcf/adrs/adr-3803-deploy-hetzner-server-provisioning-tool.json +13 -0
  194. package/rcf/adrs/adr-3804-deploy-hetzner-server-hardening-baseline.json +13 -0
  195. package/rcf/adrs/adr-3901-platform-docker-compose-host-contract.json +13 -0
  196. package/rcf/adrs/adr-3902-platform-docker-compose-host-reverse-proxy.json +13 -0
  197. package/rcf/adrs/adr-3903-platform-docker-compose-host-reject-coolify.json +13 -0
  198. package/rcf/adrs/adr-3904-platform-docker-compose-host-log-driver.json +13 -0
  199. package/rcf/adrs/adr-4001-edge-cloudflare-tunnel-ingress-bridge-contract.json +13 -0
  200. package/rcf/adrs/adr-4002-edge-cloudflare-tunnel-connector-runtime.json +13 -0
  201. package/rcf/adrs/adr-4003-edge-cloudflare-tunnel-hostname-mode.json +13 -0
  202. package/rcf/code-nodes/cn-410.json +20 -0
  203. package/rcf/code-nodes/cn-440.json +20 -0
  204. package/rcf/code-nodes/cn-470.json +19 -0
  205. package/rcf/code-nodes/cn-500.json +12 -0
  206. package/rcf/code-nodes/cn-510.json +12 -0
  207. package/rcf/code-nodes/cn-520.json +14 -0
  208. package/rcf/code-nodes/cn-521.json +12 -0
  209. package/rcf/code-nodes/cn-522.json +13 -0
  210. package/rcf/code-nodes/cn-523.json +12 -0
  211. package/rcf/code-nodes/cn-524.json +14 -0
  212. package/rcf/code-nodes/cn-525.json +12 -0
  213. package/rcf/code-nodes/cn-526.json +14 -0
  214. package/rcf/fbs/fbs-130.json +23 -0
  215. package/rcf/fbs/fbs-140.json +23 -0
  216. package/rcf/fbs/fbs-150.json +22 -0
  217. package/rcf/fbs/fbs-160.json +15 -0
  218. package/rcf/fbs/fbs-165.json +15 -0
  219. package/rcf/fbs/fbs-170.json +16 -0
  220. package/rcf/fbs/fbs-171.json +16 -0
  221. package/rcf/fbs/fbs-172.json +15 -0
  222. package/rcf/fbs/fbs-173.json +17 -0
  223. package/rcf/fbs/fbs-174.json +17 -0
  224. package/rcf/requirements/req-110.json +58 -0
  225. package/rcf/requirements/req-111.json +32 -0
  226. package/rcf/requirements/req-112.json +42 -0
  227. package/rcf/requirements/req-113.json +33 -0
  228. package/rcf/requirements/req-114.json +20 -0
  229. package/rcf/requirements/req-115.json +38 -0
  230. package/rcf/requirements/req-120.json +20 -0
  231. package/rcf/requirements/req-121.json +20 -0
  232. package/rcf/requirements/req-122.json +20 -0
  233. package/rcf/requirements/req-123.json +42 -0
  234. package/rcf/requirements/req-124.json +27 -0
  235. package/rcf/requirements/req-125.json +20 -0
  236. package/rcf/requirements/req-130.json +32 -0
  237. package/rcf/requirements/req-131.json +54 -0
  238. package/rcf/requirements/req-132.json +27 -0
  239. package/rcf/requirements/req-133.json +20 -0
  240. package/rcf/requirements/req-134.json +42 -0
  241. package/rcf/requirements/req-140.json +149 -0
  242. package/rcf/requirements/req-145.json +53 -0
  243. package/rcf/requirements/req-150.json +20 -0
  244. package/rcf/requirements/req-151.json +85 -0
  245. package/rcf/requirements/req-152.json +20 -0
  246. package/rcf/requirements/req-153.json +59 -0
  247. package/rcf/requirements/req-154.json +44 -0
  248. package/rcf/tacs/tac-3801-deploy-hetzner-server-provisioner.json +17 -0
  249. package/rcf/tacs/tac-3802-deploy-hetzner-server-manifest-schema.json +17 -0
  250. package/rcf/tacs/tac-3803-deploy-hetzner-server-cloud-init-template.json +17 -0
  251. package/rcf/tacs/tac-3804-deploy-hetzner-server-firewall-shape.json +16 -0
  252. package/rcf/tacs/tac-3901-platform-docker-compose-host-compose-layout.json +17 -0
  253. package/rcf/tacs/tac-3902-platform-docker-compose-host-secrets-mount.json +17 -0
  254. package/rcf/tacs/tac-3903-platform-docker-compose-host-healthcheck-lint.json +17 -0
  255. package/rcf/tacs/tac-3904-platform-docker-compose-host-reverse-proxy-artefact.json +17 -0
  256. package/rcf/tacs/tac-4001-edge-cloudflare-tunnel-connector-shape.json +17 -0
  257. package/rcf/tacs/tac-4002-edge-cloudflare-tunnel-manifest-schema.json +17 -0
  258. package/rcf/tacs/tac-4003-edge-cloudflare-tunnel-access-binding.json +16 -0
  259. package/rcf/test-suites/ts-071.json +2 -2
  260. package/rcf/test-suites/ts-086.json +2 -2
  261. package/rcf/test-suites/ts-140.json +86 -0
  262. package/rcf/test-suites/ts-150.json +86 -0
  263. package/rcf/test-suites/ts-160.json +78 -0
  264. package/rcf/test-suites/ts-170.json +22 -0
  265. package/rcf/test-suites/ts-175.json +22 -0
  266. package/rcf/test-suites/ts-180.json +30 -0
  267. package/rcf/test-suites/ts-181.json +30 -0
  268. package/rcf/test-suites/ts-182.json +22 -0
  269. package/rcf/test-suites/ts-183.json +38 -0
  270. package/rcf/test-suites/ts-184.json +38 -0
  271. package/rcf/user-stories/us-11001.json +23 -0
  272. package/rcf/user-stories/us-11101.json +23 -0
  273. package/rcf/user-stories/us-11102.json +24 -0
  274. package/rcf/user-stories/us-11201.json +23 -0
  275. package/rcf/user-stories/us-11202.json +23 -0
  276. package/rcf/user-stories/us-11301.json +24 -0
  277. package/rcf/user-stories/us-11401.json +23 -0
  278. package/rcf/user-stories/us-11402.json +23 -0
  279. package/rcf/user-stories/us-11501.json +23 -0
  280. package/rcf/user-stories/us-12001.json +23 -0
  281. package/rcf/user-stories/us-12101.json +23 -0
  282. package/rcf/user-stories/us-12102.json +23 -0
  283. package/rcf/user-stories/us-12201.json +23 -0
  284. package/rcf/user-stories/us-12202.json +24 -0
  285. package/rcf/user-stories/us-12301.json +23 -0
  286. package/rcf/user-stories/us-12401.json +23 -0
  287. package/rcf/user-stories/us-12402.json +23 -0
  288. package/rcf/user-stories/us-12501.json +23 -0
  289. package/rcf/user-stories/us-13001.json +23 -0
  290. package/rcf/user-stories/us-13002.json +23 -0
  291. package/rcf/user-stories/us-13101.json +23 -0
  292. package/rcf/user-stories/us-13102.json +23 -0
  293. package/rcf/user-stories/us-13201.json +23 -0
  294. package/rcf/user-stories/us-13301.json +23 -0
  295. package/rcf/user-stories/us-13302.json +23 -0
  296. package/rcf/user-stories/us-13401.json +23 -0
  297. package/rcf/user-stories/us-14001.json +21 -0
  298. package/rcf/user-stories/us-14501.json +24 -0
  299. package/rcf/user-stories/us-15001.json +26 -0
  300. package/rcf/user-stories/us-15101.json +26 -0
  301. package/rcf/user-stories/us-15201.json +21 -0
  302. package/rcf/user-stories/us-15301.json +31 -0
  303. package/rcf/user-stories/us-15401.json +31 -0
  304. package/releases/releases.yaml +21 -1
  305. package/src/blueprint/apply.js +64 -0
  306. package/src/blueprint/consistency-lint.js +432 -0
  307. package/src/blueprint/disposition-ledger.js +224 -0
  308. package/src/blueprint/dispositions.js +44 -0
  309. package/src/blueprint/index.js +19 -0
  310. package/src/browser-verify/manifest-writer.js +53 -2
  311. package/src/browser-verify/pack-runner.js +18 -0
  312. package/src/cli/blueprint.js +103 -0
  313. package/src/setup/identity-seed.js +18 -0
@@ -0,0 +1,76 @@
1
+ # platform-docker-compose-host v1.0.0
2
+
3
+ A container-orchestration facade over docker compose running on a Linux `cloudHost`. Provides `containerHost` for consumer blueprints that ship as containers.
4
+
5
+ ## What it commits
6
+
7
+ Six REQs, nine USs, four TACs, four ADRs and five Node-only probes. Round-7 T-2 of the Hetzner spec at `projects/blueprint-library/specs/hetzner-round-7-spec-2026-09-07.md`.
8
+
9
+ | REQ | Contract |
10
+ |---|---|
11
+ | REQ-001 | `compose.yaml` at repo root is the single-source runtime topology (service-per-container, named networks and volumes, `.env` for non-secret config) |
12
+ | REQ-002 | Every secret injected via a docker compose secrets file mount; no plaintext literal in `compose.yaml` (grep-refuse); references `security-secrets-management` when applied |
13
+ | REQ-003 | Healthcheck contract on every HTTP-terminating service; `docker compose config` refuses on missing |
14
+ | REQ-004 | Restart discipline enforced at lint: `unless-stopped` on long-running, `on-failure` on jobs; unclassified value refuses |
15
+ | REQ-005 | Zero-downtime reverse-proxy reload via bind-mounted config; verb per proxy; no non-2xx or dropped connection inside the elicited window (10 s default) |
16
+ | REQ-006 | Log shipping to the elicited `observability-logging` sink: `journald` default matching Debian 12 / Ubuntu 24.04 baseline; `loki` opt-in when the project runs Grafana |
17
+
18
+ ## Capability
19
+
20
+ - `containerHost` (extends `blueprint-authoring.md` section 6a).
21
+
22
+ ## Suggested companions
23
+
24
+ - `logging`: every `composeStackReady`, `containerHealthy`, `containerCrashed` and `reverseProxyReloaded` event writes through the applied logger; a logging companion supplies the factory and the log-driver binding.
25
+ - `errorHandling`: a healthcheck timeout, a compose lint refusal, a secret-file-mode mismatch, a reload window overshoot constructs an internal error record; an error-handling companion supplies the record factory and the boundary.
26
+
27
+ ## Elicits (via `elicits[]`)
28
+
29
+ - `reverse-proxy`: `caddy` (default per Baz decision 19, matches dev-01 and ops-01) | `traefik` (alternative for docker-label auto-discovery) | `none` (alternative for projects fronted only by the round-7 tunnel).
30
+ - `docker-engine-channel`: `stable` (default) | `test`.
31
+ - `compose-file-location`: `repo-root` (default) | `compose/compose.yaml`.
32
+ - `healthcheck-default-kind`: `http` (default) | `tcp` | `command`.
33
+ - `log-driver`: `journald` (default per ADR-3904) | `loki` (opt-in).
34
+ - `reload-window-seconds`: default `10`.
35
+
36
+ ## ADR shape
37
+
38
+ - ADR-3901 container host contract: scope `global` on new topic `containerHostContract`; standards trace clause `Docker Compose file reference AND Docker Engine install-on-Ubuntu docs per hetzner-round-7-spec-2026-09-07.md`.
39
+ - ADR-3902 reverse proxy: elicited, `caddy` default; standards trace clause `Caddy docs AND Traefik docs per hetzner-round-7-spec-2026-09-07.md`.
40
+ - ADR-3903 reject Coolify: decision quoted verbatim from Baz ruling 20 ("reject; it shadows what the blueprints contract and adds its own DB and UI as a second source of state"); standards trace clause `generic enterprise practice`.
41
+ - ADR-3904 log driver: elicited, `journald` default; standards trace clause `generic enterprise practice`.
42
+
43
+ ## Probes
44
+
45
+ Five modules under `contributions/probes/`, each writes an envelope to `.rcf/reports/blueprints/platform-docker-compose-host/<probe>.json`:
46
+
47
+ - `compose-config-lint` (accountBound: false; anchors AC-composeHost-healthcheckLint, AC-composeHost-restartClassification, AC-composeHost-logDriverClassification). Mutations: `SIMULATE_MISSING_HEALTHCHECK`, `SIMULATE_UNCLASSIFIED_RESTART`, `SIMULATE_UNCLASSIFIED_LOG_DRIVER`, `SIMULATE_EVENT_SECRECY_LEAK`.
48
+ - `secrets-as-files-scan` (accountBound: false; anchors AC-composeHost-secretsAreFiles, AC-composeHost-secretShape). Mutation: `SIMULATE_PLAINTEXT_SECRET`.
49
+ - `caddyfile-validate` (accountBound: false; anchors AC-composeHost-reverseProxyArtefactValid). Runs a local `caddy` binary when present, otherwise the `caddy:2` container via `docker run --rm`. Mutation: `SIMULATE_INVALID_CADDYFILE`. Skipped when `REVERSE_PROXY` is not `caddy`.
50
+ - `real-account-minimal-stack-up` (accountBound: true; anchors AC-composeHost-upClean). Provisions the throwaway server, `scp`s the compose stack, runs `docker compose up -d --wait`, asserts every declared service reaches healthy inside the elicited timeout, tears down in `always()`. Records `accountBoundSkipped: true` without `CI_HAS_HETZNER_ACCOUNT`.
51
+ - `real-account-reload-burst` (accountBound: true; anchors AC-composeHost-zeroDowntimeReload). Fires an `undici` burst against the caddy service while `docker compose exec caddy caddy reload` runs, asserts every request returns 2xx inside the elicited window with no dropped connection, tears down in `always()`. Records `accountBoundSkipped: true` without `CI_HAS_HETZNER_ACCOUNT`.
52
+
53
+ ## Running the probes
54
+
55
+ From the shared throwaway-server fixture directory:
56
+
57
+ ```
58
+ cd packages/rcf-lite/test/fixtures/hetzner-throwaway-server
59
+ node ./run-compose-config-lint.mjs && node ./run-secrets-as-files-scan.mjs && node ./run-caddyfile-validate.mjs
60
+ ```
61
+
62
+ Real-account probes gate on `CI_HAS_HETZNER_ACCOUNT`:
63
+
64
+ ```
65
+ cd packages/rcf-lite/test/fixtures/hetzner-throwaway-server
66
+ CI_HAS_HETZNER_ACCOUNT=true HCLOUD_TOKEN=$HETZNER_ACCOUNT_API_KEY node ./run-real-account-minimal-stack-up.mjs && node ./run-real-account-reload-burst.mjs
67
+ ```
68
+
69
+ ## Fixture extension path
70
+
71
+ Round-7 T-1 (`deploy-hetzner-server`) minted the shared fixture at `packages/rcf-lite/test/fixtures/hetzner-throwaway-server/`. T-2 EXTENDS that fixture, never duplicates it: `compose.yaml`, `caddy/Caddyfile`, `secrets/web-token`, `src/serve.mjs` and five `run-<probe>.mjs` delegate shims land alongside T-1's `provision.mjs`/`destroy.mjs`/`sweep-orphans.mjs`. T-3 (`edge-cloudflare-tunnel`) extends the same fixture further; consumers of that fixture see one folder, one manifest, three tracks worth of runtime.
72
+
73
+ ## When to reach for this blueprint
74
+
75
+ - Any project running a containerised stack on a `cloudHost` (T-1 `deploy-hetzner-server` provides the shipped v1.0.0 provider).
76
+ - Any project that wants secrets as file mounts (not environment literals), healthchecks that gate boot, a checked-in reverse-proxy artefact, and a log driver on the elicited sink.
@@ -0,0 +1,209 @@
1
+ {
2
+ "slug": "platform-docker-compose-host",
3
+ "version": "1.0.0",
4
+ "category": "platform",
5
+ "capabilities": [
6
+ "containerHost"
7
+ ],
8
+ "suggestedCompanions": [
9
+ {
10
+ "role": "logging",
11
+ "reason": "Every composeStackReady, containerHealthy, containerCrashed and reverseProxyReloaded event writes through the applied logger; a logging companion supplies the factory and the log-driver binding."
12
+ },
13
+ {
14
+ "role": "errorHandling",
15
+ "reason": "A healthcheck timeout, a compose lint refusal, a secret-file-mode mismatch, a reload window overshoot constructs an internal error record; an error-handling companion supplies the record factory and the boundary."
16
+ }
17
+ ],
18
+ "elicits": [
19
+ {
20
+ "id": "reverse-proxy",
21
+ "prompt": "Reverse proxy in front of the compose services. caddy is the shipped default per Baz decision 19 (matches dev-01 and ops-01); traefik is the alternative for docker-label auto-discovery; none is the alternative for projects fronted only by the round-7 tunnel.",
22
+ "kind": "enum",
23
+ "options": [
24
+ "caddy",
25
+ "traefik",
26
+ "none"
27
+ ],
28
+ "default": "caddy"
29
+ },
30
+ {
31
+ "id": "docker-engine-channel",
32
+ "prompt": "Docker Engine apt channel per the Docker Engine install-on-Ubuntu docs. stable is the shipped default; test is for pre-release verification; the vendor also documents nightly builds available separately.",
33
+ "kind": "enum",
34
+ "options": [
35
+ "stable",
36
+ "test"
37
+ ],
38
+ "default": "stable"
39
+ },
40
+ {
41
+ "id": "compose-file-location",
42
+ "prompt": "Where the compose.yaml lives in the applying repo. repo-root is the shipped default; the alternative name is used when a project already owns compose.yaml for another purpose.",
43
+ "kind": "enum",
44
+ "options": [
45
+ "repo-root",
46
+ "compose/compose.yaml"
47
+ ],
48
+ "default": "repo-root"
49
+ },
50
+ {
51
+ "id": "healthcheck-default-kind",
52
+ "prompt": "Default healthcheck kind per service. http covers the common web service (curl or wget to a /health path); tcp covers a database or plain socket service; command lets the operator supply a bespoke test string.",
53
+ "kind": "enum",
54
+ "options": [
55
+ "http",
56
+ "tcp",
57
+ "command"
58
+ ],
59
+ "default": "http"
60
+ },
61
+ {
62
+ "id": "log-driver",
63
+ "prompt": "Container log driver per ADR-3904. journald is the shipped default matching the Debian 12 and Ubuntu 24.04 baseline T-1 sets up; loki is the opt-in alternative when the project runs Grafana.",
64
+ "kind": "enum",
65
+ "options": [
66
+ "journald",
67
+ "loki"
68
+ ],
69
+ "default": "journald"
70
+ },
71
+ {
72
+ "id": "reload-window-seconds",
73
+ "prompt": "Zero-downtime reverse-proxy reload window in seconds (the maximum time a client burst may see any non-2xx or dropped connection during a reload). 10 is the shipped default per REQ-005.",
74
+ "kind": "string",
75
+ "default": "10"
76
+ }
77
+ ],
78
+ "contributions": [
79
+ {
80
+ "id": "platform-docker-compose-host-REQ-001",
81
+ "kind": "req",
82
+ "path": "requirements/platform-docker-compose-host-req-001.json"
83
+ },
84
+ {
85
+ "id": "platform-docker-compose-host-REQ-002",
86
+ "kind": "req",
87
+ "path": "requirements/platform-docker-compose-host-req-002.json"
88
+ },
89
+ {
90
+ "id": "platform-docker-compose-host-REQ-003",
91
+ "kind": "req",
92
+ "path": "requirements/platform-docker-compose-host-req-003.json"
93
+ },
94
+ {
95
+ "id": "platform-docker-compose-host-REQ-004",
96
+ "kind": "req",
97
+ "path": "requirements/platform-docker-compose-host-req-004.json"
98
+ },
99
+ {
100
+ "id": "platform-docker-compose-host-REQ-005",
101
+ "kind": "req",
102
+ "path": "requirements/platform-docker-compose-host-req-005.json"
103
+ },
104
+ {
105
+ "id": "platform-docker-compose-host-REQ-006",
106
+ "kind": "req",
107
+ "path": "requirements/platform-docker-compose-host-req-006.json"
108
+ },
109
+ {
110
+ "id": "platform-docker-compose-host-US-38101",
111
+ "kind": "us",
112
+ "path": "user-stories/platform-docker-compose-host-us-38101.json"
113
+ },
114
+ {
115
+ "id": "platform-docker-compose-host-US-38102",
116
+ "kind": "us",
117
+ "path": "user-stories/platform-docker-compose-host-us-38102.json"
118
+ },
119
+ {
120
+ "id": "platform-docker-compose-host-US-38103",
121
+ "kind": "us",
122
+ "path": "user-stories/platform-docker-compose-host-us-38103.json"
123
+ },
124
+ {
125
+ "id": "platform-docker-compose-host-US-38104",
126
+ "kind": "us",
127
+ "path": "user-stories/platform-docker-compose-host-us-38104.json"
128
+ },
129
+ {
130
+ "id": "platform-docker-compose-host-US-38105",
131
+ "kind": "us",
132
+ "path": "user-stories/platform-docker-compose-host-us-38105.json"
133
+ },
134
+ {
135
+ "id": "platform-docker-compose-host-US-38106",
136
+ "kind": "us",
137
+ "path": "user-stories/platform-docker-compose-host-us-38106.json"
138
+ },
139
+ {
140
+ "id": "platform-docker-compose-host-US-38107",
141
+ "kind": "us",
142
+ "path": "user-stories/platform-docker-compose-host-us-38107.json"
143
+ },
144
+ {
145
+ "id": "platform-docker-compose-host-US-38108",
146
+ "kind": "us",
147
+ "path": "user-stories/platform-docker-compose-host-us-38108.json"
148
+ },
149
+ {
150
+ "id": "platform-docker-compose-host-US-38109",
151
+ "kind": "us",
152
+ "path": "user-stories/platform-docker-compose-host-us-38109.json"
153
+ },
154
+ {
155
+ "id": "TAC-3901-platform-docker-compose-host-compose-layout",
156
+ "kind": "tac",
157
+ "path": "tacs/tac-3901-platform-docker-compose-host-compose-layout.json"
158
+ },
159
+ {
160
+ "id": "TAC-3902-platform-docker-compose-host-secrets-mount",
161
+ "kind": "tac",
162
+ "path": "tacs/tac-3902-platform-docker-compose-host-secrets-mount.json"
163
+ },
164
+ {
165
+ "id": "TAC-3903-platform-docker-compose-host-healthcheck-lint",
166
+ "kind": "tac",
167
+ "path": "tacs/tac-3903-platform-docker-compose-host-healthcheck-lint.json"
168
+ },
169
+ {
170
+ "id": "TAC-3904-platform-docker-compose-host-reverse-proxy-artefact",
171
+ "kind": "tac",
172
+ "path": "tacs/tac-3904-platform-docker-compose-host-reverse-proxy-artefact.json"
173
+ },
174
+ {
175
+ "id": "ADR-3901-platform-docker-compose-host-contract",
176
+ "kind": "adr",
177
+ "path": "adrs/adr-3901-platform-docker-compose-host-contract.json",
178
+ "scope": "global",
179
+ "topic": "containerHostContract",
180
+ "recommendedDefault": true,
181
+ "elicited": false,
182
+ "standardsTraceClause": "Docker Compose file reference AND Docker Engine install-on-Ubuntu docs per hetzner-round-7-spec-2026-09-07.md"
183
+ },
184
+ {
185
+ "id": "ADR-3902-platform-docker-compose-host-reverse-proxy",
186
+ "kind": "adr",
187
+ "path": "adrs/adr-3902-platform-docker-compose-host-reverse-proxy.json",
188
+ "recommendedDefault": true,
189
+ "elicited": true,
190
+ "standardsTraceClause": "Caddy docs AND Traefik docs per hetzner-round-7-spec-2026-09-07.md"
191
+ },
192
+ {
193
+ "id": "ADR-3903-platform-docker-compose-host-reject-coolify",
194
+ "kind": "adr",
195
+ "path": "adrs/adr-3903-platform-docker-compose-host-reject-coolify.json",
196
+ "recommendedDefault": false,
197
+ "elicited": false,
198
+ "standardsTraceClause": "generic enterprise practice"
199
+ },
200
+ {
201
+ "id": "ADR-3904-platform-docker-compose-host-log-driver",
202
+ "kind": "adr",
203
+ "path": "adrs/adr-3904-platform-docker-compose-host-log-driver.json",
204
+ "recommendedDefault": true,
205
+ "elicited": true,
206
+ "standardsTraceClause": "generic enterprise practice"
207
+ }
208
+ ]
209
+ }
@@ -0,0 +1,14 @@
1
+ {
2
+ "adrId": "ADR-3901-platform-docker-compose-host-contract",
3
+ "prdId": "PRD-001",
4
+ "tadId": "TAD-001",
5
+ "version": "1.0.0",
6
+ "status": "accepted",
7
+ "title": "Container host contract: docker compose as source of truth on a cloudHost (scope global, new topic containerHostContract)",
8
+ "context": "An applying project running its stack on a Linux cloudHost needs one shipped contract for how services are declared, wired and brought up on a container-orchestration surface. Round-7 T-2 mints the containerHostContract topic on this ADR. Docker Compose is the shipped v1.0.0 surface (compose.yaml as source of truth, healthchecks required, secrets as files, restart discipline, reverse-proxy as artefact). Every applied container host needs one project-wide answer to the containerHostContract topic; a future non-compose sibling (Docker Swarm, Nomad) would contribute the same topic string with a different mechanism, forcing a DELIBERATE conflict the operator resolves per the round-2 conflict pattern. Standards trace clause: Docker Compose file reference AND Docker Engine install-on-Ubuntu docs per hetzner-round-7-spec-2026-09-07.md.",
9
+ "decision": "The shipped v1.0.0 default is docker compose on a cloudHost as the containerHostContract provider. A canonical compose.yaml at the repo root drives docker compose up on the applied cloudHost (T-1 deploy-hetzner-server); healthchecks refuse at docker compose config on missing; secrets are file mounts; restart policies are unless-stopped or on-failure; the reverse-proxy config is a first-class versioned artefact per TAC-3904. The containerHostContract topic scope is global on this blueprint; the topic string is containerHostContract (lower camelCase, one concept per topic, no version suffix, per the round-2 rules-for-new-topics clause on the shelf registry). Standards trace clause: Docker Compose file reference AND Docker Engine install-on-Ubuntu docs per hetzner-round-7-spec-2026-09-07.md.",
10
+ "consequences": "Consumer blueprints that ship as containers declare capabilities: [containerHost] on their applied contract; the round-7 T-3 edge-cloudflare-tunnel reads this capability at apply-time to choose the compose-service runtime. Rebuild-from-manifest is always possible: the compose file is the source of truth, the running stack is derivative. Compose is famously many right ways; over-specifying alienates a project with a defensible different shape, so v1.0.0 pins the small load-bearing set (healthchecks, secrets-as-files, restart discipline, reverse-proxy-as-artefact) and leaves everything else to project-owned ADRs.",
11
+ "alternativesConsidered": [],
12
+ "createdAt": "2026-09-08T00:00:00.000Z",
13
+ "updatedAt": "2026-09-08T00:00:00.000Z"
14
+ }
@@ -0,0 +1,14 @@
1
+ {
2
+ "adrId": "ADR-3902-platform-docker-compose-host-reverse-proxy",
3
+ "prdId": "PRD-001",
4
+ "tadId": "TAD-001",
5
+ "version": "1.0.0",
6
+ "status": "accepted",
7
+ "title": "Reverse proxy choice: caddy default (matches dev-01 and ops-01), traefik alternative for docker-label auto-discovery, none for tunnel-fronted projects (elicited)",
8
+ "context": "Compose stacks need a reverse-proxy for HTTPS termination and hostname-to-service routing. Caddy is the estate baseline (dev-01 and ops-01 already run it per Baz decision 19 on 2026-09-07 09:50Z). Traefik has a docker-label auto-discovery model some projects prefer. Some projects front their stack only with the round-7 tunnel and skip a reverse proxy inside compose.",
9
+ "decision": "The reverse-proxy choice is elicited via the reverseProxy parameter. The shipped default is caddy per Baz decision 19. The alternatives are traefik (for projects that want docker-label auto-discovery) and none (for projects fronted only by the round-7 tunnel). Standards trace clause: Caddy docs AND Traefik docs per hetzner-round-7-spec-2026-09-07.md.",
10
+ "consequences": "A project applying reverseProxy=caddy gets the caddy/Caddyfile artefact and the caddy reload verb. A project applying reverseProxy=traefik gets the traefik/traefik.yaml artefact and the Traefik equivalent reload verb; docker-label auto-discovery is a project-side pattern the guide names. A project applying reverseProxy=none omits the reverse-proxy service and must apply edge-cloudflare-tunnel (T-3) so ingress terminates at the CF edge.",
11
+ "alternativesConsidered": [],
12
+ "createdAt": "2026-09-08T00:00:00.000Z",
13
+ "updatedAt": "2026-09-08T00:00:00.000Z"
14
+ }
@@ -0,0 +1,14 @@
1
+ {
2
+ "adrId": "ADR-3903-platform-docker-compose-host-reject-coolify",
3
+ "prdId": "PRD-001",
4
+ "tadId": "TAD-001",
5
+ "version": "1.0.0",
6
+ "status": "accepted",
7
+ "title": "Coolify rejected per Baz decision 20 (it shadows what the blueprints contract and adds its own DB and UI as a second source of state)",
8
+ "context": "Coolify was proposed as a candidate platform-* sibling in the round-7 proposal. It is a self-hosted PaaS with its own database and UI. Baz decision 20 on 2026-09-07 09:50Z ruled Coolify out for round 7.",
9
+ "decision": "reject; it shadows what the blueprints contract and adds its own DB and UI as a second source of state.",
10
+ "consequences": "No platform-coolify-host blueprint is scoped in round 7 and no reserved slot is allocated. A future platform-coolify-host sibling mints on operator demand under a fresh scope PR. The standards trace clause on the contribution entry is generic enterprise practice; no vendor-doc URL is claimed for the reject decision.",
11
+ "alternativesConsidered": [],
12
+ "createdAt": "2026-09-08T00:00:00.000Z",
13
+ "updatedAt": "2026-09-08T00:00:00.000Z"
14
+ }
@@ -0,0 +1,14 @@
1
+ {
2
+ "adrId": "ADR-3904-platform-docker-compose-host-log-driver",
3
+ "prdId": "PRD-001",
4
+ "tadId": "TAD-001",
5
+ "version": "1.0.0",
6
+ "status": "accepted",
7
+ "title": "Log driver: journald default matching Debian 12 and Ubuntu 24.04 baseline; loki opt-in when the project runs Grafana (elicited)",
8
+ "context": "Containers write stdout and stderr to a log driver. Debian 12 and Ubuntu 24.04 (the T-1 cloud-init baseline) ship journald. Grafana users on the estate reach for loki as a native sink. A one-choice hard-code loses either journald parity with the OS or loki when the operator runs Grafana.",
9
+ "decision": "The log driver is elicited via the log-driver parameter. The shipped default is journald matching the Debian 12 and Ubuntu 24.04 baselines T-1 sets up. The alternative is loki, opted into when the applying project runs Grafana. When observability-logging is applied, the compose file wires the elicited driver to that companion. Standards trace clause: generic enterprise practice.",
10
+ "consequences": "A project applying log-driver=journald gets the systemd-native path; the journald sink is queried via journalctl. A project applying log-driver=loki targets the Grafana loki endpoint; the observability-logging companion supplies the endpoint address. Neither choice adds a runtime npm dependency. The compose-config-lint refuses on any driver value outside the allowed set.",
11
+ "alternativesConsidered": [],
12
+ "createdAt": "2026-09-08T00:00:00.000Z",
13
+ "updatedAt": "2026-09-08T00:00:00.000Z"
14
+ }
@@ -0,0 +1,108 @@
1
+ // Probe: caddyfile-validate.
2
+ //
3
+ // anchorAcId: AC-composeHost-reverseProxyArtefactValid.
4
+ // accountBound: false.
5
+ //
6
+ // Runs caddy validate against the applied fixture caddy/Caddyfile. When
7
+ // a local caddy binary is not on PATH the probe uses the caddy:2
8
+ // container image via docker run --rm (pinned tag), so review machines
9
+ // without a local caddy still get a real validation. When neither is
10
+ // available the probe records skipped with a warn note.
11
+ //
12
+ // The applying project may set reverseProxy to a value other than caddy
13
+ // (traefik or none per ADR-3902); when that happens the probe returns
14
+ // skipped with note.
15
+ //
16
+ // Mutation:
17
+ // - SIMULATE_INVALID_CADDYFILE=true writes an obviously-invalid
18
+ // directive (\"not-a-directive-at-all\") into a scratch copy of the
19
+ // Caddyfile; the probe FAILS naming the offending line.
20
+
21
+ import { readFile, writeFile, mkdir, rm } from 'node:fs/promises';
22
+ import { spawnSync } from 'node:child_process';
23
+ import { tmpdir } from 'node:os';
24
+ import { join, dirname } from 'node:path';
25
+ import { runShim, CADDYFILE_PATH, whichCaddy, whichDocker } from './probe-utils.mjs';
26
+
27
+ export const anchorAcId = 'AC-composeHost-reverseProxyArtefactValid';
28
+ export const accountBound = false;
29
+
30
+ function isCaddyReverseProxy() {
31
+ // Applying project passes reverseProxy via env for the probe run; the
32
+ // shipped default per ADR-3902 is caddy.
33
+ const v = process.env.REVERSE_PROXY;
34
+ if (v === undefined || v === 'caddy') return true;
35
+ return false;
36
+ }
37
+
38
+ export default async function runProbe() {
39
+ const results = [];
40
+ const extra = {};
41
+ extra.mutations = { invalidCaddyfile: process.env.SIMULATE_INVALID_CADDYFILE === 'true' };
42
+ extra.reverseProxy = process.env.REVERSE_PROXY ?? 'caddy';
43
+ if (!isCaddyReverseProxy()) {
44
+ results.push({
45
+ anchorAcId,
46
+ verdict: 'skipped',
47
+ detail: `reverseProxy=${extra.reverseProxy}: caddyfile-validate skipped (applies only when reverseProxy=caddy)`,
48
+ });
49
+ return { results, extra };
50
+ }
51
+ const scratchDir = join(tmpdir(), `rcf-lite-t2-caddyfile-validate-${Date.now()}`);
52
+ await mkdir(scratchDir, { recursive: true });
53
+ const scratchPath = join(scratchDir, 'Caddyfile');
54
+ try {
55
+ let text = await readFile(CADDYFILE_PATH, 'utf8');
56
+ if (process.env.SIMULATE_INVALID_CADDYFILE === 'true') {
57
+ text = text + "\n{ unclosed_block_that_never_ends_and_is_a_syntax_error_caddy_will_reject\n";
58
+ }
59
+ await writeFile(scratchPath, text, 'utf8');
60
+ const localCaddy = whichCaddy();
61
+ const localDocker = whichDocker();
62
+ extra.caddyLocal = localCaddy;
63
+ extra.dockerLocal = localDocker;
64
+ let cmd, args, engineLabel;
65
+ if (localCaddy !== null) {
66
+ cmd = 'caddy';
67
+ args = ['validate', '--config', scratchPath, '--adapter', 'caddyfile'];
68
+ engineLabel = `local caddy ${localCaddy}`;
69
+ } else if (localDocker !== null) {
70
+ cmd = 'docker';
71
+ args = ['run', '--rm', '-v', `${scratchDir}:/etc/caddy:ro`, 'caddy:2',
72
+ 'caddy', 'validate', '--config', '/etc/caddy/Caddyfile', '--adapter', 'caddyfile'];
73
+ engineLabel = 'caddy:2 container (docker run --rm)';
74
+ } else {
75
+ results.push({
76
+ anchorAcId,
77
+ verdict: 'warn',
78
+ detail: 'neither caddy binary nor docker on PATH; caddy validate could not be exercised',
79
+ });
80
+ return { results, extra };
81
+ }
82
+ const r = spawnSync(cmd, args, { encoding: 'utf8', timeout: 60_000 });
83
+ extra.exitStatus = r.status;
84
+ extra.engineLabel = engineLabel;
85
+ const tail = ((r.stderr || '') + (r.stdout || '')).split('\n').slice(-10).join('\n');
86
+ if (r.status === 0) {
87
+ results.push({
88
+ anchorAcId,
89
+ verdict: 'pass',
90
+ detail: `caddy validate exit 0 (${engineLabel}); tail: ${tail.slice(-200)}`,
91
+ });
92
+ } else {
93
+ results.push({
94
+ anchorAcId,
95
+ verdict: 'fail',
96
+ detail: `caddy validate exit ${r.status} (${engineLabel}); tail: ${tail.slice(-400)}`,
97
+ });
98
+ }
99
+ } finally {
100
+ await rm(scratchDir, { recursive: true, force: true });
101
+ }
102
+ return { results, extra };
103
+ }
104
+
105
+ const engine = { kind: 'caddy-validate', image: 'caddy:2 (or local caddy binary)', healthy: true };
106
+ if (import.meta.url === `file://${process.argv[1]}`) {
107
+ await runShim('caddyfile-validate', engine, runProbe);
108
+ }