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.
- package/CHANGELOG.md +36 -0
- package/blueprints/application-account-settings/docs/topics.md +4 -1
- package/blueprints/application-admin-console/docs/topics.md +4 -1
- package/blueprints/application-api-rest/docs/topics.md +4 -1
- package/blueprints/application-charts/docs/topics.md +4 -1
- package/blueprints/application-dashboard/docs/topics.md +4 -1
- package/blueprints/application-datatable/docs/topics.md +4 -1
- package/blueprints/application-empty-error-states/docs/topics.md +4 -1
- package/blueprints/application-error-handling/docs/topics.md +4 -1
- package/blueprints/application-file-upload/docs/topics.md +4 -1
- package/blueprints/application-forms-wizard/docs/topics.md +4 -1
- package/blueprints/application-notifications-in-app/docs/topics.md +4 -1
- package/blueprints/application-onboarding-tour/docs/topics.md +4 -1
- package/blueprints/application-spa/docs/topics.md +4 -1
- package/blueprints/delivery-ci-workflows/docs/topics.md +4 -1
- package/blueprints/deploy-cloudflare-workers/docs/topics.md +4 -1
- package/blueprints/deploy-hetzner-server/CHANGELOG.md +55 -0
- package/blueprints/deploy-hetzner-server/README.md +202 -0
- package/blueprints/deploy-hetzner-server/blueprint.json +233 -0
- package/blueprints/deploy-hetzner-server/contributions/adrs/adr-3801-deploy-hetzner-server-cloud-host-contract.json +14 -0
- package/blueprints/deploy-hetzner-server/contributions/adrs/adr-3802-deploy-hetzner-server-snapshot-cadence.json +14 -0
- package/blueprints/deploy-hetzner-server/contributions/adrs/adr-3803-deploy-hetzner-server-provisioning-tool.json +20 -0
- package/blueprints/deploy-hetzner-server/contributions/adrs/adr-3804-deploy-hetzner-server-hardening-baseline.json +14 -0
- package/blueprints/deploy-hetzner-server/contributions/probes/cloud-init-render-lint.mjs +71 -0
- package/blueprints/deploy-hetzner-server/contributions/probes/hcloud-dry-run-mock.mjs +164 -0
- package/blueprints/deploy-hetzner-server/contributions/probes/manifest-schema-validate.mjs +182 -0
- package/blueprints/deploy-hetzner-server/contributions/probes/probe-utils.mjs +112 -0
- package/blueprints/deploy-hetzner-server/contributions/probes/real-account-cloud-init-hardened.mjs +64 -0
- package/blueprints/deploy-hetzner-server/contributions/probes/real-account-snapshot-on-demand.mjs +60 -0
- package/blueprints/deploy-hetzner-server/contributions/probes/real-account-throwaway-server-provision.mjs +58 -0
- package/blueprints/deploy-hetzner-server/contributions/probes/run-cloud-init-render-lint.mjs +9 -0
- package/blueprints/deploy-hetzner-server/contributions/probes/run-hcloud-dry-run-mock.mjs +9 -0
- package/blueprints/deploy-hetzner-server/contributions/probes/run-manifest-schema-validate.mjs +9 -0
- package/blueprints/deploy-hetzner-server/contributions/probes/run-real-account-cloud-init-hardened.mjs +9 -0
- package/blueprints/deploy-hetzner-server/contributions/probes/run-real-account-snapshot-on-demand.mjs +9 -0
- package/blueprints/deploy-hetzner-server/contributions/probes/run-real-account-throwaway-server-provision.mjs +9 -0
- package/blueprints/deploy-hetzner-server/contributions/requirements/deploy-hetzner-server-req-001.json +18 -0
- package/blueprints/deploy-hetzner-server/contributions/requirements/deploy-hetzner-server-req-002.json +18 -0
- package/blueprints/deploy-hetzner-server/contributions/requirements/deploy-hetzner-server-req-003.json +18 -0
- package/blueprints/deploy-hetzner-server/contributions/requirements/deploy-hetzner-server-req-004.json +18 -0
- package/blueprints/deploy-hetzner-server/contributions/requirements/deploy-hetzner-server-req-005.json +18 -0
- package/blueprints/deploy-hetzner-server/contributions/requirements/deploy-hetzner-server-req-006.json +18 -0
- package/blueprints/deploy-hetzner-server/contributions/schemas/hetzner-server.schema.json +108 -0
- package/blueprints/deploy-hetzner-server/contributions/tacs/tac-3801-deploy-hetzner-server-provisioner.json +27 -0
- package/blueprints/deploy-hetzner-server/contributions/tacs/tac-3802-deploy-hetzner-server-manifest-schema.json +26 -0
- package/blueprints/deploy-hetzner-server/contributions/tacs/tac-3803-deploy-hetzner-server-cloud-init-template.json +26 -0
- package/blueprints/deploy-hetzner-server/contributions/tacs/tac-3804-deploy-hetzner-server-firewall-shape.json +25 -0
- package/blueprints/deploy-hetzner-server/contributions/templates/cloud-init.yaml.tmpl +113 -0
- package/blueprints/deploy-hetzner-server/contributions/user-stories/deploy-hetzner-server-us-37101.json +24 -0
- package/blueprints/deploy-hetzner-server/contributions/user-stories/deploy-hetzner-server-us-37102.json +24 -0
- package/blueprints/deploy-hetzner-server/contributions/user-stories/deploy-hetzner-server-us-37103.json +25 -0
- package/blueprints/deploy-hetzner-server/contributions/user-stories/deploy-hetzner-server-us-37104.json +24 -0
- package/blueprints/deploy-hetzner-server/contributions/user-stories/deploy-hetzner-server-us-37105.json +24 -0
- package/blueprints/deploy-hetzner-server/contributions/user-stories/deploy-hetzner-server-us-37106.json +25 -0
- package/blueprints/deploy-hetzner-server/contributions/user-stories/deploy-hetzner-server-us-37107.json +24 -0
- package/blueprints/deploy-hetzner-server/contributions/user-stories/deploy-hetzner-server-us-37108.json +24 -0
- package/blueprints/deploy-hetzner-server/contributions/user-stories/deploy-hetzner-server-us-37109.json +24 -0
- package/blueprints/deploy-hetzner-server/docs/topics.md +48 -0
- package/blueprints/deploy-hetzner-server/guide/deploy-hetzner-server.md +180 -0
- package/blueprints/edge-cloudflare-access/docs/topics.md +4 -1
- package/blueprints/edge-cloudflare-rate-limiting/docs/topics.md +4 -1
- package/blueprints/edge-cloudflare-tunnel/CHANGELOG.md +23 -0
- package/blueprints/edge-cloudflare-tunnel/README.md +257 -0
- package/blueprints/edge-cloudflare-tunnel/blueprint.json +168 -0
- package/blueprints/edge-cloudflare-tunnel/contributions/adrs/adr-4001-edge-cloudflare-tunnel-ingress-bridge-contract.json +23 -0
- package/blueprints/edge-cloudflare-tunnel/contributions/adrs/adr-4002-edge-cloudflare-tunnel-connector-runtime.json +19 -0
- package/blueprints/edge-cloudflare-tunnel/contributions/adrs/adr-4003-edge-cloudflare-tunnel-hostname-mode.json +19 -0
- package/blueprints/edge-cloudflare-tunnel/contributions/probes/aud-presence-check.mjs +114 -0
- package/blueprints/edge-cloudflare-tunnel/contributions/probes/cloudflared-config-lint.mjs +80 -0
- package/blueprints/edge-cloudflare-tunnel/contributions/probes/manifest-schema-validate.mjs +237 -0
- package/blueprints/edge-cloudflare-tunnel/contributions/probes/probe-utils.mjs +231 -0
- package/blueprints/edge-cloudflare-tunnel/contributions/probes/real-account-connector-healthy.mjs +143 -0
- package/blueprints/edge-cloudflare-tunnel/contributions/probes/real-account-tunnel-hostname-routes.mjs +166 -0
- package/blueprints/edge-cloudflare-tunnel/contributions/probes/run-aud-presence-check.mjs +4 -0
- package/blueprints/edge-cloudflare-tunnel/contributions/probes/run-cloudflared-config-lint.mjs +4 -0
- package/blueprints/edge-cloudflare-tunnel/contributions/probes/run-manifest-schema-validate.mjs +4 -0
- package/blueprints/edge-cloudflare-tunnel/contributions/probes/run-real-account-connector-healthy.mjs +4 -0
- package/blueprints/edge-cloudflare-tunnel/contributions/probes/run-real-account-tunnel-hostname-routes.mjs +4 -0
- package/blueprints/edge-cloudflare-tunnel/contributions/probes/tunnel-manifest.schema.json +55 -0
- package/blueprints/edge-cloudflare-tunnel/contributions/requirements/edge-cloudflare-tunnel-req-001.json +18 -0
- package/blueprints/edge-cloudflare-tunnel/contributions/requirements/edge-cloudflare-tunnel-req-002.json +18 -0
- package/blueprints/edge-cloudflare-tunnel/contributions/requirements/edge-cloudflare-tunnel-req-003.json +18 -0
- package/blueprints/edge-cloudflare-tunnel/contributions/requirements/edge-cloudflare-tunnel-req-004.json +18 -0
- package/blueprints/edge-cloudflare-tunnel/contributions/requirements/edge-cloudflare-tunnel-req-005.json +18 -0
- package/blueprints/edge-cloudflare-tunnel/contributions/tacs/tac-4001-edge-cloudflare-tunnel-connector-shape.json +26 -0
- package/blueprints/edge-cloudflare-tunnel/contributions/tacs/tac-4002-edge-cloudflare-tunnel-manifest-schema.json +26 -0
- package/blueprints/edge-cloudflare-tunnel/contributions/tacs/tac-4003-edge-cloudflare-tunnel-access-binding.json +25 -0
- package/blueprints/edge-cloudflare-tunnel/contributions/user-stories/edge-cloudflare-tunnel-us-39101.json +24 -0
- package/blueprints/edge-cloudflare-tunnel/contributions/user-stories/edge-cloudflare-tunnel-us-39102.json +24 -0
- package/blueprints/edge-cloudflare-tunnel/contributions/user-stories/edge-cloudflare-tunnel-us-39103.json +24 -0
- package/blueprints/edge-cloudflare-tunnel/contributions/user-stories/edge-cloudflare-tunnel-us-39104.json +24 -0
- package/blueprints/edge-cloudflare-tunnel/contributions/user-stories/edge-cloudflare-tunnel-us-39105.json +24 -0
- package/blueprints/edge-cloudflare-tunnel/contributions/user-stories/edge-cloudflare-tunnel-us-39106.json +24 -0
- package/blueprints/edge-cloudflare-tunnel/contributions/user-stories/edge-cloudflare-tunnel-us-39107.json +24 -0
- package/blueprints/edge-cloudflare-tunnel/contributions/user-stories/edge-cloudflare-tunnel-us-39108.json +24 -0
- package/blueprints/edge-cloudflare-tunnel/docs/topics.md +72 -0
- package/blueprints/edge-cloudflare-tunnel/guide/edge-cloudflare-tunnel.md +204 -0
- package/blueprints/edge-cloudflare-turnstile/docs/topics.md +4 -1
- package/blueprints/email-smtp-resend/docs/topics.md +4 -1
- package/blueprints/jobs-background/docs/topics.md +4 -1
- package/blueprints/messaging-queue-cloudflare/CHANGELOG.md +19 -0
- package/blueprints/messaging-queue-cloudflare/README.md +2 -2
- package/blueprints/messaging-queue-cloudflare/blueprint.json +1 -1
- package/blueprints/messaging-queue-cloudflare/contributions/probes/real-account-concurrency-smoke.mjs +192 -37
- package/blueprints/messaging-queue-cloudflare/docs/topics.md +4 -1
- package/blueprints/object-storage-s3/CHANGELOG.md +11 -0
- package/blueprints/object-storage-s3/README.md +14 -1
- package/blueprints/object-storage-s3/blueprint.json +12 -1
- package/blueprints/object-storage-s3/contributions/adrs/adr-2905-object-storage-s3-hetzner-object-storage-provider.json +30 -0
- package/blueprints/object-storage-s3/contributions/probes/hetzner-object-storage-round-trip.mjs +136 -0
- package/blueprints/object-storage-s3/contributions/probes/run-hetzner-object-storage-round-trip.mjs +11 -0
- package/blueprints/object-storage-s3/contributions/requirements/object-storage-s3-req-101.json +18 -0
- package/blueprints/object-storage-s3/contributions/tacs/tac-2904-object-storage-s3-hetzner-endpoint-helper.json +34 -0
- package/blueprints/object-storage-s3/contributions/user-stories/object-storage-s3-us-28110.json +25 -0
- package/blueprints/object-storage-s3/docs/topics.md +4 -1
- package/blueprints/object-storage-s3/guide/object-storage-s3.md +36 -0
- package/blueprints/observability-essentials/docs/topics.md +4 -1
- package/blueprints/observability-logging/docs/topics.md +4 -1
- package/blueprints/observability-probe-endpoints/docs/topics.md +4 -1
- package/blueprints/persistence-data-d1/docs/topics.md +4 -1
- package/blueprints/persistence-data-postgres/docs/topics.md +4 -1
- package/blueprints/persistence-data-sqlite/docs/topics.md +4 -1
- package/blueprints/platform-cloudflare-cron-triggers/docs/topics.md +4 -1
- package/blueprints/platform-cloudflare-durable-objects/CHANGELOG.md +15 -0
- package/blueprints/platform-cloudflare-durable-objects/blueprint.json +1 -1
- package/blueprints/platform-cloudflare-durable-objects/contributions/probes/namespace-facade-ready.mjs +3 -3
- package/blueprints/platform-cloudflare-durable-objects/contributions/probes/probe-utils.mjs +28 -14
- package/blueprints/platform-cloudflare-durable-objects/contributions/probes/real-account-storage-smoke.mjs +132 -26
- package/blueprints/platform-cloudflare-durable-objects/contributions/probes/sole-reader-scan.mjs +40 -39
- package/blueprints/platform-cloudflare-durable-objects/contributions/probes/storage-round-trip.mjs +26 -16
- package/blueprints/platform-cloudflare-durable-objects/contributions/probes/websocket-hub-broadcast.mjs +31 -34
- package/blueprints/platform-cloudflare-durable-objects/docs/topics.md +4 -1
- package/blueprints/platform-cloudflare-kv/CHANGELOG.md +40 -1
- package/blueprints/platform-cloudflare-kv/README.md +41 -13
- package/blueprints/platform-cloudflare-kv/blueprint.json +1 -1
- package/blueprints/platform-cloudflare-kv/contributions/probes/cache-aside-hit-then-miss.mjs +26 -26
- package/blueprints/platform-cloudflare-kv/contributions/probes/event-secrecy.mjs +49 -31
- package/blueprints/platform-cloudflare-kv/contributions/probes/facade-round-trip.mjs +58 -16
- package/blueprints/platform-cloudflare-kv/contributions/probes/list-with-prefix.mjs +6 -5
- package/blueprints/platform-cloudflare-kv/contributions/probes/real-account-eventual-consistency-smoke.mjs +131 -67
- package/blueprints/platform-cloudflare-kv/docs/topics.md +4 -1
- package/blueprints/platform-docker-compose-host/CHANGELOG.md +12 -0
- package/blueprints/platform-docker-compose-host/README.md +76 -0
- package/blueprints/platform-docker-compose-host/blueprint.json +209 -0
- package/blueprints/platform-docker-compose-host/contributions/adrs/adr-3901-platform-docker-compose-host-contract.json +14 -0
- package/blueprints/platform-docker-compose-host/contributions/adrs/adr-3902-platform-docker-compose-host-reverse-proxy.json +14 -0
- package/blueprints/platform-docker-compose-host/contributions/adrs/adr-3903-platform-docker-compose-host-reject-coolify.json +14 -0
- package/blueprints/platform-docker-compose-host/contributions/adrs/adr-3904-platform-docker-compose-host-log-driver.json +14 -0
- package/blueprints/platform-docker-compose-host/contributions/probes/caddyfile-validate.mjs +108 -0
- package/blueprints/platform-docker-compose-host/contributions/probes/compose-config-lint.mjs +231 -0
- package/blueprints/platform-docker-compose-host/contributions/probes/probe-utils.mjs +185 -0
- package/blueprints/platform-docker-compose-host/contributions/probes/real-account-minimal-stack-up.mjs +41 -0
- package/blueprints/platform-docker-compose-host/contributions/probes/real-account-reload-burst.mjs +36 -0
- package/blueprints/platform-docker-compose-host/contributions/probes/run-caddyfile-validate.mjs +5 -0
- package/blueprints/platform-docker-compose-host/contributions/probes/run-compose-config-lint.mjs +5 -0
- package/blueprints/platform-docker-compose-host/contributions/probes/run-real-account-minimal-stack-up.mjs +5 -0
- package/blueprints/platform-docker-compose-host/contributions/probes/run-real-account-reload-burst.mjs +5 -0
- package/blueprints/platform-docker-compose-host/contributions/probes/run-secrets-as-files-scan.mjs +5 -0
- package/blueprints/platform-docker-compose-host/contributions/probes/secrets-as-files-scan.mjs +116 -0
- package/blueprints/platform-docker-compose-host/contributions/requirements/platform-docker-compose-host-req-001.json +18 -0
- package/blueprints/platform-docker-compose-host/contributions/requirements/platform-docker-compose-host-req-002.json +18 -0
- package/blueprints/platform-docker-compose-host/contributions/requirements/platform-docker-compose-host-req-003.json +18 -0
- package/blueprints/platform-docker-compose-host/contributions/requirements/platform-docker-compose-host-req-004.json +18 -0
- package/blueprints/platform-docker-compose-host/contributions/requirements/platform-docker-compose-host-req-005.json +18 -0
- package/blueprints/platform-docker-compose-host/contributions/requirements/platform-docker-compose-host-req-006.json +18 -0
- package/blueprints/platform-docker-compose-host/contributions/tacs/tac-3901-platform-docker-compose-host-compose-layout.json +26 -0
- package/blueprints/platform-docker-compose-host/contributions/tacs/tac-3902-platform-docker-compose-host-secrets-mount.json +26 -0
- package/blueprints/platform-docker-compose-host/contributions/tacs/tac-3903-platform-docker-compose-host-healthcheck-lint.json +26 -0
- package/blueprints/platform-docker-compose-host/contributions/tacs/tac-3904-platform-docker-compose-host-reverse-proxy-artefact.json +26 -0
- package/blueprints/platform-docker-compose-host/contributions/user-stories/platform-docker-compose-host-us-38101.json +24 -0
- package/blueprints/platform-docker-compose-host/contributions/user-stories/platform-docker-compose-host-us-38102.json +24 -0
- package/blueprints/platform-docker-compose-host/contributions/user-stories/platform-docker-compose-host-us-38103.json +24 -0
- package/blueprints/platform-docker-compose-host/contributions/user-stories/platform-docker-compose-host-us-38104.json +24 -0
- package/blueprints/platform-docker-compose-host/contributions/user-stories/platform-docker-compose-host-us-38105.json +25 -0
- package/blueprints/platform-docker-compose-host/contributions/user-stories/platform-docker-compose-host-us-38106.json +24 -0
- package/blueprints/platform-docker-compose-host/contributions/user-stories/platform-docker-compose-host-us-38107.json +24 -0
- package/blueprints/platform-docker-compose-host/contributions/user-stories/platform-docker-compose-host-us-38108.json +24 -0
- package/blueprints/platform-docker-compose-host/contributions/user-stories/platform-docker-compose-host-us-38109.json +24 -0
- package/blueprints/platform-docker-compose-host/docs/topics.md +71 -0
- package/blueprints/platform-docker-compose-host/guide/platform-docker-compose-host.md +94 -0
- package/blueprints/security-auth-clerk/docs/topics.md +4 -1
- package/blueprints/security-auth-keycloak/docs/topics.md +4 -1
- package/blueprints/security-auth-magic-link/docs/topics.md +4 -1
- package/blueprints/security-auth-oauth2/docs/topics.md +4 -1
- package/blueprints/security-secrets-management/docs/topics.md +4 -1
- package/fixtures/canary-manifest.json +9 -9
- package/guidance/harness-template.md +67 -0
- package/guidance/managed/agent-instructions-block.hash +1 -1
- package/guidance/managed/agent-instructions-block.md +67 -0
- package/package.json +2 -2
- package/rcf/adrs/adr-3801-deploy-hetzner-server-cloud-host-contract.json +13 -0
- package/rcf/adrs/adr-3802-deploy-hetzner-server-snapshot-cadence.json +13 -0
- package/rcf/adrs/adr-3803-deploy-hetzner-server-provisioning-tool.json +13 -0
- package/rcf/adrs/adr-3804-deploy-hetzner-server-hardening-baseline.json +13 -0
- package/rcf/adrs/adr-3901-platform-docker-compose-host-contract.json +13 -0
- package/rcf/adrs/adr-3902-platform-docker-compose-host-reverse-proxy.json +13 -0
- package/rcf/adrs/adr-3903-platform-docker-compose-host-reject-coolify.json +13 -0
- package/rcf/adrs/adr-3904-platform-docker-compose-host-log-driver.json +13 -0
- package/rcf/adrs/adr-4001-edge-cloudflare-tunnel-ingress-bridge-contract.json +13 -0
- package/rcf/adrs/adr-4002-edge-cloudflare-tunnel-connector-runtime.json +13 -0
- package/rcf/adrs/adr-4003-edge-cloudflare-tunnel-hostname-mode.json +13 -0
- package/rcf/code-nodes/cn-410.json +20 -0
- package/rcf/code-nodes/cn-440.json +20 -0
- package/rcf/code-nodes/cn-470.json +19 -0
- package/rcf/code-nodes/cn-500.json +12 -0
- package/rcf/code-nodes/cn-510.json +12 -0
- package/rcf/code-nodes/cn-520.json +14 -0
- package/rcf/code-nodes/cn-521.json +12 -0
- package/rcf/code-nodes/cn-522.json +13 -0
- package/rcf/code-nodes/cn-523.json +12 -0
- package/rcf/code-nodes/cn-524.json +14 -0
- package/rcf/code-nodes/cn-525.json +12 -0
- package/rcf/code-nodes/cn-526.json +14 -0
- package/rcf/fbs/fbs-130.json +23 -0
- package/rcf/fbs/fbs-140.json +23 -0
- package/rcf/fbs/fbs-150.json +22 -0
- package/rcf/fbs/fbs-160.json +15 -0
- package/rcf/fbs/fbs-165.json +15 -0
- package/rcf/fbs/fbs-170.json +16 -0
- package/rcf/fbs/fbs-171.json +16 -0
- package/rcf/fbs/fbs-172.json +15 -0
- package/rcf/fbs/fbs-173.json +17 -0
- package/rcf/fbs/fbs-174.json +17 -0
- package/rcf/requirements/req-110.json +58 -0
- package/rcf/requirements/req-111.json +32 -0
- package/rcf/requirements/req-112.json +42 -0
- package/rcf/requirements/req-113.json +33 -0
- package/rcf/requirements/req-114.json +20 -0
- package/rcf/requirements/req-115.json +38 -0
- package/rcf/requirements/req-120.json +20 -0
- package/rcf/requirements/req-121.json +20 -0
- package/rcf/requirements/req-122.json +20 -0
- package/rcf/requirements/req-123.json +42 -0
- package/rcf/requirements/req-124.json +27 -0
- package/rcf/requirements/req-125.json +20 -0
- package/rcf/requirements/req-130.json +32 -0
- package/rcf/requirements/req-131.json +54 -0
- package/rcf/requirements/req-132.json +27 -0
- package/rcf/requirements/req-133.json +20 -0
- package/rcf/requirements/req-134.json +42 -0
- package/rcf/requirements/req-140.json +149 -0
- package/rcf/requirements/req-145.json +53 -0
- package/rcf/requirements/req-150.json +20 -0
- package/rcf/requirements/req-151.json +85 -0
- package/rcf/requirements/req-152.json +20 -0
- package/rcf/requirements/req-153.json +59 -0
- package/rcf/requirements/req-154.json +44 -0
- package/rcf/tacs/tac-3801-deploy-hetzner-server-provisioner.json +17 -0
- package/rcf/tacs/tac-3802-deploy-hetzner-server-manifest-schema.json +17 -0
- package/rcf/tacs/tac-3803-deploy-hetzner-server-cloud-init-template.json +17 -0
- package/rcf/tacs/tac-3804-deploy-hetzner-server-firewall-shape.json +16 -0
- package/rcf/tacs/tac-3901-platform-docker-compose-host-compose-layout.json +17 -0
- package/rcf/tacs/tac-3902-platform-docker-compose-host-secrets-mount.json +17 -0
- package/rcf/tacs/tac-3903-platform-docker-compose-host-healthcheck-lint.json +17 -0
- package/rcf/tacs/tac-3904-platform-docker-compose-host-reverse-proxy-artefact.json +17 -0
- package/rcf/tacs/tac-4001-edge-cloudflare-tunnel-connector-shape.json +17 -0
- package/rcf/tacs/tac-4002-edge-cloudflare-tunnel-manifest-schema.json +17 -0
- package/rcf/tacs/tac-4003-edge-cloudflare-tunnel-access-binding.json +16 -0
- package/rcf/test-suites/ts-071.json +2 -2
- package/rcf/test-suites/ts-086.json +2 -2
- package/rcf/test-suites/ts-140.json +86 -0
- package/rcf/test-suites/ts-150.json +86 -0
- package/rcf/test-suites/ts-160.json +78 -0
- package/rcf/test-suites/ts-170.json +22 -0
- package/rcf/test-suites/ts-175.json +22 -0
- package/rcf/test-suites/ts-180.json +30 -0
- package/rcf/test-suites/ts-181.json +30 -0
- package/rcf/test-suites/ts-182.json +22 -0
- package/rcf/test-suites/ts-183.json +38 -0
- package/rcf/test-suites/ts-184.json +38 -0
- package/rcf/user-stories/us-11001.json +23 -0
- package/rcf/user-stories/us-11101.json +23 -0
- package/rcf/user-stories/us-11102.json +24 -0
- package/rcf/user-stories/us-11201.json +23 -0
- package/rcf/user-stories/us-11202.json +23 -0
- package/rcf/user-stories/us-11301.json +24 -0
- package/rcf/user-stories/us-11401.json +23 -0
- package/rcf/user-stories/us-11402.json +23 -0
- package/rcf/user-stories/us-11501.json +23 -0
- package/rcf/user-stories/us-12001.json +23 -0
- package/rcf/user-stories/us-12101.json +23 -0
- package/rcf/user-stories/us-12102.json +23 -0
- package/rcf/user-stories/us-12201.json +23 -0
- package/rcf/user-stories/us-12202.json +24 -0
- package/rcf/user-stories/us-12301.json +23 -0
- package/rcf/user-stories/us-12401.json +23 -0
- package/rcf/user-stories/us-12402.json +23 -0
- package/rcf/user-stories/us-12501.json +23 -0
- package/rcf/user-stories/us-13001.json +23 -0
- package/rcf/user-stories/us-13002.json +23 -0
- package/rcf/user-stories/us-13101.json +23 -0
- package/rcf/user-stories/us-13102.json +23 -0
- package/rcf/user-stories/us-13201.json +23 -0
- package/rcf/user-stories/us-13301.json +23 -0
- package/rcf/user-stories/us-13302.json +23 -0
- package/rcf/user-stories/us-13401.json +23 -0
- package/rcf/user-stories/us-14001.json +21 -0
- package/rcf/user-stories/us-14501.json +24 -0
- package/rcf/user-stories/us-15001.json +26 -0
- package/rcf/user-stories/us-15101.json +26 -0
- package/rcf/user-stories/us-15201.json +21 -0
- package/rcf/user-stories/us-15301.json +31 -0
- package/rcf/user-stories/us-15401.json +31 -0
- package/releases/releases.yaml +21 -1
- package/src/blueprint/apply.js +64 -0
- package/src/blueprint/consistency-lint.js +432 -0
- package/src/blueprint/disposition-ledger.js +224 -0
- package/src/blueprint/dispositions.js +44 -0
- package/src/blueprint/index.js +19 -0
- package/src/browser-verify/manifest-writer.js +53 -2
- package/src/browser-verify/pack-runner.js +18 -0
- package/src/cli/blueprint.js +103 -0
- package/src/setup/identity-seed.js +18 -0
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"usId": "edge-cloudflare-tunnel-US-39108",
|
|
3
|
+
"prdId": "PRD-001",
|
|
4
|
+
"reqId": "edge-cloudflare-tunnel-REQ-005",
|
|
5
|
+
"version": "1.0.0",
|
|
6
|
+
"status": "approved",
|
|
7
|
+
"title": "Credentials-file discipline (0o400 host mode, secretRef, not committed, grep-refuse, no leak in event bodies)",
|
|
8
|
+
"asA": "shelf consumer applying edge-cloudflare-tunnel v1.0.0 on a cloudHost",
|
|
9
|
+
"iWant": "the tunnel credentials file to land at mode 0o400 on the host, be referenced from the manifest as a secretRef, never be committed to the applying tree (grep-refuse on the tunnel id and account tag literals), and never appear in any lifecycle event body",
|
|
10
|
+
"soThat": "a leaked credentials file cannot happen through a review-time miss",
|
|
11
|
+
"acceptanceCriteria": [
|
|
12
|
+
{
|
|
13
|
+
"id": "AC-tunnel-credentialsDiscipline",
|
|
14
|
+
"description": "The fixture credentials placeholder documents the 0o400 host mode and secretRef pattern; the manifest references the credentials via a secretRef; the grep-refuse pattern is documented in the guide; every cloudflaredReady, tunnelConnectorUp and ingressRuleReloaded event body captured by the in-process facade carries metadata only, and SIMULATE_EVENT_SECRECY_LEAK inserts the credentials literal into a lifecycle event body and the scan FAILS naming the leaked field.",
|
|
15
|
+
"testable": true,
|
|
16
|
+
"scope": "runtime"
|
|
17
|
+
}
|
|
18
|
+
],
|
|
19
|
+
"tacIds": [
|
|
20
|
+
"TAC-4002-edge-cloudflare-tunnel-manifest-schema"
|
|
21
|
+
],
|
|
22
|
+
"createdAt": "2026-09-08T00:00:00.000Z",
|
|
23
|
+
"updatedAt": "2026-09-08T00:00:00.000Z"
|
|
24
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# edge-cloudflare-tunnel blueprint coordination vocabulary
|
|
2
|
+
|
|
3
|
+
This file is the edge-cloudflare-tunnel half of the cross-blueprint contract. The Phase 1 conflict detector matches scope:global ADR topics by EXACT string equality, and AC ids are unnamespaced by the 0.4.4 grammar. Any blueprint intended to compose with this one must reuse these exact strings and respect these bands.
|
|
4
|
+
|
|
5
|
+
## Global ADR topics this blueprint contributes (exact strings)
|
|
6
|
+
|
|
7
|
+
| Topic string | edge-cloudflare-tunnel contribution | Origin | Composition note |
|
|
8
|
+
|---|---|---|---|
|
|
9
|
+
| `edgeIngressBridge` | ADR-4001-edge-cloudflare-tunnel-ingress-bridge-contract | Minted by this blueprint. Names the wire-shape contract for the project-wide ingress-bridge from a `cloudHost` service to the CF edge; the shipped answer is a Cloudflare Tunnel connector (as a compose service by default when `containerHost` is applied; as a systemd unit for a bare `cloudHost` per the vendor cloudflared as-a-service local-configuration-file docs). | The one project-wide decision on how a service on a `cloudHost` reaches the public internet without opening origin ports. A future non-Cloudflare sibling (Tailscale Funnel, Fly.io proxy) would contribute the same topic string with a different mechanism, forcing a DELIBERATE conflict the operator resolves with a project-level ADR. |
|
|
10
|
+
|
|
11
|
+
The edge-cloudflare-tunnel blueprint claims one global topic (minted here, shipped as the Cloudflare Tunnel connector bridge on a `cloudHost` or `containerHost`). ADR-4002 connector-runtime elicit and ADR-4003 hostname-mode discovered decision do not contribute global topics; a composing blueprint that holds an opinion on either authors its own project-level ADR.
|
|
12
|
+
|
|
13
|
+
Rules for new topics: lower camel case, one concept per topic, no version suffixes. A topic names the decision area, not the chosen answer.
|
|
14
|
+
|
|
15
|
+
## Id number bands (registry bootstrap)
|
|
16
|
+
|
|
17
|
+
This table is maintained shelf-wide across every blueprint's `docs/topics.md`. Rows are recorded at ship, never predicted.
|
|
18
|
+
|
|
19
|
+
| Blueprint | US band | ADR/TAC suffix block | Status | Global topics |
|
|
20
|
+
|---|---|---|---|---|
|
|
21
|
+
| application-spa | 1101-1899 | 2xx | shipped v1.3.0 | `clientRouting`, `theming`, `clientState`, `errorEnvelope`, `authModel` |
|
|
22
|
+
| application-api-rest | 2101-2899 | 3xx | shipped v1.0.0 | `errorEnvelope`, `authModel`, `apiVersioning`, `logging` |
|
|
23
|
+
| security-auth-magic-link | 3101-3899 | 5xx | shipped v1.2.0 | `authModel` |
|
|
24
|
+
| email-smtp-resend | 4101-4899 | 4xx | shipped v1.0.0 | none |
|
|
25
|
+
| hello-panel (walkthrough exemplar) | 4101-4899 | 4xx | doc-reserved; teaching exemplar in `packages/rcf-lite/docs/blueprint-authoring-walkthrough.md`, not shipped as a blueprint directory | `operatorPanel` |
|
|
26
|
+
| persistence-data-sqlite | 5101-5899 | 6xx | shipped v1.0.0 | `persistenceStore`, `migrationDiscipline` |
|
|
27
|
+
| delivery-ci-workflows | 6101-6899 | 7xx | shipped v2.0.0 (renamed from ci-pipeline) | `ciGates`, `strictCoverageGate`, `releaseArtefacts` |
|
|
28
|
+
| observability-essentials | 7101-7899 | 8xx | shipped v2.0.0 | `statusPageContract` |
|
|
29
|
+
| security-secrets-management | 8101-8899 | 9xx | shipped v1.0.1 | `secretsSource` |
|
|
30
|
+
| security-auth-clerk | 9101-9899 | 10xx | shipped v1.0.0 | `authModel` |
|
|
31
|
+
| security-auth-oauth2 | 10101-10899 | 11xx | shipped v1.0.0 | `authModel` |
|
|
32
|
+
| security-auth-keycloak | 11101-11899 | 12xx | shipped v1.0.0 | `authModel` |
|
|
33
|
+
| deploy-cloudflare-workers | 12101-12899 | 13xx | shipped v1.2.0 | `deploymentTarget` |
|
|
34
|
+
| persistence-data-d1 | 13101-13899 | 14xx | shipped v1.0.0 | `persistenceStore`, `migrationDiscipline` |
|
|
35
|
+
| observability-probe-endpoints | 14101-14899 | 15xx | shipped v1.1.0 | `healthProbes`, `readinessSemantics` |
|
|
36
|
+
| observability-logging | 15101-15899 | 16xx | shipped v1.0.0 | `logging` |
|
|
37
|
+
| application-error-handling | 16101-16899 | 17xx | shipped v1.0.0 | `errorHandling` |
|
|
38
|
+
| application-datatable | 17101-17899 | 18xx | shipped v1.0.0 | none |
|
|
39
|
+
| application-charts | 18101-18899 | 19xx | shipped v1.0.0 | none |
|
|
40
|
+
| application-dashboard | 19101-19899 | 20xx | shipped v1.0.0 | none |
|
|
41
|
+
| application-notifications-in-app | 20101-20899 | 21xx | shipped v1.0.0 | none |
|
|
42
|
+
| application-admin-console | 21101-21899 | 22xx | shipped v1.1.0 | `adminConsoleSignInSurface` |
|
|
43
|
+
| application-empty-error-states | 22101-22899 | 23xx | shipped v1.0.0 | none |
|
|
44
|
+
| application-file-upload | 23101-23899 | 24xx | shipped v1.0.0 | none |
|
|
45
|
+
| application-forms-wizard | 24101-24899 | 25xx | shipped v1.0.0 | none |
|
|
46
|
+
| application-account-settings | 25101-25899 | 26xx | shipped v1.0.0 | none |
|
|
47
|
+
| application-onboarding-tour | 26101-26899 | 27xx | shipped v1.0.0 | none |
|
|
48
|
+
| persistence-data-postgres | 27101-27899 | 28xx | shipped v1.0.0 | `persistenceStore`, `migrationDiscipline` |
|
|
49
|
+
| object-storage-s3 | 28101-28899 | 29xx | shipped v1.1.0 | `objectStorageContract` |
|
|
50
|
+
| messaging-queue-cloudflare | 29101-29899 | 30xx | shipped v1.0.0 | `deliverySemantics` |
|
|
51
|
+
| jobs-background | 30101-30899 | 31xx | shipped v1.0.0 | `backgroundJobModel` |
|
|
52
|
+
| platform-cloudflare-kv | 31101-31899 | 32xx | shipped v1.0.0 | `keyValueStoreContract` |
|
|
53
|
+
| platform-cloudflare-cron-triggers | 32101-32899 | 33xx | shipped v1.0.0 | `scheduledTriggerContract` |
|
|
54
|
+
| platform-cloudflare-durable-objects | 33101-33899 | 34xx | shipped v1.0.0 | `strongConsistencyCellContract`, `websocketHubContract` |
|
|
55
|
+
| edge-cloudflare-access | 34101-34899 | 35xx | shipped v1.0.0 | `edgeAuthenticationGate` |
|
|
56
|
+
| edge-cloudflare-turnstile | 35101-35899 | 36xx | shipped v1.0.0 | `humanVerificationGate` |
|
|
57
|
+
| edge-cloudflare-rate-limiting | 36101-36899 | 37xx | shipped v1.0.0 | `edgeThrottleContract` |
|
|
58
|
+
| deploy-hetzner-server | 37101-37899 | 38xx | shipped v1.0.0 | `linuxCloudHostContract`, `snapshotAndBackupCadence` |
|
|
59
|
+
| platform-docker-compose-host | 38101-38899 | 39xx | shipped v1.0.0 | `containerHostContract` |
|
|
60
|
+
| edge-cloudflare-tunnel | 39101-39899 | 40xx | shipped v1.0.0 | `edgeIngressBridge` |
|
|
61
|
+
|
|
62
|
+
US 39101-39108 sit at the LOW end of the 39101-39899 band on purpose (watchpost run-4 lesson). A project-side story mechanically derived from an edge-cloudflare-tunnel REQ id into the number 39108 would collide against the shipped US-39108; band headroom (39109-39899) leaves that space.
|
|
63
|
+
|
|
64
|
+
Edge-cloudflare-tunnel suffixes for this blueprint use the 4001-4003 block, continuing the widening pattern (deploy-hetzner-server 3801-3804 for the T-1 sibling, platform-docker-compose-host 3901-3904 for the T-2 sibling).
|
|
65
|
+
|
|
66
|
+
## Cross-references
|
|
67
|
+
|
|
68
|
+
- `deploy-hetzner-server` (v1.0.0): consumed via `capabilities: [cloudHost]` for the bare systemd-unit connector runtime path.
|
|
69
|
+
- `platform-docker-compose-host` (v1.0.0): consumed via `capabilities: [containerHost]` for the shipped default compose-service connector runtime path.
|
|
70
|
+
- `security-secrets-management` (v1.0.1): the tunnel credentials file source resolves through the applied secrets facade when the secrets blueprint is applied; the guide names the `secretRef` shape.
|
|
71
|
+
- `edge-cloudflare-access` (v1.0.0): optional composition on `capabilities: [zeroTrustGate]`; when applied, ingress rules attach originRequest.access.aud per ADR-4003.
|
|
72
|
+
- `observability-logging`: the applied logging companion consumes every `cloudflaredReady`, `tunnelConnectorUp`, `tunnelConnectorDown`, `ingressRuleReloaded` and `accessGateRefused` event.
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
# Guide: edge-cloudflare-tunnel
|
|
2
|
+
|
|
3
|
+
The edge-cloudflare-tunnel blueprint bridges a service on a `cloudHost`
|
|
4
|
+
or a `containerHost` to the Cloudflare edge through a Cloudflare Tunnel,
|
|
5
|
+
with no public origin ports. This guide walks the shape end to end:
|
|
6
|
+
what the connector looks like, what the manifest looks like, how the
|
|
7
|
+
Access-gated shape composes on top of the public-hostname shape, and
|
|
8
|
+
how the credentials-file discipline stays honest on every reapply.
|
|
9
|
+
|
|
10
|
+
Ratifying spec: `projects/blueprint-library/specs/hetzner-round-7-spec-2026-09-07.md` section 5.3.
|
|
11
|
+
|
|
12
|
+
## When to reach for this blueprint
|
|
13
|
+
|
|
14
|
+
Reach when the applying project needs to expose a service on the public
|
|
15
|
+
internet without opening origin ports on the host and without standing
|
|
16
|
+
up a bespoke reverse proxy in front of the CDN. The tunnel connector
|
|
17
|
+
dials out to the Cloudflare edge and terminates ingress there; the host
|
|
18
|
+
firewall (T-1 deploy-hetzner-server) can stay closed on 80/443 unless a
|
|
19
|
+
reverse proxy is also applied.
|
|
20
|
+
|
|
21
|
+
Do not reach for this blueprint when the applying project runs on
|
|
22
|
+
Cloudflare Workers (`deploy-cloudflare-workers` handles ingress
|
|
23
|
+
directly), when the applying project runs behind a corporate VPN
|
|
24
|
+
(private connectivity has different tools), or when the ingress path
|
|
25
|
+
needs a non-Cloudflare bridge shape (Tailscale Funnel, Fly.io proxy;
|
|
26
|
+
those will mint on operator demand into their own reserved slots).
|
|
27
|
+
|
|
28
|
+
## Connector runtime: when to reach for compose-service vs systemd-unit
|
|
29
|
+
|
|
30
|
+
The connector runtime is elicited via `connector-runtime` per ADR-4002
|
|
31
|
+
with `recommendedDefault: compose-service`.
|
|
32
|
+
|
|
33
|
+
Reach for **compose-service** (the shipped default when `containerHost`
|
|
34
|
+
is applied) when the applying project already runs docker compose on
|
|
35
|
+
the host. The connector ships as another service in the same stack,
|
|
36
|
+
sharing the compose network, the log driver and the restart discipline.
|
|
37
|
+
The T-2 platform-docker-compose-host contract makes this the natural
|
|
38
|
+
home; the connector composes on `containerHost` from T-2.
|
|
39
|
+
|
|
40
|
+
Reach for **systemd-unit** when the host runs bare (only T-1 applied)
|
|
41
|
+
and there is no compose stack to add a service to. The connector runs
|
|
42
|
+
as a systemd unit per the vendor cloudflared as-a-service documented
|
|
43
|
+
systemd unit; the unit file lives at `/etc/systemd/system/cloudflared.service`
|
|
44
|
+
on the host and reads the local configuration file at
|
|
45
|
+
`/etc/cloudflared/<name>.yaml`. Boot ordering plays nicely with journald.
|
|
46
|
+
|
|
47
|
+
The fixture ships both variants under
|
|
48
|
+
`packages/rcf-lite/test/fixtures/hetzner-throwaway-server/cloudflared/{compose-service,systemd-unit}/`
|
|
49
|
+
and both pass `manifest-schema-validate`, `cloudflared-config-lint` and
|
|
50
|
+
`aud-presence-check` on every reviewer boot.
|
|
51
|
+
|
|
52
|
+
## Hostname mode: when to reach for Access-gated vs public-hostname
|
|
53
|
+
|
|
54
|
+
The hostname mode is not elicited. It is DISCOVERED from the applied
|
|
55
|
+
capability set (ADR-4003). When `zeroTrustGate` is applied (i.e.
|
|
56
|
+
edge-cloudflare-access v1.0.0 is applied on the same project), every
|
|
57
|
+
ingress rule attaches `originRequest.access.aud` with the AUD from the
|
|
58
|
+
sidecar. When `zeroTrustGate` is not applied, the block is omitted and
|
|
59
|
+
the tunnel serves in public-hostname mode.
|
|
60
|
+
|
|
61
|
+
Reach for **access-gated** when the service behind the tunnel needs an
|
|
62
|
+
authentication gate at the edge (any request without a valid Access
|
|
63
|
+
JWT is refused before it hits the origin). The Access side of the
|
|
64
|
+
composition is owned by edge-cloudflare-access; edge-cloudflare-tunnel
|
|
65
|
+
only reads the sidecar and attaches the AUD block. See the vendor
|
|
66
|
+
self-hosted-public-app documentation for the full AUD binding shape.
|
|
67
|
+
|
|
68
|
+
Reach for **public-hostname** when the service is deliberately public
|
|
69
|
+
(a marketing page, a documentation site, or a public API where
|
|
70
|
+
authorisation lives at the origin). The tunnel still terminates
|
|
71
|
+
ingress at the CF edge; no origin port is opened; the difference is
|
|
72
|
+
that cloudflared does not check for a JWT before forwarding.
|
|
73
|
+
|
|
74
|
+
Graceful degrade: when Access is not applied, the blueprint still ships
|
|
75
|
+
in public-hostname mode. The `aud-presence-check` probe runs on both
|
|
76
|
+
fixture variants and asserts the shape flips correctly.
|
|
77
|
+
|
|
78
|
+
## Tunnel manifest walkthrough
|
|
79
|
+
|
|
80
|
+
The applying project ships one tunnel manifest per named tunnel at
|
|
81
|
+
`cloudflare/tunnels/<name>.yaml`. A minimal public-hostname manifest:
|
|
82
|
+
|
|
83
|
+
```yaml
|
|
84
|
+
tunnel: 12345678-90ab-4cde-8f12-3456789abcde
|
|
85
|
+
credentialsFile:
|
|
86
|
+
secretRef: hq-estate/CLOUDFLARE_TUNNEL_CREDENTIALS_MY_PROJECT
|
|
87
|
+
ingress:
|
|
88
|
+
- hostname: my-app.example.com
|
|
89
|
+
service: http://web:8080
|
|
90
|
+
- service: http_status:404
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
An access-gated manifest adds one `originRequest.access` block per
|
|
94
|
+
non-catch-all rule:
|
|
95
|
+
|
|
96
|
+
```yaml
|
|
97
|
+
tunnel: 12345678-90ab-4cde-8f12-3456789abcde
|
|
98
|
+
credentialsFile:
|
|
99
|
+
secretRef: hq-estate/CLOUDFLARE_TUNNEL_CREDENTIALS_MY_PROJECT
|
|
100
|
+
ingress:
|
|
101
|
+
- hostname: my-app.example.com
|
|
102
|
+
service: http://web:8080
|
|
103
|
+
originRequest:
|
|
104
|
+
access:
|
|
105
|
+
aud: AUD-example-team
|
|
106
|
+
teamName: my-team
|
|
107
|
+
required: true
|
|
108
|
+
- service: http_status:404
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
The shipped JSON schema at
|
|
112
|
+
`blueprints/edge-cloudflare-tunnel/contributions/probes/tunnel-manifest.schema.json`
|
|
113
|
+
requires: a uuid-shaped `tunnel` id, a `credentialsFile.secretRef`
|
|
114
|
+
reference (never a literal path or inline JSON body), and an ingress
|
|
115
|
+
rules array whose last entry is a catch-all `service: http_status:404`.
|
|
116
|
+
Every ingress service URL must bind to an internal address (a compose
|
|
117
|
+
service name or a loopback interface); binding to `0.0.0.0` or a
|
|
118
|
+
non-loopback numeric IP refuses at apply time.
|
|
119
|
+
|
|
120
|
+
## Credentials rotation pattern
|
|
121
|
+
|
|
122
|
+
The tunnel credentials JSON file lands on the host at mode 0o400 (owner
|
|
123
|
+
read only) and is referenced from the manifest as a
|
|
124
|
+
`credentialsFile.secretRef`. To rotate:
|
|
125
|
+
|
|
126
|
+
1. Regenerate the credentials via `cloudflared tunnel token <name>` or
|
|
127
|
+
the Cloudflare API against the tunnel id.
|
|
128
|
+
2. Update the secret named by the manifest's `secretRef` via
|
|
129
|
+
`security-secrets-management`.
|
|
130
|
+
3. Trigger a reapply on the applying project; the connector picks up
|
|
131
|
+
the new credentials on its next boot cycle.
|
|
132
|
+
|
|
133
|
+
The credentials file MUST NOT be committed to the applying tree; a
|
|
134
|
+
grep across the working tree for the tunnel id and account tag
|
|
135
|
+
literals refuses on any tracked file. Every `cloudflaredReady`,
|
|
136
|
+
`tunnelConnectorUp` and `ingressRuleReloaded` event body carries
|
|
137
|
+
metadata only; the event-secrecy scan refuses on a body that mentions
|
|
138
|
+
the credentials literal.
|
|
139
|
+
|
|
140
|
+
## Composition on the shelf
|
|
141
|
+
|
|
142
|
+
Consumes: `platform-docker-compose-host` (compose-service runtime),
|
|
143
|
+
`deploy-hetzner-server` (bare cloudHost systemd runtime),
|
|
144
|
+
`security-secrets-management` (credentials secretRef). Optionally
|
|
145
|
+
consumes `edge-cloudflare-access` (the Access-gated shape).
|
|
146
|
+
|
|
147
|
+
Provides: `tunnelBridge` capability; new global topic
|
|
148
|
+
`edgeIngressBridge` (ADR-4001 scope global).
|
|
149
|
+
|
|
150
|
+
The `deliver-ci-workflows` shelf blueprint invokes the two account-bound
|
|
151
|
+
probes on a scratch subdomain when the account tokens are present;
|
|
152
|
+
without them the probes record `accountBoundSkipped: true` and the
|
|
153
|
+
aggregate flips to pass per hetzner-round-7-spec section 3.5.
|
|
154
|
+
|
|
155
|
+
## Running the probes
|
|
156
|
+
|
|
157
|
+
Every reviewer boot exercises the three local probes on the fixture:
|
|
158
|
+
|
|
159
|
+
```
|
|
160
|
+
cd packages/rcf-lite/test/fixtures/hetzner-throwaway-server
|
|
161
|
+
node ./run-tunnel-manifest-schema-validate.mjs
|
|
162
|
+
node ./run-cloudflared-config-lint.mjs
|
|
163
|
+
node ./run-aud-presence-check.mjs
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
Every probe writes its report envelope to
|
|
167
|
+
`.rcf/reports/blueprints/edge-cloudflare-tunnel/<probe-name>.json`
|
|
168
|
+
under the repo root.
|
|
169
|
+
|
|
170
|
+
Mutations (fixture-side, one per switch; the probe modules never read
|
|
171
|
+
`SIMULATE_` env vars):
|
|
172
|
+
|
|
173
|
+
- `SIMULATE_MANIFEST_INVALID_TUNNEL_ID=true` on `run-tunnel-manifest-schema-validate.mjs`
|
|
174
|
+
- `SIMULATE_MANIFEST_CREDENTIALS_INLINE=true` on `run-tunnel-manifest-schema-validate.mjs`
|
|
175
|
+
- `SIMULATE_MANIFEST_MISSING_CATCHALL=true` on `run-tunnel-manifest-schema-validate.mjs`
|
|
176
|
+
- `SIMULATE_ORIGIN_PORT_OPEN=true` on `run-tunnel-manifest-schema-validate.mjs`
|
|
177
|
+
- `SIMULATE_EVENT_SECRECY_LEAK=true` on `run-tunnel-manifest-schema-validate.mjs`
|
|
178
|
+
- `SIMULATE_INGRESS_INVALID=true` on `run-cloudflared-config-lint.mjs`
|
|
179
|
+
- `SIMULATE_AUD_DROP=true` on `run-aud-presence-check.mjs`
|
|
180
|
+
|
|
181
|
+
Real-account probes need `CI_HAS_CLOUDFLARE_ACCOUNT=true` and
|
|
182
|
+
`CI_HAS_HETZNER_ACCOUNT=true` (plus `CI_HAS_CLOUDFLARE_ACCESS=true` for
|
|
183
|
+
the gated sub-case per the round-7 Q4 ratification):
|
|
184
|
+
|
|
185
|
+
```
|
|
186
|
+
CI_HAS_CLOUDFLARE_ACCOUNT=true CI_HAS_HETZNER_ACCOUNT=true \
|
|
187
|
+
node ./run-real-account-connector-healthy.mjs
|
|
188
|
+
CI_HAS_CLOUDFLARE_ACCOUNT=true CI_HAS_HETZNER_ACCOUNT=true CI_HAS_CLOUDFLARE_ACCESS=true \
|
|
189
|
+
node ./run-real-account-tunnel-hostname-routes.mjs
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
Without the env vars the probes record `accountBoundSkipped: true` and
|
|
193
|
+
the aggregate flips to pass.
|
|
194
|
+
|
|
195
|
+
## Standards trace
|
|
196
|
+
|
|
197
|
+
- Cloudflare Tunnel overview: https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/
|
|
198
|
+
- Get-started with Tunnel: https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/get-started/
|
|
199
|
+
- cloudflared downloads: https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/downloads/
|
|
200
|
+
- Routing to a tunnel: https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/routing-to-tunnel/
|
|
201
|
+
- Local configuration file: https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/do-more-with-tunnels/local-management/configuration-file/
|
|
202
|
+
- cloudflared as-a-service: https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/install-and-setup/tunnel-guide/local/as-a-service/
|
|
203
|
+
- Self-hosted app in front of a tunnel (Access): https://developers.cloudflare.com/cloudflare-one/applications/configure-apps/self-hosted-public-app/
|
|
204
|
+
- Cloudflare Access policies: https://developers.cloudflare.com/cloudflare-one/policies/access/
|
|
@@ -46,7 +46,7 @@ This table is maintained shelf-wide across every blueprint's `docs/topics.md`. R
|
|
|
46
46
|
| application-account-settings | 25101-25899 | 26xx | shipped v1.0.0 | none |
|
|
47
47
|
| application-onboarding-tour | 26101-26899 | 27xx | shipped v1.0.0 | none |
|
|
48
48
|
| persistence-data-postgres | 27101-27899 | 28xx | shipped v1.0.0 | `persistenceStore`, `migrationDiscipline` |
|
|
49
|
-
| object-storage-s3 | 28101-28899 | 29xx | shipped v1.
|
|
49
|
+
| object-storage-s3 | 28101-28899 | 29xx | shipped v1.1.0 | `objectStorageContract` |
|
|
50
50
|
| messaging-queue-cloudflare | 29101-29899 | 30xx | shipped v1.0.0 | `deliverySemantics` |
|
|
51
51
|
| jobs-background | 30101-30899 | 31xx | shipped v1.0.0 | `backgroundJobModel` |
|
|
52
52
|
| platform-cloudflare-kv | 31101-31899 | 32xx | shipped v1.0.0 | `keyValueStoreContract` |
|
|
@@ -55,6 +55,9 @@ This table is maintained shelf-wide across every blueprint's `docs/topics.md`. R
|
|
|
55
55
|
| edge-cloudflare-access | 34101-34899 | 35xx | shipped v1.0.0 | `edgeAuthenticationGate` |
|
|
56
56
|
| edge-cloudflare-turnstile | 35101-35899 | 36xx | shipped v1.0.0 | `humanVerificationGate` |
|
|
57
57
|
| edge-cloudflare-rate-limiting | 36101-36899 | 37xx | shipped v1.0.0 | `edgeThrottleContract` |
|
|
58
|
+
| deploy-hetzner-server | 37101-37899 | 38xx | shipped v1.0.0 | `linuxCloudHostContract`, `snapshotAndBackupCadence` |
|
|
59
|
+
| platform-docker-compose-host | 38101-38899 | 39xx | shipped v1.0.0 | `containerHostContract` |
|
|
60
|
+
| edge-cloudflare-tunnel | 39101-39899 | 40xx | shipped v1.0.0 | `edgeIngressBridge` |
|
|
58
61
|
|
|
59
62
|
US 35101-35108 sit at the LOW end of the 35101-35899 band on purpose (watchpost run-4 lesson). ADR/TAC suffixes for this blueprint use the 3601-3699 block, continuing the shelf pattern.
|
|
60
63
|
|
|
@@ -42,7 +42,7 @@ This table is maintained shelf-wide across every blueprint's `docs/topics.md`. R
|
|
|
42
42
|
| application-account-settings | 25101-25899 | 26xx | shipped v1.0.0 | none |
|
|
43
43
|
| application-onboarding-tour | 26101-26899 | 27xx | shipped v1.0.0 | none |
|
|
44
44
|
| persistence-data-postgres | 27101-27899 | 28xx | shipped v1.0.0 | `persistenceStore`, `migrationDiscipline` |
|
|
45
|
-
| object-storage-s3 | 28101-28899 | 29xx | shipped v1.
|
|
45
|
+
| object-storage-s3 | 28101-28899 | 29xx | shipped v1.1.0 | `objectStorageContract` |
|
|
46
46
|
| messaging-queue-cloudflare | 29101-29899 | 30xx | shipped v1.0.0 | `deliverySemantics` |
|
|
47
47
|
| jobs-background | 30101-30899 | 31xx | shipped v1.0.0 | `backgroundJobModel` |
|
|
48
48
|
| platform-cloudflare-kv | 31101-31899 | 32xx | shipped v1.0.0 | `keyValueStoreContract` |
|
|
@@ -51,6 +51,9 @@ This table is maintained shelf-wide across every blueprint's `docs/topics.md`. R
|
|
|
51
51
|
| edge-cloudflare-access | 34101-34899 | 35xx | shipped v1.0.0 | `edgeAuthenticationGate` |
|
|
52
52
|
| edge-cloudflare-turnstile | 35101-35899 | 36xx | shipped v1.0.0 | `humanVerificationGate` |
|
|
53
53
|
| edge-cloudflare-rate-limiting | 36101-36899 | 37xx | shipped v1.0.0 | `edgeThrottleContract` |
|
|
54
|
+
| deploy-hetzner-server | 37101-37899 | 38xx | shipped v1.0.0 | `linuxCloudHostContract`, `snapshotAndBackupCadence` |
|
|
55
|
+
| platform-docker-compose-host | 38101-38899 | 39xx | shipped v1.0.0 | `containerHostContract` |
|
|
56
|
+
| edge-cloudflare-tunnel | 39101-39899 | 40xx | shipped v1.0.0 | `edgeIngressBridge` |
|
|
54
57
|
|
|
55
58
|
US 4101-4106 sit at the LOW end of the 4101-4899 band on purpose. A project-side story that mechanically derives from an email-smtp-resend REQ id into the number `4106` (leading `4` + sequence `106`) would collide against email-smtp-resend-US-4106 in this package; the band leaves headroom at the HIGH end (US 4181-4899) so a project's own stories anchored to email-smtp-resend REQs can allocate without conflict. The watchpost run4 lesson applies here too.
|
|
56
59
|
|
|
@@ -43,7 +43,7 @@ This table is maintained shelf-wide across every blueprint's `docs/topics.md`. R
|
|
|
43
43
|
| application-empty-error-states | 22101-22899 | 23xx | shipped v1.0.0 | none |
|
|
44
44
|
| application-file-upload | 23101-23899 | 24xx | shipped v1.0.0 | none |
|
|
45
45
|
| persistence-data-postgres | 27101-27899 | 28xx | shipped v1.0.0 | `persistenceStore`, `migrationDiscipline` |
|
|
46
|
-
| object-storage-s3 | 28101-28899 | 29xx | shipped v1.
|
|
46
|
+
| object-storage-s3 | 28101-28899 | 29xx | shipped v1.1.0 | `objectStorageContract` |
|
|
47
47
|
| messaging-queue-cloudflare | 29101-29899 | 30xx | shipped v1.0.0 | `deliverySemantics` |
|
|
48
48
|
| jobs-background | 30101-30899 | 31xx | shipped v1.0.0 | `backgroundJobModel` |
|
|
49
49
|
| platform-cloudflare-kv | 31101-31899 | 32xx | shipped v1.0.0 | `keyValueStoreContract` |
|
|
@@ -52,6 +52,9 @@ This table is maintained shelf-wide across every blueprint's `docs/topics.md`. R
|
|
|
52
52
|
| edge-cloudflare-access | 34101-34899 | 35xx | shipped v1.0.0 | `edgeAuthenticationGate` |
|
|
53
53
|
| edge-cloudflare-turnstile | 35101-35899 | 36xx | shipped v1.0.0 | `humanVerificationGate` |
|
|
54
54
|
| edge-cloudflare-rate-limiting | 36101-36899 | 37xx | shipped v1.0.0 | `edgeThrottleContract` |
|
|
55
|
+
| deploy-hetzner-server | 37101-37899 | 38xx | shipped v1.0.0 | `linuxCloudHostContract`, `snapshotAndBackupCadence` |
|
|
56
|
+
| platform-docker-compose-host | 38101-38899 | 39xx | shipped v1.0.0 | `containerHostContract` |
|
|
57
|
+
| edge-cloudflare-tunnel | 39101-39899 | 40xx | shipped v1.0.0 | `edgeIngressBridge` |
|
|
55
58
|
|
|
56
59
|
US 30101-30109 sit at the LOW end of the 30101-30899 band on purpose (watchpost run-4 lesson). A project-side story mechanically derived from a jobs-background REQ id into the number 30110 would collide against a shipped US-30110; band headroom (30110-30899) leaves that space.
|
|
57
60
|
|
|
@@ -1,5 +1,24 @@
|
|
|
1
1
|
# messaging-queue-cloudflare changelog
|
|
2
2
|
|
|
3
|
+
## 1.0.2 - 2026-09-08
|
|
4
|
+
|
|
5
|
+
H-2 follow-up (`w-2026-09-08-dave-017`, addendum item 6 fixture defect): the real-account queue probe now self-provisions its own throwaway Queue + consumer Worker + telemetry KV namespace, closing the second-tier undeclared-env skip HQ hit at the real-account gate on 2026-09-08 (`REAL RUN: PARTIAL`, `MERGE DECISION: HOLD`). No shipped-code capability change.
|
|
6
|
+
|
|
7
|
+
- `real-account-concurrency-smoke.mjs` rewritten against a new self-provisioning fixture shim at `packages/rcf-lite/test/fixtures/cf-platform/h2-cf-queue-real-account-shim.mjs`. AC-29108-2 requires a real consumer to process the published messages ("the consumer processes them concurrently up to the documented 250-invocation cap"), so the shim mints a scratch Cloudflare Queue under `h2-cf-probe-integrity-scratch-q-`, a scratch KV namespace for consumer telemetry under `h2-cf-probe-integrity-scratch-kv-tel-`, and a throwaway consumer Worker under `h2-cf-probe-integrity-scratch-w-` bound to the queue (consumer) with `RCF_TEST_QUEUE` (shipped queue producer binding name matching `packages/rcf-lite/test/fixtures/infra-s3-and-queue/wrangler.toml`) + `RCF_TEST_TELEMETRY_KV` bindings. NO workers.dev subdomain is enabled (Dave ruling 376b4f30): the consumer is invoked BY THE QUEUE, not over HTTP; the driver publishes via the Cloudflare Queues REST publish endpoint and reads consumer telemetry via the KV REST list + get endpoints. The consumer Worker's source is a plain module (`h2-cf-queue-consumer-worker.mjs`); its `queue()` handler records one telemetry entry per invocation (start / end timestamps + batchSize) to the bound telemetry KV namespace; the driver computes `maxConcurrent` from an interval-overlap analysis on those timestamps.
|
|
8
|
+
- Declared env for a real-account run is now `CI_HAS_CLOUDFLARE_ACCOUNT` + `CF_ACCOUNT_ID` + `CF_API_TOKEN` (optional `CF_API_BASE_URL` test override; optional `CF_QUEUE_MESSAGE_COUNT` per section 3.5). The `CF_QUEUE_WORKER_URL` and `CF_QUEUE_NAME` second-tier gates are removed; the fixture provides them itself. Every skip-causing env var enumerated in `report.extra.envDeclared` on the probe result and mirrored in the shim's `DECLARED_ENV` export.
|
|
9
|
+
- Teardown deletes the consumer Worker first (so the queue has no active consumer at delete time), then the Queue, then the telemetry KV namespace, all by EXACT id / EXACT name against the mint record with three independent prefix guards per resource. `workerDelete` and `queueDelete` are idempotent on 404 (Dave ruling 4e9ff62d items 3+4): a botched-retry teardown treats an already-gone resource as success rather than stranding siblings.
|
|
10
|
+
- Separate crash-recovery `sweepOrphans` code path filters over the account by the frozen throwaway prefix constants and deletes each match by exact identity; the sweep is structurally unable to select a non-prefixed name. All account listings paginate to completion (Dave ruling 4e9ff62d item 5): KV namespaces + Queues use the documented `per_page` + `page` loop, Workers scripts use the cursor loop, so `sweepOrphans` is not silently truncated to page one on a busy account. Dedicated sweep-safety test at `packages/rcf-lite/test/fixtures/cf-platform/test/h2-cf-sweep-safety.test.mjs` seeds the mock account with the ten live production Worker script names on the operator account plus mid-string-prefix decoys AND a 250-per-type multi-page cover, and asserts sweep selects zero of them.
|
|
11
|
+
- Queue consumer-attach body sends `type: "worker"` (Dave ruling 4e9ff62d item 1: survives CF schema tightening on the discriminated attach union) and omits `dead_letter_queue` entirely rather than sending an explicit `null` (item 2).
|
|
12
|
+
- Local proof harness (`packages/rcf-lite/test/fixtures/cf-platform/test/mock-cf-api-server.mjs`) is a zero-dep in-process mock of the Cloudflare REST contract, not the wire. **The local run exercises OUR lifecycle logic against a mock of Cloudflare's contract; the real-account gate is the only surface that proves the wire format.** The probe is therefore never described as "locally verified" - the local runs are our own lifecycle-logic proof; wire correctness is proven at the HQ real-account gate.
|
|
13
|
+
|
|
14
|
+
## 1.0.1 - 2026-09-08
|
|
15
|
+
|
|
16
|
+
H-2 hardening train (`h2-cf-platform-probe-integrity`): probe-integrity patch. No capability change.
|
|
17
|
+
|
|
18
|
+
- Replaced the `accountBoundSkipped: true` pass-stub in `real-account-concurrency-smoke.mjs` with a real 500-message concurrency driver against a live Queues binding on a deployed Worker. When `CI_HAS_CLOUDFLARE_ACCOUNT` is set with `CF_QUEUE_WORKER_URL` and `CF_QUEUE_NAME`, the driver publishes 500 messages through the producer facade in 10 concurrent 50-message batches, polls consumer telemetry via `/stats`, and asserts `drained`, `withinCap` and `observedConcurrency > 1` against Cloudflare's documented push-invocation cap (250). The env-absent branch keeps the pass-with-skip shape. Locally proven against `wrangler dev --local` end-to-end (500/500 messages in 583 ms; local queue serialises so the concurrency assertion FAIL tail is the expected local-proof outcome; on real Cloudflare push consumers the assertion passes at HQ gate time).
|
|
19
|
+
- Re-verified the Cloudflare Queues limits URL (`https://developers.cloudflare.com/queues/platform/limits/`) returns `HTTP/2 200`; recorded in the H-2 PR provenance (2026-09-08T13:38:07Z).
|
|
20
|
+
- Extended the fixture Worker at `packages/rcf-lite/test/fixtures/infra-s3-and-queue/src/worker.mjs` with consumer telemetry and `/publish-batch`, `/stats` and `/reset` endpoints; added `wrangler ^4.0.0` as devDep on the fixture package.
|
|
21
|
+
|
|
3
22
|
## 1.0.0 - 2026-09-06
|
|
4
23
|
|
|
5
24
|
Initial release. Directed producer-to-consumer worklist queue on Cloudflare Queues; first shipped adapter with the reserved `messaging-queue-postgres` sibling (Baz decision 7) named beside it in the section 6a capability table. Accessed through a producer facade that is the sole reader of the Cloudflare Queues binding (`env.RCF_TEST_QUEUE` in the fixture). Landed via the infra round 5 spec (ratified 2026-09-06) as track T-3.
|
|
@@ -60,7 +60,7 @@ Each probe is a Node module under `contributions/probes/` exporting the round-5
|
|
|
60
60
|
| `publish-to-delivery` | AC-29102-1, AC-29102-2, AC-29105-1, AC-29108-1 | 5 messages round-trip body byte-equal with stable message-ids and producer-supplied trace-ids preserved; per-message ack; wrangler-dev-equivalent seam. | false |
|
|
61
61
|
| `retry-and-dlq` | AC-29103-1, AC-29104-1 | Consumer returning `retry` observes same stable message-id with attempts 1..max_retries; DLQ landing fires `messageDeadLettered` at `max_retries + 1`; DLQ contents body byte-equal via the DLQ inspector helper. | false |
|
|
62
62
|
| `event-secrecy` | AC-29106-1 | Every event record carries only the whitelist (event, ts, messageId, queueName, attempts); no PII fixture text on JSON grep. | false |
|
|
63
|
-
| `real-account-concurrency-smoke` | AC-29108-2 |
|
|
63
|
+
| `real-account-concurrency-smoke` | AC-29108-2 | Self-provisioning (v1.0.2): the fixture shim (`packages/rcf-lite/test/fixtures/cf-platform/h2-cf-queue-real-account-shim.mjs`) mints a scratch Cloudflare Queue under the H-2 prefix `h2-cf-probe-integrity-scratch-q-`, a scratch KV namespace for consumer telemetry under `h2-cf-probe-integrity-scratch-kv-tel-`, and a throwaway consumer Worker under `h2-cf-probe-integrity-scratch-w-` bound to the queue (consumer) with `RCF_TEST_QUEUE` (shipped queue binding name) + `RCF_TEST_TELEMETRY_KV` bindings. The Worker has NO fetch surface and NO workers.dev subdomain is enabled (Dave ruling 376b4f30): the consumer is invoked BY THE QUEUE, not over HTTP. Driver publishes 500 messages in 10 concurrent 50-message batches via the Cloudflare Queues REST publish endpoint, polls the telemetry KV namespace via the KV REST list + get endpoints until drained, and asserts `totalConsumed === published` and `1 < maxConcurrent <= 250` per https://developers.cloudflare.com/queues/platform/limits/. Teardown deletes Worker, Queue and telemetry KV namespace on exit; the shim's separate `sweepOrphans` path lists over the account with full pagination (Dave ruling 4e9ff62d item 5) and deletes any prefixed residue after a mid-run crash. **The local proof exercises OUR lifecycle logic against a mock of Cloudflare's contract; the real-account gate is the only surface that proves the wire format.** Without `CI_HAS_CLOUDFLARE_ACCOUNT` records `accountBoundSkipped: true`. | true |
|
|
64
64
|
|
|
65
65
|
## Anatomy
|
|
66
66
|
|
|
@@ -111,7 +111,7 @@ Two live paths are unproven at v1.0.0 and are recorded per AC below so the gate
|
|
|
111
111
|
- **AC-29105-1** (batch consume: 5 messages in one batch, per-message ack semantics under `max_batch_size = 10`): proven against the in-memory realisation of the binding shape (probe `publish-to-delivery`, verdict pass); live Queues `max_batch_size` / `max_batch_timeout` behaviour on the [[queues.consumers]] block unproven pending a reviewer `wrangler dev` run or the accountBound smoke.
|
|
112
112
|
- **AC-29106-1** (metadata-only event whitelist; no PII body / header value / consumer context leaks): proven end-to-end against the in-memory realisation (probe `event-secrecy`, verdict pass; the whitelist is code-enforced in `src/event-sink.mjs`, independent of transport); live-Queues run does not change the sink code path, so this AC has no live-only gap.
|
|
113
113
|
- **AC-29108-1** (wrangler-dev-equivalent seam round-trip): proven end-to-end against the in-memory realisation of the binding shape (probe `publish-to-delivery`, verdict pass); a live `wrangler dev` process was not driven in this pass. Rationale: SDR-3-a on US-29107 makes the wrangler-dev-equivalent seam the shipped local seam because Cloudflare Queues does not support consumer concurrency under `wrangler dev` and does not support `wrangler dev --remote` per the local-development doc, so a live-wrangler run adds observability (a real process on port 8787) but does not add facade-contract certainty over the in-memory realisation. The gate reviewer drives one live `wrangler dev` run in their own scratch to close the observability gap.
|
|
114
|
-
- **AC-29108-2** (real-account concurrency smoke: 500 messages, consumer concurrency up to 250):
|
|
114
|
+
- **AC-29108-2** (real-account concurrency smoke: 500 messages, consumer concurrency up to 250): as of v1.0.2 the probe SELF-PROVISIONS the throwaway Queue + consumer Worker + telemetry KV namespace under the H-2 prefixes and requires no hand-provisioned CI infrastructure (`w-2026-09-08-dave-017`). Declared env for a live run: `CI_HAS_CLOUDFLARE_ACCOUNT` + `CF_ACCOUNT_ID` + `CF_API_TOKEN`. Without `CI_HAS_CLOUDFLARE_ACCOUNT` the probe records `accountBoundSkipped: true` per spec section 3.5 and the per-blueprint report carries `aggregateVerdict: pass` on the skipped shape. **The local proof harness under `packages/rcf-lite/test/fixtures/cf-platform/test/` is a mock of Cloudflare's REST contract, not the wire; the local runs exercise OUR lifecycle logic against that mock, and the real-account gate is the only surface that proves the wire format.**
|
|
115
115
|
|
|
116
116
|
## Other limitations (not mechanism-reach gaps)
|
|
117
117
|
|