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,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"createdAt": "2026-09-08T03:21:16.415Z",
|
|
3
|
+
"updatedAt": "2026-09-08T03:21:16.415Z",
|
|
4
|
+
"usId": "US-13001",
|
|
5
|
+
"prdId": "PRD-001",
|
|
6
|
+
"reqId": "REQ-130",
|
|
7
|
+
"version": "0.1.0",
|
|
8
|
+
"status": "draft",
|
|
9
|
+
"title": "T-3 cloudflared connector install shape switches on applied containerHost (compose-service default; systemd-unit fallback for bare cloudHost)",
|
|
10
|
+
"asA": "shelf consumer applying edge-cloudflare-tunnel v1.0.0 alongside deploy-hetzner-server (and optionally platform-docker-compose-host)",
|
|
11
|
+
"iWant": "the cloudflared connector to install as a compose service when the containerHost capability is applied and as a systemd unit when the host runs bare",
|
|
12
|
+
"soThat": "the runtime shape matches the applied platform rather than forcing a container onto a bare host or a bare service into a compose-managed stack",
|
|
13
|
+
"acceptanceCriteria": [
|
|
14
|
+
{
|
|
15
|
+
"id": "AC-13001-1",
|
|
16
|
+
"description": "The blueprint declares its connector runtime via ADR-4002 with elicited enum {compose-service, systemd-unit} and recommendedDefault compose-service. The shared fixture ships both variants under packages/rcf-lite/test/fixtures/hetzner-throwaway-server/cloudflared/{compose-service,systemd-unit}/; the compose-service variant defines a cloudflared service alongside the T-2 web and caddy services on the same web-net network with restart unless-stopped, no host ports and a healthcheck; the systemd-unit variant ships a cloudflared.service unit file per the vendor local-configuration-file docs.",
|
|
17
|
+
"testable": true
|
|
18
|
+
}
|
|
19
|
+
],
|
|
20
|
+
"tacIds": [
|
|
21
|
+
"TAC-4001-edge-cloudflare-tunnel-connector-shape"
|
|
22
|
+
]
|
|
23
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"createdAt": "2026-09-08T03:21:16.655Z",
|
|
3
|
+
"updatedAt": "2026-09-08T03:21:16.655Z",
|
|
4
|
+
"usId": "US-13002",
|
|
5
|
+
"prdId": "PRD-001",
|
|
6
|
+
"reqId": "REQ-130",
|
|
7
|
+
"version": "0.1.0",
|
|
8
|
+
"status": "draft",
|
|
9
|
+
"title": "T-3 cloudflared connector reports healthy on boot (tunnelConnectorUp fires with connector id, region, version)",
|
|
10
|
+
"asA": "shelf consumer applying edge-cloudflare-tunnel v1.0.0 on a cloudHost",
|
|
11
|
+
"iWant": "the connector to emit a tunnelConnectorUp event on boot with connector id, region and version metadata (metadata only)",
|
|
12
|
+
"soThat": "the observability sink proves the tunnel is up without a shell into the host",
|
|
13
|
+
"acceptanceCriteria": [
|
|
14
|
+
{
|
|
15
|
+
"id": "AC-13002-1",
|
|
16
|
+
"description": "real-account-connector-healthy probe declares accountBound true (on CI_HAS_CLOUDFLARE_ACCOUNT AND CI_HAS_HETZNER_ACCOUNT) and records accountBoundSkipped when either env var is unset. When both are set the probe drives cloudflared tunnel info against the fixture tunnel and asserts at least one healthy connector plus a tunnelConnectorUp event with connector id, region and version.",
|
|
17
|
+
"testable": true
|
|
18
|
+
}
|
|
19
|
+
],
|
|
20
|
+
"tacIds": [
|
|
21
|
+
"TAC-4001-edge-cloudflare-tunnel-connector-shape"
|
|
22
|
+
]
|
|
23
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"createdAt": "2026-09-08T03:21:16.885Z",
|
|
3
|
+
"updatedAt": "2026-09-08T03:21:16.885Z",
|
|
4
|
+
"usId": "US-13101",
|
|
5
|
+
"prdId": "PRD-001",
|
|
6
|
+
"reqId": "REQ-131",
|
|
7
|
+
"version": "0.1.0",
|
|
8
|
+
"status": "draft",
|
|
9
|
+
"title": "T-3 tunnel manifest schema at cloudflare/tunnels/<name>.yaml validates on shape (tunnel id, credentials secretRef, ingress rules with catch-all 404)",
|
|
10
|
+
"asA": "shelf consumer applying edge-cloudflare-tunnel v1.0.0",
|
|
11
|
+
"iWant": "the tunnel manifest at cloudflare/tunnels/<name>.yaml to validate against a shipped JSON schema (uuid-shaped tunnel id, secretRef credentials, ingress rules with a mandatory catch-all http_status 404)",
|
|
12
|
+
"soThat": "a mis-shaped manifest is caught at apply-time rather than at first inbound request",
|
|
13
|
+
"acceptanceCriteria": [
|
|
14
|
+
{
|
|
15
|
+
"id": "AC-13101-1",
|
|
16
|
+
"description": "manifest-schema-validate probe passes on the canonical fixture at cloudflared/*/cloudflare/tunnels/probe.yaml and fails when the fixture is mutated: SIMULATE_MANIFEST_INVALID_TUNNEL_ID rewrites the tunnel-id field to a non-uuid literal; SIMULATE_MANIFEST_CREDENTIALS_INLINE writes the credentials JSON body inline (bypassing the secretRef); SIMULATE_MANIFEST_MISSING_CATCHALL removes the catch-all rule. Each mutation FAILS naming the offending field.",
|
|
17
|
+
"testable": true
|
|
18
|
+
}
|
|
19
|
+
],
|
|
20
|
+
"tacIds": [
|
|
21
|
+
"TAC-4002-edge-cloudflare-tunnel-manifest-schema"
|
|
22
|
+
]
|
|
23
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"createdAt": "2026-09-08T03:21:17.114Z",
|
|
3
|
+
"updatedAt": "2026-09-08T03:21:17.114Z",
|
|
4
|
+
"usId": "US-13102",
|
|
5
|
+
"prdId": "PRD-001",
|
|
6
|
+
"reqId": "REQ-131",
|
|
7
|
+
"version": "0.1.0",
|
|
8
|
+
"status": "draft",
|
|
9
|
+
"title": "T-3 ingress rules route the public hostname to an internal service URL and cloudflared config lint exits 0",
|
|
10
|
+
"asA": "shelf consumer applying edge-cloudflare-tunnel v1.0.0 with a compose service listening on an internal port",
|
|
11
|
+
"iWant": "the ingress rule mapping the public hostname to the internal service URL (e.g. http://web:8080) to pass cloudflared tunnel ingress validate cleanly",
|
|
12
|
+
"soThat": "a rule that would fail at boot fails at gate instead",
|
|
13
|
+
"acceptanceCriteria": [
|
|
14
|
+
{
|
|
15
|
+
"id": "AC-13102-1",
|
|
16
|
+
"description": "cloudflared-config-lint probe runs cloudflared tunnel ingress validate through the cloudflare/cloudflared container image (when the binary is not on PATH) against the fixture manifest and exits 0 on the canonical fixture; SIMULATE_INGRESS_INVALID rewrites the ingress rule service URL to an unresolvable scheme and the probe FAILS naming the offending line.",
|
|
17
|
+
"testable": true
|
|
18
|
+
}
|
|
19
|
+
],
|
|
20
|
+
"tacIds": [
|
|
21
|
+
"TAC-4002-edge-cloudflare-tunnel-manifest-schema"
|
|
22
|
+
]
|
|
23
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"createdAt": "2026-09-08T03:21:17.345Z",
|
|
3
|
+
"updatedAt": "2026-09-08T03:21:17.345Z",
|
|
4
|
+
"usId": "US-13201",
|
|
5
|
+
"prdId": "PRD-001",
|
|
6
|
+
"reqId": "REQ-132",
|
|
7
|
+
"version": "0.1.0",
|
|
8
|
+
"status": "draft",
|
|
9
|
+
"title": "T-3 no public origin ports on the host (firewall stays 22 plus 80/443-only-when-reverse-proxy; manifest refuses an origin-port request)",
|
|
10
|
+
"asA": "shelf consumer applying edge-cloudflare-tunnel v1.0.0 without a reverse proxy",
|
|
11
|
+
"iWant": "the host firewall to stay closed on 80/443 and the manifest schema to refuse any ingress rule that binds to a host public port rather than an internal address",
|
|
12
|
+
"soThat": "the tunnel remains the only path from the edge to the origin",
|
|
13
|
+
"acceptanceCriteria": [
|
|
14
|
+
{
|
|
15
|
+
"id": "AC-13201-1",
|
|
16
|
+
"description": "manifest-schema-validate refuses ingress rules whose service URL binds to a host public interface. SIMULATE_ORIGIN_PORT_OPEN rewrites the ingress rule service URL to http://0.0.0.0:80 (or a host-relative port); the probe FAILS naming the leak. The T-1 firewall on the ci-throwaway manifest stays 22 open plus 80/443 open only when a reverse proxy is applied; a T-3-only project declares no 80/443 rule.",
|
|
17
|
+
"testable": true
|
|
18
|
+
}
|
|
19
|
+
],
|
|
20
|
+
"tacIds": [
|
|
21
|
+
"TAC-4002-edge-cloudflare-tunnel-manifest-schema"
|
|
22
|
+
]
|
|
23
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"createdAt": "2026-09-08T03:21:17.575Z",
|
|
3
|
+
"updatedAt": "2026-09-08T03:21:17.575Z",
|
|
4
|
+
"usId": "US-13301",
|
|
5
|
+
"prdId": "PRD-001",
|
|
6
|
+
"reqId": "REQ-133",
|
|
7
|
+
"version": "0.1.0",
|
|
8
|
+
"status": "draft",
|
|
9
|
+
"title": "T-3 Access-gated composition: when zeroTrustGate is applied, ingress rules attach originRequest.access.aud",
|
|
10
|
+
"asA": "shelf consumer applying edge-cloudflare-tunnel v1.0.0 alongside edge-cloudflare-access v1.0.0",
|
|
11
|
+
"iWant": "every ingress rule to attach an originRequest.access block naming the Access AUD",
|
|
12
|
+
"soThat": "cloudflared refuses at the edge any request that arrives without a valid Access JWT for that AUD",
|
|
13
|
+
"acceptanceCriteria": [
|
|
14
|
+
{
|
|
15
|
+
"id": "AC-13301-1",
|
|
16
|
+
"description": "aud-presence-check probe passes on BOTH fixture variants: on the access-gated variant every ingress rule attaches originRequest.access.aud read from the sidecar rcf/blueprints/edge-cloudflare-tunnel.applied.json (appliedCapabilities includes zeroTrustGate); on the public-hostname variant the originRequest.access block is absent from every rule (appliedCapabilities excludes zeroTrustGate). The shape flip is a pure function of the sidecar contents.",
|
|
17
|
+
"testable": true
|
|
18
|
+
}
|
|
19
|
+
],
|
|
20
|
+
"tacIds": [
|
|
21
|
+
"TAC-4003-edge-cloudflare-tunnel-access-binding"
|
|
22
|
+
]
|
|
23
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"createdAt": "2026-09-08T03:21:17.805Z",
|
|
3
|
+
"updatedAt": "2026-09-08T03:21:17.805Z",
|
|
4
|
+
"usId": "US-13302",
|
|
5
|
+
"prdId": "PRD-001",
|
|
6
|
+
"reqId": "REQ-133",
|
|
7
|
+
"version": "0.1.0",
|
|
8
|
+
"status": "draft",
|
|
9
|
+
"title": "T-3 shape does not silently degrade to open ingress when zeroTrustGate drifts absent on a project that intended the gated shape (aud-presence-check refuses)",
|
|
10
|
+
"asA": "shelf consumer who applied edge-cloudflare-tunnel v1.0.0 with zeroTrustGate on",
|
|
11
|
+
"iWant": "a probe that asserts the ingress rule keeps its originRequest.access.aud block on every reapply and refuses if the block drifts absent",
|
|
12
|
+
"soThat": "a silent config drift to open ingress is caught at gate rather than at first probing",
|
|
13
|
+
"acceptanceCriteria": [
|
|
14
|
+
{
|
|
15
|
+
"id": "AC-13302-1",
|
|
16
|
+
"description": "aud-presence-check refuses when the gated variant drifts to open ingress. SIMULATE_AUD_DROP rewrites the gated fixture ingress to remove the originRequest.access block; the probe FAILS with a defensive-against-silent-degradation finding naming the affected rule and the missing AUD value.",
|
|
17
|
+
"testable": true
|
|
18
|
+
}
|
|
19
|
+
],
|
|
20
|
+
"tacIds": [
|
|
21
|
+
"TAC-4003-edge-cloudflare-tunnel-access-binding"
|
|
22
|
+
]
|
|
23
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"createdAt": "2026-09-08T03:21:18.038Z",
|
|
3
|
+
"updatedAt": "2026-09-08T03:21:18.038Z",
|
|
4
|
+
"usId": "US-13401",
|
|
5
|
+
"prdId": "PRD-001",
|
|
6
|
+
"reqId": "REQ-134",
|
|
7
|
+
"version": "0.1.0",
|
|
8
|
+
"status": "draft",
|
|
9
|
+
"title": "T-3 credentials-file discipline (JSON at mode 0o400, referenced via secretRef, not committed, grep-refuses on the literal, no leak in event bodies)",
|
|
10
|
+
"asA": "shelf consumer applying edge-cloudflare-tunnel v1.0.0 on a cloudHost",
|
|
11
|
+
"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 project tree (grep-refuse on the tunnel id and account tag literals), and never appear in any lifecycle event body",
|
|
12
|
+
"soThat": "a leaked credentials file cannot happen through a review-time miss",
|
|
13
|
+
"acceptanceCriteria": [
|
|
14
|
+
{
|
|
15
|
+
"id": "AC-13401-1",
|
|
16
|
+
"description": "The fixture credentials placeholder at cloudflared/credentials/probe.json.example carries a note that a real credentials file must land at mode 0o400 on the host; the manifest references it 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.",
|
|
17
|
+
"testable": true
|
|
18
|
+
}
|
|
19
|
+
],
|
|
20
|
+
"tacIds": [
|
|
21
|
+
"TAC-4002-edge-cloudflare-tunnel-manifest-schema"
|
|
22
|
+
]
|
|
23
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"createdAt": "2026-09-08T09:02:48.558Z",
|
|
3
|
+
"updatedAt": "2026-09-08T09:05:33.736Z",
|
|
4
|
+
"description": "As a shelf consumer applying object-storage-s3 v1.1.0 on a Hetzner Object Storage bucket, I want an endpoint-shape helper that composes the vendor-documented endpoint pattern from an elicited bucket and location code, and a probe that proves the composed endpoint round-trips a byte-equal put/get/delete on either a real Hetzner Object Storage bucket (when CI_HAS_HETZNER_OBJECT_STORAGE is set) or records accountBoundSkipped true when not, so the R2 real-account smoke and the MinIO local-emulator flow both stay unaffected while the shelf gains a fourth provider value alongside R2, AWS, MinIO. Chain: HQ round-7 follow-up adapter block per HQ chain-block ruling 2026-09-08.",
|
|
5
|
+
"usId": "US-14001",
|
|
6
|
+
"prdId": "PRD-001",
|
|
7
|
+
"reqId": "REQ-140",
|
|
8
|
+
"version": "0.1.0",
|
|
9
|
+
"status": "draft",
|
|
10
|
+
"title": "T-follow-up adapter object-storage-s3 v1.1.0 Hetzner: endpoint-shape helper composes <bucket>.<location>.your-objectstorage.com; new probe hetzner-object-storage-round-trip drives put/get/delete against the composed endpoint on the extended fixture; accountBound gated on CI_HAS_HETZNER_OBJECT_STORAGE",
|
|
11
|
+
"asA": "shelf consumer applying object-storage-s3 v1.1.0 on a Hetzner Object Storage bucket (fsn1, hel1 or nbg1 location)",
|
|
12
|
+
"iWant": "an endpoint-shape helper that composes <bucket>.<location>.your-objectstorage.com from an elicited bucket and location per the Hetzner storage overview, plus a new Node-only probe hetzner-object-storage-round-trip.mjs driven from the extended infra-s3-and-queue fixture that either round-trips a byte-equal put/get/delete against a real Hetzner Object Storage bucket when CI_HAS_HETZNER_OBJECT_STORAGE is set or records accountBoundSkipped true when unset",
|
|
13
|
+
"soThat": "the shelf gains a fourth provider value alongside R2, AWS and MinIO with no runtime dependency added to the applying project, no facade re-shape, and no regression to the shipped MinIO local-emulator or R2 real-account paths",
|
|
14
|
+
"acceptanceCriteria": [
|
|
15
|
+
{
|
|
16
|
+
"id": "AC-14001-1",
|
|
17
|
+
"description": "Given the extended fixture packages/rcf-lite/test/fixtures/infra-s3-and-queue/ carrying hetzner-endpoint.mjs and run-hetzner-object-storage-round-trip.mjs, when node blueprints/object-storage-s3/contributions/probes/run-hetzner-object-storage-round-trip.mjs runs, then either (a) with CI_HAS_HETZNER_OBJECT_STORAGE set alongside HETZNER_OBJECT_STORAGE_ACCESS_KEY_ID, HETZNER_OBJECT_STORAGE_SECRET_ACCESS_KEY, HETZNER_OBJECT_STORAGE_BUCKET and HETZNER_OBJECT_STORAGE_LOCATION the composed endpoint is https://<bucket>.<location>.your-objectstorage.com per the Hetzner storage overview and put/get/delete round-trips a byte-equal 1 KiB payload with teardown scrubbing the object; or (b) without CI_HAS_HETZNER_OBJECT_STORAGE the probe records accountBoundSkipped true and the aggregate flips to pass per spec section 3.5. The endpoint-shape helper is the sole composer of the vendor pattern; SIMULATE_HETZNER_ENDPOINT_MISSHAPEN true composes an invalid endpoint via the fixture-side shim (INPUT-side mutation) and the probe FAILS naming the missing subdomain. Anchors the label AC-hetznerObjectStorage-endpointRoundTrip on the blueprint side.",
|
|
18
|
+
"testable": true
|
|
19
|
+
}
|
|
20
|
+
]
|
|
21
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"createdAt": "2026-09-08T10:51:08.784Z",
|
|
3
|
+
"updatedAt": "2026-09-08T10:53:03.294Z",
|
|
4
|
+
"asA": "shelf consumer running the deploy-hetzner-server v1.0.1 real-account probes against a live Hetzner Cloud project (CI_HAS_HETZNER_ACCOUNT=true)",
|
|
5
|
+
"iWant": "the T-1 real-account probes to return aggregateVerdict pass without local patches: provision reads snake_case hcloud fields; the fixture renders the cloud-init user-data to a scratch path from the shipped template with resolved ssh public-key material and NOPASSWD sudo for the deploy user; provision, mock and destroy consume that same rendered file; destroy and sweep-orphans never pass --output json to a delete verb; the snapshot verb uses hcloud server create-image --type snapshot and matches by label; ssh baseline waits for cloud-init before firing; and the manifest ssh-key name is overridable via RCF_LITE_CI_SSH_KEY_NAME with the manifest value as default",
|
|
6
|
+
"soThat": "the mocked probes cannot pass while the real path fails on the same rendered artefact, throwaway servers never leak because destroy always succeeds, and the six baseline hardening blocks are observably present on the running server",
|
|
7
|
+
"acceptanceCriteria": [
|
|
8
|
+
{
|
|
9
|
+
"id": "AC-14501-1",
|
|
10
|
+
"description": "Given the shared throwaway-server fixture at packages/rcf-lite/test/fixtures/hetzner-throwaway-server/ on the H-1 patch train, when node blueprints/deploy-hetzner-server/contributions/probes/run-real-account-throwaway-server-provision.mjs, run-real-account-cloud-init-hardened.mjs and run-real-account-snapshot-on-demand.mjs run against a live Hetzner Cloud project (CI_HAS_HETZNER_ACCOUNT=true, RCF_LITE_CI_SSH_KEY_NAME=dave-ed25519, HCLOUD_TOKEN from hq-estate/HETZNER_ACCOUNT_API_KEY), then (a) provision writes hetzner/servers/rendered/ci-throwaway.cloud-init.yaml by rendering the shipped cloud-init template with the ssh public-key material fetched via hcloud ssh-key describe --output json and a write_files sudoers.d fragment granting NOPASSWD to the deploy user; (b) provision reads s.public_net.ipv4.ip, s.datacenter.location.name, s.server_type.name (snake_case) off the hcloud server create --output json response and writes scratch/last-throwaway.json before returning; (c) hcloud-dry-run-mock.mjs reads the same rendered file back and asserts it carries at least one ssh-ed25519 or ssh-rsa line and a NOPASSWD directive naming the deploy user; (d) destroy.mjs and sweep-orphans.mjs never pass --output json to a hcloud <resource> delete verb and the tolerant JSON parser accepts arrays; (e) snapshot-verb.mjs shells hcloud server create-image --type snapshot --description <label> <id> and recovers the created id via hcloud image list --type=snapshot --output json by matching the serverName label; (f) ssh-baseline-check.mjs polls port 22 open plus a ssh true exec (bounded up to 6 minutes) before firing the six baseline checks, all six of which pass on the running server (sshKeyOnly, rootDisabled, ufwDefaultDeny, dockerUserChain, fail2banActive, unattendedUpgradesActive). Anchors the label AC-hetznerServer-realAccountFidelity.",
|
|
11
|
+
"testable": true
|
|
12
|
+
}
|
|
13
|
+
],
|
|
14
|
+
"usId": "US-14501",
|
|
15
|
+
"prdId": "PRD-001",
|
|
16
|
+
"reqId": "REQ-145",
|
|
17
|
+
"version": "0.1.0",
|
|
18
|
+
"status": "draft",
|
|
19
|
+
"title": "H-1: deploy-hetzner-server 1.0.1 real-account probes return aggregateVerdict pass unpatched; fixture renders cloud-init with ssh public key material and NOPASSWD deploy user; mock consumes the same rendered file; destroy and sweep drop --output json on delete; snapshot uses hcloud server create-image --type snapshot; ssh baseline polls before firing; sshKeyIds override via RCF_LITE_CI_SSH_KEY_NAME",
|
|
20
|
+
"tacIds": [
|
|
21
|
+
"TAC-3801-deploy-hetzner-server-provisioner",
|
|
22
|
+
"TAC-3803-deploy-hetzner-server-cloud-init-template"
|
|
23
|
+
]
|
|
24
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"createdAt": "2026-09-08T12:17:33.807Z",
|
|
3
|
+
"updatedAt": "2026-09-08T12:19:24.742Z",
|
|
4
|
+
"asA": "rcf-lite maintainer applying platform-cloudflare-kv v1.0.0",
|
|
5
|
+
"iWant": "every kv probe result and the kv README to cite ACs from the shipped AC-31xxx band, and every one of the nine shipped kv ACs to appear as an anchor (primary or additional result) on at least one probe with a runtime observable",
|
|
6
|
+
"soThat": "the shipped kv probes count as evidence for the shipped kv ACs, no defunct AC-5xxx id survives on the kv blueprint, and traceability closes over the whole shipped kv surface",
|
|
7
|
+
"description": "As part of H-2 (Cloudflare-platform probe integrity), re-anchor every kv probe (facade-round-trip, list-with-prefix, cache-aside-hit-then-miss, event-secrecy, real-account-eventual-consistency-smoke), plus the kv README chain-slice pointers and the kv-anatomy test assertions, from AC-5xxx to the shipped AC-31xxx band per Dave ruling 4 (relay 582c2bca, 2026-09-08). The two ACs no shipped probe currently covers are added as additional results: AC-31102-1 (env.CACHE grep returns exactly src/kv-facade.mjs) becomes a runtime grep observable on facade-round-trip; AC-31107-1 (whitelist-only lifecycle events) becomes a whitelist-scan result on event-secrecy. Anatomy-test edits ride H-2 per dispatch addendum ruling 1. Nine ACs bound: 31101-1, 31102-1, 31103-1, 31103-2, 31104-1, 31105-1, 31106-1, 31107-1, 31108-1.",
|
|
8
|
+
"usId": "US-15001",
|
|
9
|
+
"prdId": "PRD-001",
|
|
10
|
+
"reqId": "REQ-150",
|
|
11
|
+
"version": "0.1.0",
|
|
12
|
+
"status": "draft",
|
|
13
|
+
"title": "H-2 kv re-anchor: every kv probe result cites AC-31xxx; every shipped kv AC gains a runtime observable through the existing five probes",
|
|
14
|
+
"acceptanceCriteria": [
|
|
15
|
+
{
|
|
16
|
+
"id": "AC-15001-1",
|
|
17
|
+
"description": "A grep for AC-5 across blueprints/platform-cloudflare-kv/ (probes, README, changelog, guide, blueprint.json, .rcf/reports/blueprints/platform-cloudflare-kv/) returns zero hits. Every anchorAcId string in the five contributed kv probes (facade-round-trip, list-with-prefix, cache-aside-hit-then-miss, event-secrecy, real-account-eventual-consistency-smoke) and every AC id in the kv-anatomy test cite the shipped AC-31xxx band. The kv README chain-slice pointer paragraph names the shipped US-31101..US-31108 range and no AC-5xxx string remains.",
|
|
18
|
+
"testable": true
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
"id": "AC-15001-2",
|
|
22
|
+
"description": "Each of the nine shipped kv ACs (AC-31101-1, AC-31102-1, AC-31103-1, AC-31103-2, AC-31104-1, AC-31105-1, AC-31106-1, AC-31107-1, AC-31108-1) appears as an anchorAcId (primary or additional result) on at least one shipped kv probe result. AC-31102-1 is covered by a runtime env.CACHE-grep observable on facade-round-trip; AC-31107-1 is covered by a whitelist-scan observable on event-secrecy. A test in the kv-anatomy suite asserts each of the nine AC ids appears in the union of shipped probe results and each cited result is pass.",
|
|
23
|
+
"testable": true
|
|
24
|
+
}
|
|
25
|
+
]
|
|
26
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"createdAt": "2026-09-08T12:17:34.305Z",
|
|
3
|
+
"updatedAt": "2026-09-08T12:19:47.426Z",
|
|
4
|
+
"asA": "rcf-lite maintainer applying platform-cloudflare-durable-objects v1.0.0",
|
|
5
|
+
"iWant": "real-account-storage-smoke to drive a real HTTP round trip against a deployed Worker route that opens the DO facade, writes a fixture key and reads it back byte-equal (or record accountBoundSkipped when the account env is absent), and the five DO ACs currently unbound (AC-33106-1, AC-33108-1, AC-33109-1, AC-33110-1, AC-33111-1) to appear as additional-result anchors on the wrangler-seam, storage-round-trip and concurrent-increment probes",
|
|
6
|
+
"soThat": "the real-account run proves the DO facade actually round-trips a value on Cloudflare (not just that credentials are present), and all 13 shipped DO ACs are bound to a probe with a runtime observable",
|
|
7
|
+
"description": "Part of H-2. The credential-readiness pass-stub is replaced by a real driver: when CI_HAS_CLOUDFLARE_ACCOUNT is set with CF_ACCOUNT_ID, CF_DO_NAMESPACE_ID (or the binding config the driver needs) and CF_API_TOKEN, the probe drives an HTTP round trip against a deployed Worker route; the returned bytes must equal the written bytes for pass. Local proof via the existing wrangler-seam against miniflare or wrangler dev. Env-absent branch keeps section 3.5 pass-with-skip shape. A pass must never again be reachable from credential presence alone. The five unbound ACs are bound as additional-result anchors on existing probes; if any AC has no honest carrier a new probe body is added inside existing capability.",
|
|
8
|
+
"usId": "US-15101",
|
|
9
|
+
"prdId": "PRD-001",
|
|
10
|
+
"reqId": "REQ-151",
|
|
11
|
+
"version": "0.1.0",
|
|
12
|
+
"status": "draft",
|
|
13
|
+
"title": "H-2 DO real storage driver + anchor coverage: real-account-storage-smoke drives a byte-equal put/get round-trip against a deployed Worker; five previously-unbound DO ACs bound as additional-result anchors on existing probes",
|
|
14
|
+
"acceptanceCriteria": [
|
|
15
|
+
{
|
|
16
|
+
"id": "AC-15101-1",
|
|
17
|
+
"description": "When CI_HAS_CLOUDFLARE_ACCOUNT is set with CF_ACCOUNT_ID, CF_DO_NAMESPACE_ID (or the DO binding config the driver needs) and CF_API_TOKEN, real-account-storage-smoke drives an HTTP round trip against a deployed Worker route that opens the DO facade, writes a fixture key with a random 1 KiB payload, reads it back, and asserts the returned bytes equal the written value (fail-with-detail otherwise, never pass on credential-presence). Local proof: the same driver path against miniflare or wrangler dev via the existing wrangler-seam. Env-absent branch keeps section 3.5 pass-with-skip. A mutation switch (moved to a fixture-side shim; not read from a probe body) that returns wrong bytes on read causes aggregateVerdict fail with the observed vs expected bytes named.",
|
|
18
|
+
"testable": true
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
"id": "AC-15101-2",
|
|
22
|
+
"description": "Each of the thirteen shipped DO ACs (AC-33101-1..AC-33113-1) appears as an anchorAcId (primary or additional result) on at least one shipped DO probe result. The five previously-unbound DO ACs (AC-33106-1, AC-33108-1, AC-33109-1, AC-33110-1, AC-33111-1) are bound as additional-result anchors on the wrangler-seam, storage-round-trip and concurrent-increment probes where the probe genuinely observes the AC's behaviour; a new probe body is added inside existing capability only if no existing probe carries the observable. A test in the DO anatomy suite asserts each of the thirteen AC ids appears in the union of shipped probe results and each cited result is pass.",
|
|
23
|
+
"testable": true
|
|
24
|
+
}
|
|
25
|
+
]
|
|
26
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"createdAt": "2026-09-08T12:17:34.801Z",
|
|
3
|
+
"updatedAt": "2026-09-08T12:19:47.822Z",
|
|
4
|
+
"asA": "rcf-lite maintainer applying messaging-queue-cloudflare v1.0.0",
|
|
5
|
+
"iWant": "real-account-concurrency-smoke to publish 500 messages through the producer facade wired to a live Queues binding on a deployed Worker and assert concurrent processing up to the documented push-invocation cap when CI_HAS_CLOUDFLARE_ACCOUNT is set (or record accountBoundSkipped when it is not)",
|
|
6
|
+
"soThat": "the real-account run proves the queue actually processes messages concurrently on Cloudflare (not just that credentials are present) and the accountBoundSkipped pass-stub can never again be reached from account-flag presence alone",
|
|
7
|
+
"description": "Part of H-2. Cloudflare Queues does not support wrangler dev --remote, so the real-account driver rides a deployed Worker that binds the queue (queue name and binding parameterised via env; HQ supplies values at gate time, canonical queue rcf-lite-ci-queue-smoke per HQ runbook). The account-set branch publishes 500 messages, waits for delivery under a bounded timeout, and asserts concurrent processing per the documented push-invocation cap. Local proof against miniflare or wrangler dev (local queue simulation). The env-absent branch keeps pass-with-skip. The documented Cloudflare Queues limits URL (https://developers.cloudflare.com/queues/platform/limits/) is re-verified 200 at merge time and logged in the PR provenance transcript.",
|
|
8
|
+
"usId": "US-15201",
|
|
9
|
+
"prdId": "PRD-001",
|
|
10
|
+
"reqId": "REQ-152",
|
|
11
|
+
"version": "0.1.0",
|
|
12
|
+
"status": "draft",
|
|
13
|
+
"title": "H-2 queue real concurrency driver: real-account-concurrency-smoke publishes 500 messages through the producer facade against a live Queues binding on a deployed Worker and asserts concurrent processing up to the documented push-invocation cap",
|
|
14
|
+
"acceptanceCriteria": [
|
|
15
|
+
{
|
|
16
|
+
"id": "AC-15201-1",
|
|
17
|
+
"description": "When CI_HAS_CLOUDFLARE_ACCOUNT is set with the deployed-Worker binding env vars, real-account-concurrency-smoke publishes 500 messages through the producer facade wired to a live Queues binding on the deployed Worker (queue name and binding parameterised via env, canonical queue rcf-lite-ci-queue-smoke), waits under a bounded timeout for all 500 to be observed on the consumer side, and asserts concurrent processing occurred (observed max-in-flight consumers greater than one, up to and not exceeding the documented push-invocation cap read from Cloudflare Queues limits). accountBoundSkipped is never set on the account-set branch; a pass is unreachable from account-flag presence alone. Local proof: the same driver path against miniflare or wrangler dev with local queue simulation. Env-absent branch keeps section 3.5 pass-with-skip. The documented limits URL https://developers.cloudflare.com/queues/platform/limits/ is fetched once at merge time, must answer 200 and is logged in the PR provenance transcript.",
|
|
18
|
+
"testable": true
|
|
19
|
+
}
|
|
20
|
+
]
|
|
21
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
{
|
|
2
|
+
"createdAt": "2026-09-08T12:17:35.296Z",
|
|
3
|
+
"updatedAt": "2026-09-08T12:19:48.200Z",
|
|
4
|
+
"asA": "rcf-lite maintainer applying edge-cloudflare-tunnel v1.0.0",
|
|
5
|
+
"iWant": "real-account-connector-healthy to actually provision the throwaway hetzner server through the T-1 fixture surface and run cloudflared tunnel info <name> asserting healthy connector count (when both CI_HAS_CLOUDFLARE_ACCOUNT and CI_HAS_HETZNER_ACCOUNT are set), real-account-tunnel-hostname-routes to drive undici for the public-hostname sub-case (activated on CI_HAS_CLOUDFLARE_ACCOUNT) and a two-identity JWT probe for the access-gated sub-case (activated only when CI_HAS_CLOUDFLARE_ACCESS is also set), and manifest-schema-validate to fail with a fixture-setup pointer when the credentials placeholder is missing rather than warn",
|
|
6
|
+
"soThat": "the real-account tunnel run proves connectors are up and routes actually serve on Cloudflare, the warn-on-env-set branches never again mask a broken driver, and a missing fixture pointer surfaces as a clear failure not a warning",
|
|
7
|
+
"description": "Part of H-2. connector-healthy consumes the hetzner fixture as-is; its defects are H-1 scope at HQ; if the fixture path fails locally the driver fails with a pointer naming the fixture step, never warn. hostname-routes: the public-hostname sub-case fetches the scratch subdomain via undici; the access-gated sub-case obtains an Access Service Token identity, exchanges it for a JWT and asserts an authenticated fetch succeeds AND an unauthenticated fetch is denied; the AUD sub-case stays pass-with-skip when CI_HAS_CLOUDFLARE_ACCESS is unset (HQ note: Access is not enabled on the HQ account today, so at gate time the AUD sub-case stays pass-with-skip until HQ enables Access, expected not a driver defect). Env-absent branch keeps pass-with-skip on both probes; a pass must never again be reachable from account-flag presence alone.",
|
|
8
|
+
"usId": "US-15301",
|
|
9
|
+
"prdId": "PRD-001",
|
|
10
|
+
"reqId": "REQ-153",
|
|
11
|
+
"version": "0.1.0",
|
|
12
|
+
"status": "draft",
|
|
13
|
+
"title": "H-2 tunnel real drivers: connector-healthy exercises cloudflared tunnel info against the throwaway hetzner server; hostname-routes drives undici and (when Access is enabled) a two-identity JWT probe; manifest-schema-validate placeholder becomes fail-with-pointer",
|
|
14
|
+
"acceptanceCriteria": [
|
|
15
|
+
{
|
|
16
|
+
"id": "AC-15301-1",
|
|
17
|
+
"description": "When both CI_HAS_CLOUDFLARE_ACCOUNT and CI_HAS_HETZNER_ACCOUNT are set with the required credentials, real-account-connector-healthy provisions the throwaway hetzner server via the T-1 hetzner fixture surface, brings a named cloudflared tunnel connector up on it, runs cloudflared tunnel info <name> through a cloudflared control shim, asserts the reported healthy connector count is at least one, captures a tunnelConnectorUp event on the injected event sink, and tears the connector and server down on exit. If the hetzner fixture path fails locally the driver fails with a pointer naming the failed fixture step (hetzner fixture defects are H-1 scope at HQ, never a warn on this driver). Env-absent branch keeps section 3.5 pass-with-skip.",
|
|
18
|
+
"testable": true
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
"id": "AC-15301-2",
|
|
22
|
+
"description": "When CI_HAS_CLOUDFLARE_ACCOUNT is set with the required tunnel credentials, real-account-tunnel-hostname-routes drives an undici fetch against the configured scratch subdomain for the public-hostname sub-case, asserts an HTTP 200 with expected body signature. When CI_HAS_CLOUDFLARE_ACCESS is ALSO set with Access service-token identities, the same probe drives a two-identity JWT sub-case: identity A obtains a JWT via the Service Token exchange and an authenticated fetch to the access-gated hostname succeeds; identity B without a JWT is denied (HTTP 302 to Access or HTTP 401). accountBoundSkipped is never set on the account-set branch; a pass is unreachable from CI_HAS_CLOUDFLARE_ACCOUNT presence alone on this probe. The access-gated sub-case remains pass-with-skip when CI_HAS_CLOUDFLARE_ACCESS is unset (HQ note: not enabled on HQ account today, expected). Env-absent branch keeps pass-with-skip.",
|
|
23
|
+
"testable": true
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
"id": "AC-15301-3",
|
|
27
|
+
"description": "manifest-schema-validate.mjs returns aggregateVerdict fail (not warn) with a detail string naming the missing credentials placeholder file and the fixture-setup step that would create it when the credentials placeholder is absent. The warn-on-missing-credentials-placeholder branch is removed.",
|
|
28
|
+
"testable": true
|
|
29
|
+
}
|
|
30
|
+
]
|
|
31
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
{
|
|
2
|
+
"createdAt": "2026-09-08T12:17:35.792Z",
|
|
3
|
+
"updatedAt": "2026-09-08T12:19:48.599Z",
|
|
4
|
+
"asA": "rcf-lite maintainer applying the four Cloudflare-platform blueprints",
|
|
5
|
+
"iWant": "no SIMULATE_ read anywhere in a shipped probe body on the four blueprints, no fail envelope committed under .rcf/reports on the four blueprints, and every committed envelope reflecting a shipped-code pass run against the re-anchored probes",
|
|
6
|
+
"soThat": "the mutation-purity rule holds at the probe boundary, envelopes are trusted evidence rather than stale fail records, and honest labelling of local test doubles restores probe-comment credibility",
|
|
7
|
+
"description": "Part of H-2. All SIMULATE_ branches in shipped probe bodies (kv cache-aside-hit-then-miss, kv event-secrecy, DO sole-reader-scan, DO storage-round-trip, DO websocket-hub-broadcast) move to fixture-side shim modules under packages/rcf-lite/test/fixtures/cf-platform/ or .../cf-edge/. New shim files carry the h2-cf-platform-probe-integrity slug prefix (short form h2-cf acceptable). Every driver's negative path is proven by firing the fixture-side mutation switch and observing the FAIL tail; only shipped-code pass envelopes are committed. The committed fail envelope at .rcf/reports/blueprints/platform-cloudflare-kv/event-secrecy.json is deleted and a shipped-code pass envelope committed in its place; the other four kv envelopes are regenerated so committed envelopes reflect re-anchored shipped-code runs. Probe comments labelling doubles as fake state / fake WebSocket pair / fake clock are reworded to name the local double honestly, or adjudicated acceptable with reason in the PR body.",
|
|
8
|
+
"usId": "US-15401",
|
|
9
|
+
"prdId": "PRD-001",
|
|
10
|
+
"reqId": "REQ-154",
|
|
11
|
+
"version": "0.1.0",
|
|
12
|
+
"status": "draft",
|
|
13
|
+
"title": "H-2 cross-cutting probe hygiene: SIMULATE_ branches out of probe bodies into fixture shims; no fail envelope committed; probe comments name test doubles honestly",
|
|
14
|
+
"acceptanceCriteria": [
|
|
15
|
+
{
|
|
16
|
+
"id": "AC-15401-1",
|
|
17
|
+
"description": "A grep for the token SIMULATE_ across every shipped probe module (contributions/probes/*.mjs) on the four Cloudflare-platform blueprints (platform-cloudflare-kv, platform-cloudflare-durable-objects, messaging-queue-cloudflare, edge-cloudflare-tunnel) returns zero hits. Every mutation switch previously read from a probe body is now read from a fixture-side shim module under packages/rcf-lite/test/fixtures/cf-platform/ or .../cf-edge/ whose file name carries the h2-cf-platform-probe-integrity slug prefix (short form h2-cf acceptable). For each moved switch, a corresponding FAIL tail is observed and recorded in the PR provenance transcript when the shims switch is on.",
|
|
18
|
+
"testable": true
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
"id": "AC-15401-2",
|
|
22
|
+
"description": "No committed report under .rcf/reports/blueprints/{platform-cloudflare-kv, platform-cloudflare-durable-objects, messaging-queue-cloudflare, edge-cloudflare-tunnel}/ carries aggregateVerdict fail or warn. Every committed envelope on the four blueprints reflects a shipped-code pass run against the re-anchored probes; the previously committed fail envelope at .rcf/reports/blueprints/platform-cloudflare-kv/event-secrecy.json is replaced with a shipped-code pass envelope.",
|
|
23
|
+
"testable": true
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
"id": "AC-15401-3",
|
|
27
|
+
"description": "Every probe-comment or probe-utils-comment surfaced by stage-1 marker rows (kv fake clock; DO fake state; DO probe-utils lines 73 and 75; DO websocket-hub-broadcast fake WebSocket pair; kv not-yet elicit-gating wording) is either reworded to name the local test double honestly on its terms (a fixture in-memory driver realises the Workers KV binding shape; a synthetic WebSocket pair; an elicited fake wall-clock advanced deterministically by the fixture; a follow-up work-item note in place of not-yet) or adjudicated acceptable in the PR body with a stated reason. No shipped probe comment on the four blueprints carries a bare fake / not-yet marker without either honest naming or an adjudication row.",
|
|
28
|
+
"testable": true
|
|
29
|
+
}
|
|
30
|
+
]
|
|
31
|
+
}
|
package/releases/releases.yaml
CHANGED
|
@@ -40,8 +40,28 @@
|
|
|
40
40
|
# `npm install rcf-lite`.
|
|
41
41
|
|
|
42
42
|
feedVersion: 1
|
|
43
|
-
latest: "0.
|
|
43
|
+
latest: "0.26.0"
|
|
44
44
|
releases:
|
|
45
|
+
- version: "0.26.0"
|
|
46
|
+
date: "2026-09-09"
|
|
47
|
+
breaking: false
|
|
48
|
+
headlines:
|
|
49
|
+
- "rcf-lite 0.26.0 is a hardening and authoring release. The Cloudflare-platform blueprints on the shelf pick up real-account probe drivers with positive evidence and one shared account-token env matrix."
|
|
50
|
+
- "The blueprint authoring standard gains three new sections (7c REQ-layer sufficiency, 7d positive-evidence verification, 7e single-definition ownership), ten checklist rows and RULE 16 in the managed agent block."
|
|
51
|
+
- "The rcf define blueprint verb group gains a lint-consistency subverb, a per-slug disposition ledger with an apply-time prompt and a read-only dispositions view, and the identity seed grows a register field. The schema floor moves to rcf-schemas 0.6.2."
|
|
52
|
+
minAgentAction: null
|
|
53
|
+
notesUrl: "https://stravica.ai/docs/rcf/changelog/"
|
|
54
|
+
|
|
55
|
+
- version: "0.25.0"
|
|
56
|
+
date: "2026-09-08"
|
|
57
|
+
breaking: false
|
|
58
|
+
headlines:
|
|
59
|
+
- "rcf-lite 0.25.0 opens the Hetzner line with three blueprints in one round: a Hetzner Cloud server as the shipped Linux VM shape with the estate hardening baseline and a snapshot cadence, a docker-compose platform on top with healthchecks, secrets as file mounts and a first-class reverse-proxy artefact, and a Cloudflare Tunnel bridge that composes with Access when Zero Trust is applied and drops to public-hostname mode when it is not."
|
|
60
|
+
- "Every real-account probe across the round ships accountBoundSkipped pending the Hetzner and Cloudflare token vault ruling; the local probes carry the ship-time verdicts."
|
|
61
|
+
- "The follow-up Hetzner Object Storage adapter ships as a sequential PR under object-storage-s3 v1.1.0 after this release; the rcf-lite package version does not bump for it."
|
|
62
|
+
minAgentAction: null
|
|
63
|
+
notesUrl: "https://stravica.ai/docs/rcf/changelog/"
|
|
64
|
+
|
|
45
65
|
- version: "0.24.0"
|
|
46
66
|
date: "2026-09-08"
|
|
47
67
|
breaking: false
|
package/src/blueprint/apply.js
CHANGED
|
@@ -21,6 +21,7 @@ import { updateManifest } from './manifest-writer.js';
|
|
|
21
21
|
import { stampId } from './namespace.js';
|
|
22
22
|
import { nextResolutionId } from './resolutions.js';
|
|
23
23
|
import { buildRefusalMessage, discoverAppliedCapabilities, runCustomAuthCapabilityElicits, runElicitationPhase, writeSidecar } from './capabilities.js';
|
|
24
|
+
import { APPLY_DISPOSITION_PROMPT, initialiseLedger } from './disposition-ledger.js';
|
|
24
25
|
|
|
25
26
|
/**
|
|
26
27
|
* @typedef {object} ApplyResult
|
|
@@ -410,11 +411,36 @@ export async function applyBlueprint({ projectRoot, tree, source, displaySource,
|
|
|
410
411
|
});
|
|
411
412
|
}
|
|
412
413
|
|
|
414
|
+
// Disposition ledger. On a fresh apply, initialise
|
|
415
|
+
// rcf/blueprints/<slug>.disposition.json with one record per
|
|
416
|
+
// contributed AC so the applying agent has a machine-readable walk
|
|
417
|
+
// list. Reads AC ids and their `disposition` field (rcf-schemas
|
|
418
|
+
// 0.6.2) from the SOURCE user-story JSON so the record reflects the
|
|
419
|
+
// authored shape, not the stamped one; `fixed` ACs land as accepted
|
|
420
|
+
// with the sentinel reason, `template` and unmarked ACs land as
|
|
421
|
+
// pending-disposition. Re-apply leaves an existing ledger untouched.
|
|
422
|
+
let ledgerPath = null;
|
|
423
|
+
let dispositionPrompt = null;
|
|
424
|
+
let acCount = 0;
|
|
425
|
+
if (!dryRun) {
|
|
426
|
+
const acDescriptors = await collectAcDescriptorsFromSource(source, blueprint, namespace);
|
|
427
|
+
acCount = acDescriptors.length;
|
|
428
|
+
if (acCount > 0) {
|
|
429
|
+
const ledgerRes = await initialiseLedger({ projectRoot, slug: appliedSlug, acDescriptors, now });
|
|
430
|
+
ledgerPath = ledgerRes.path;
|
|
431
|
+
if (!ledgerRes.alreadyExisted) {
|
|
432
|
+
dispositionPrompt = APPLY_DISPOSITION_PROMPT(appliedSlug, blueprint.version, acCount);
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
|
|
413
437
|
return {
|
|
414
438
|
applied: true,
|
|
415
439
|
slug: appliedSlug,
|
|
416
440
|
version: blueprint.version,
|
|
417
441
|
contributions: writtenContributions,
|
|
442
|
+
...(ledgerPath ? { ledgerPath, dispositionAcCount: acCount } : {}),
|
|
443
|
+
...(dispositionPrompt ? { dispositionPrompt } : {}),
|
|
418
444
|
...(wroteSidecar ? { sidecarPath, appliedCapabilities, appliedElicitations } : {}),
|
|
419
445
|
// Companion-suggestion mechanism (spec 2.6). Bubble the source
|
|
420
446
|
// blueprint's `suggestedCompanions[]` up on the result so the CLI
|
|
@@ -428,6 +454,44 @@ export async function applyBlueprint({ projectRoot, tree, source, displaySource,
|
|
|
428
454
|
};
|
|
429
455
|
}
|
|
430
456
|
|
|
457
|
+
/**
|
|
458
|
+
* Walk the blueprint's user-story contributions on-disk and collect
|
|
459
|
+
* every AC as a { id, storyId, sourceDisposition? } descriptor for the
|
|
460
|
+
* disposition ledger. AC ids and story ids are stamped with the
|
|
461
|
+
* applied namespace so they match what the applying agent sees in the
|
|
462
|
+
* tree (rather than the raw blueprint-slug ids on the source files).
|
|
463
|
+
*
|
|
464
|
+
* `disposition` on the AC (rcf-schemas 0.6.2 $defs.acDisposition) is
|
|
465
|
+
* `fixed` | `template` and is optional; an unmarked AC lands as
|
|
466
|
+
* pending-disposition with no `sourceDisposition` field so the operator
|
|
467
|
+
* can decide.
|
|
468
|
+
*/
|
|
469
|
+
async function collectAcDescriptorsFromSource(sourcePath, blueprint, namespace) {
|
|
470
|
+
const descriptors = [];
|
|
471
|
+
for (const c of blueprint.contributions ?? []) {
|
|
472
|
+
if (c.kind !== 'us' || typeof c.path !== 'string') continue;
|
|
473
|
+
const abs = join(sourcePath, 'contributions', c.path);
|
|
474
|
+
let doc;
|
|
475
|
+
try { doc = JSON.parse(await readFile(abs, 'utf8')); } catch { continue; }
|
|
476
|
+
const rawStoryId = typeof doc.usId === 'string' ? doc.usId : c.id;
|
|
477
|
+
// Re-stamp under the applied namespace so a library-qualified apply
|
|
478
|
+
// (namespace differs from the blueprint's own slug) records the
|
|
479
|
+
// story id the applying agent will actually see on the tree.
|
|
480
|
+
const storyStamped = stampId(rawStoryId, namespace);
|
|
481
|
+
const storyId = 'error' in storyStamped ? rawStoryId : storyStamped.id;
|
|
482
|
+
const acs = Array.isArray(doc.acceptanceCriteria) ? doc.acceptanceCriteria : [];
|
|
483
|
+
for (const ac of acs) {
|
|
484
|
+
if (!ac || typeof ac.id !== 'string') continue;
|
|
485
|
+
const descriptor = { id: ac.id, storyId };
|
|
486
|
+
if (ac.disposition === 'fixed' || ac.disposition === 'template') {
|
|
487
|
+
descriptor.sourceDisposition = ac.disposition;
|
|
488
|
+
}
|
|
489
|
+
descriptors.push(descriptor);
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
return descriptors;
|
|
493
|
+
}
|
|
494
|
+
|
|
431
495
|
function stampContributions(contributions, namespace) {
|
|
432
496
|
const out = [];
|
|
433
497
|
for (const c of contributions ?? []) {
|