rcf-lite 0.27.0 → 0.28.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 +23 -0
- package/README.md +10 -0
- package/bin/rcf.js +2 -0
- package/blueprints/application-account-settings/CHANGELOG.md +35 -6
- package/blueprints/application-account-settings/README.md +1 -1
- package/blueprints/application-account-settings/blueprint.json +4 -2
- package/blueprints/application-account-settings/contributions/adrs/adr-2602-application-account-settings-security-surface-shape.json +1 -1
- package/blueprints/application-account-settings/contributions/probes/probe-utils.mjs +177 -0
- package/blueprints/application-account-settings/contributions/probes/profile-form-autocomplete.mjs +67 -0
- package/blueprints/application-account-settings/contributions/probes/run-profile-form-autocomplete.mjs +5 -0
- package/blueprints/application-account-settings/contributions/probes/run-sessions-adapter-uniform.mjs +5 -0
- package/blueprints/application-account-settings/contributions/probes/run-sessions-surface-shape.mjs +5 -0
- package/blueprints/application-account-settings/contributions/probes/run-shell-tablist-per-capability.mjs +5 -0
- package/blueprints/application-account-settings/contributions/probes/run-theme-radiogroup.mjs +5 -0
- package/blueprints/application-account-settings/contributions/probes/sessions-adapter-uniform.mjs +130 -0
- package/blueprints/application-account-settings/contributions/probes/sessions-surface-shape.mjs +70 -0
- package/blueprints/application-account-settings/contributions/probes/shell-tablist-per-capability.mjs +60 -0
- package/blueprints/application-account-settings/contributions/probes/theme-radiogroup.mjs +126 -0
- package/blueprints/application-admin-console/CHANGELOG.md +32 -6
- package/blueprints/application-admin-console/README.md +1 -1
- package/blueprints/application-admin-console/blueprint.json +4 -2
- package/blueprints/application-admin-console/contributions/adrs/adr-2201-application-admin-console-capability-vocabulary.json +1 -1
- package/blueprints/application-admin-console/contributions/probes/audit-log-surface.mjs +79 -0
- package/blueprints/application-admin-console/contributions/probes/org-switcher-surface.mjs +83 -0
- package/blueprints/application-admin-console/contributions/probes/permission-matrix-grid.mjs +67 -0
- package/blueprints/application-admin-console/contributions/probes/probe-utils.mjs +177 -0
- package/blueprints/application-admin-console/contributions/probes/run-audit-log-surface.mjs +5 -0
- package/blueprints/application-admin-console/contributions/probes/run-org-switcher-surface.mjs +5 -0
- package/blueprints/application-admin-console/contributions/probes/run-permission-matrix-grid.mjs +5 -0
- package/blueprints/application-admin-console/contributions/probes/run-sign-in-access-gated-surface.mjs +5 -0
- package/blueprints/application-admin-console/contributions/probes/run-users-directory-surface.mjs +5 -0
- package/blueprints/application-admin-console/contributions/probes/sign-in-access-gated-surface.mjs +117 -0
- package/blueprints/application-admin-console/contributions/probes/users-directory-surface.mjs +145 -0
- package/blueprints/application-api-rest/CHANGELOG.md +16 -8
- package/blueprints/application-api-rest/README.md +3 -3
- package/blueprints/application-api-rest/blueprint.json +3 -2
- package/blueprints/application-api-rest/contributions/adrs/adr-302-application-api-rest-auth-model.json +1 -1
- package/blueprints/application-api-rest/contributions/probes/cursor-pagination-round-trip.mjs +154 -0
- package/blueprints/application-api-rest/contributions/probes/health-probes-distinct.mjs +124 -0
- package/blueprints/application-api-rest/contributions/probes/probe-utils.mjs +177 -0
- package/blueprints/application-api-rest/contributions/probes/problem-details-on-error.mjs +77 -0
- package/blueprints/application-api-rest/contributions/probes/request-id-echoed.mjs +76 -0
- package/blueprints/application-api-rest/contributions/probes/run-cursor-pagination-round-trip.mjs +5 -0
- package/blueprints/application-api-rest/contributions/probes/run-health-probes-distinct.mjs +5 -0
- package/blueprints/application-api-rest/contributions/probes/run-problem-details-on-error.mjs +5 -0
- package/blueprints/application-api-rest/contributions/probes/run-request-id-echoed.mjs +5 -0
- package/blueprints/application-api-rest/docs/topics.md +1 -1
- package/blueprints/application-charts/CHANGELOG.md +35 -9
- package/blueprints/application-charts/README.md +6 -6
- package/blueprints/application-charts/blueprint.json +5 -3
- package/blueprints/application-charts/contributions/adrs/adr-1901-application-charts-engine-choice.json +1 -1
- package/blueprints/application-charts/contributions/probes/keyboard-traversal.mjs +151 -0
- package/blueprints/application-charts/contributions/probes/non-colour-distinction.mjs +67 -0
- package/blueprints/application-charts/contributions/probes/probe-utils.mjs +177 -0
- package/blueprints/application-charts/contributions/probes/run-keyboard-traversal.mjs +5 -0
- package/blueprints/application-charts/contributions/probes/run-non-colour-distinction.mjs +5 -0
- package/blueprints/application-charts/contributions/probes/run-text-alternative-table.mjs +5 -0
- package/blueprints/application-charts/contributions/probes/text-alternative-table.mjs +139 -0
- package/blueprints/application-charts/contributions/requirements/application-charts-req-001.json +1 -1
- package/blueprints/application-charts/contributions/requirements/application-charts-req-002.json +1 -1
- package/blueprints/application-charts/contributions/user-stories/application-charts-us-18101.json +5 -5
- package/blueprints/application-charts/contributions/user-stories/application-charts-us-18106.json +1 -1
- package/blueprints/application-charts/guide/application-charts.md +1 -1
- package/blueprints/application-dashboard/CHANGELOG.md +20 -10
- package/blueprints/application-dashboard/README.md +6 -6
- package/blueprints/application-dashboard/assets/guidance/dashboard-design.md +2 -2
- package/blueprints/application-dashboard/blueprint.json +3 -2
- package/blueprints/application-dashboard/contributions/adrs/adr-2001-application-dashboard-primary-kpi-enum.json +1 -1
- package/blueprints/application-dashboard/contributions/adrs/adr-2002-application-dashboard-timeframe-presets.json +1 -1
- package/blueprints/application-dashboard/contributions/probes/export-handle-formats.mjs +75 -0
- package/blueprints/application-dashboard/contributions/probes/four-tile-states.mjs +75 -0
- package/blueprints/application-dashboard/contributions/probes/primary-kpi-top-left.mjs +58 -0
- package/blueprints/application-dashboard/contributions/probes/probe-utils.mjs +177 -0
- package/blueprints/application-dashboard/contributions/probes/run-export-handle-formats.mjs +4 -0
- package/blueprints/application-dashboard/contributions/probes/run-four-tile-states.mjs +4 -0
- package/blueprints/application-dashboard/contributions/probes/run-primary-kpi-top-left.mjs +4 -0
- package/blueprints/application-dashboard/contributions/probes/run-shell-five-regions.mjs +4 -0
- package/blueprints/application-dashboard/contributions/probes/shell-five-regions.mjs +93 -0
- package/blueprints/application-dashboard/contributions/requirements/application-dashboard-req-002.json +1 -1
- package/blueprints/application-dashboard/contributions/requirements/application-dashboard-req-003.json +1 -1
- package/blueprints/application-dashboard/contributions/tacs/tac-2002-application-dashboard-filter-chrome.json +1 -1
- package/blueprints/application-dashboard/contributions/tacs/tac-2003-application-dashboard-export-handle.json +2 -2
- package/blueprints/application-dashboard/contributions/user-stories/application-dashboard-us-19101.json +2 -2
- package/blueprints/application-dashboard/contributions/user-stories/application-dashboard-us-19102.json +2 -2
- package/blueprints/application-dashboard/contributions/user-stories/application-dashboard-us-19103.json +1 -1
- package/blueprints/application-dashboard/contributions/user-stories/application-dashboard-us-19104.json +1 -1
- package/blueprints/application-dashboard/contributions/user-stories/application-dashboard-us-19105.json +1 -1
- package/blueprints/application-dashboard/contributions/user-stories/application-dashboard-us-19106.json +2 -2
- package/blueprints/application-dashboard/contributions/user-stories/application-dashboard-us-19107.json +5 -5
- package/blueprints/application-dashboard/docs/topics.md +2 -2
- package/blueprints/application-dashboard/guide/application-dashboard.md +2 -2
- package/blueprints/application-datatable/CHANGELOG.md +19 -9
- package/blueprints/application-datatable/README.md +2 -2
- package/blueprints/application-datatable/blueprint.json +3 -2
- package/blueprints/application-datatable/contributions/probes/apg-table-shape.mjs +57 -0
- package/blueprints/application-datatable/contributions/probes/four-states-regions.mjs +80 -0
- package/blueprints/application-datatable/contributions/probes/probe-utils.mjs +177 -0
- package/blueprints/application-datatable/contributions/probes/run-apg-table-shape.mjs +4 -0
- package/blueprints/application-datatable/contributions/probes/run-four-states-regions.mjs +4 -0
- package/blueprints/application-datatable/contributions/probes/run-search-adapter-round-trip.mjs +4 -0
- package/blueprints/application-datatable/contributions/probes/run-sort-adapter-round-trip.mjs +4 -0
- package/blueprints/application-datatable/contributions/probes/search-adapter-round-trip.mjs +58 -0
- package/blueprints/application-datatable/contributions/probes/sort-adapter-round-trip.mjs +60 -0
- package/blueprints/application-datatable/contributions/requirements/application-datatable-req-006.json +1 -1
- package/blueprints/application-datatable/docs/topics.md +1 -1
- package/blueprints/application-empty-error-states/CHANGELOG.md +33 -3
- package/blueprints/application-empty-error-states/blueprint.json +4 -2
- package/blueprints/application-empty-error-states/contributions/probes/empty-list-and-no-search.mjs +66 -0
- package/blueprints/application-empty-error-states/contributions/probes/error-boundary-alert.mjs +65 -0
- package/blueprints/application-empty-error-states/contributions/probes/forbidden-and-server-error.mjs +167 -0
- package/blueprints/application-empty-error-states/contributions/probes/not-found-and-recovery.mjs +61 -0
- package/blueprints/application-empty-error-states/contributions/probes/permission-denied-and-offline.mjs +155 -0
- package/blueprints/application-empty-error-states/contributions/probes/probe-utils.mjs +177 -0
- package/blueprints/application-empty-error-states/contributions/probes/run-empty-list-and-no-search.mjs +5 -0
- package/blueprints/application-empty-error-states/contributions/probes/run-error-boundary-alert.mjs +5 -0
- package/blueprints/application-empty-error-states/contributions/probes/run-forbidden-and-server-error.mjs +5 -0
- package/blueprints/application-empty-error-states/contributions/probes/run-not-found-and-recovery.mjs +5 -0
- package/blueprints/application-empty-error-states/contributions/probes/run-permission-denied-and-offline.mjs +5 -0
- package/blueprints/application-error-handling/CHANGELOG.md +45 -6
- package/blueprints/application-error-handling/blueprint.json +3 -2
- package/blueprints/application-error-handling/contributions/probes/category-vocabulary.mjs +90 -0
- package/blueprints/application-error-handling/contributions/probes/probe-utils.mjs +177 -0
- package/blueprints/application-error-handling/contributions/probes/record-shape-adr-1701.mjs +78 -0
- package/blueprints/application-error-handling/contributions/probes/run-category-vocabulary.mjs +5 -0
- package/blueprints/application-error-handling/contributions/probes/run-record-shape-adr-1701.mjs +5 -0
- package/blueprints/application-error-handling/contributions/probes/run-two-boundaries-registered.mjs +5 -0
- package/blueprints/application-error-handling/contributions/probes/two-boundaries-registered.mjs +343 -0
- package/blueprints/application-file-upload/CHANGELOG.md +28 -6
- package/blueprints/application-file-upload/README.md +1 -1
- package/blueprints/application-file-upload/blueprint.json +3 -2
- package/blueprints/application-file-upload/contributions/probes/assertive-completion-slot.mjs +78 -0
- package/blueprints/application-file-upload/contributions/probes/chunked-transport-endpoints.mjs +173 -0
- package/blueprints/application-file-upload/contributions/probes/per-file-progressbar.mjs +124 -0
- package/blueprints/application-file-upload/contributions/probes/probe-utils.mjs +177 -0
- package/blueprints/application-file-upload/contributions/probes/run-assertive-completion-slot.mjs +4 -0
- package/blueprints/application-file-upload/contributions/probes/run-chunked-transport-endpoints.mjs +4 -0
- package/blueprints/application-file-upload/contributions/probes/run-per-file-progressbar.mjs +4 -0
- package/blueprints/application-file-upload/contributions/probes/run-upload-surface-shape.mjs +4 -0
- package/blueprints/application-file-upload/contributions/probes/upload-surface-shape.mjs +55 -0
- package/blueprints/application-file-upload/contributions/requirements/application-file-upload-req-001.json +1 -1
- package/blueprints/application-file-upload/contributions/requirements/application-file-upload-req-002.json +1 -1
- package/blueprints/application-file-upload/contributions/requirements/application-file-upload-req-003.json +1 -1
- package/blueprints/application-file-upload/contributions/requirements/application-file-upload-req-004.json +1 -1
- package/blueprints/application-file-upload/contributions/requirements/application-file-upload-req-005.json +1 -1
- package/blueprints/application-file-upload/probe-packs/application-file-upload.pack.mjs +1 -1
- package/blueprints/application-forms-wizard/CHANGELOG.md +20 -6
- package/blueprints/application-forms-wizard/README.md +2 -2
- package/blueprints/application-forms-wizard/blueprint.json +3 -2
- package/blueprints/application-forms-wizard/contributions/probes/draft-persistence-round-trip.mjs +110 -0
- package/blueprints/application-forms-wizard/contributions/probes/probe-utils.mjs +177 -0
- package/blueprints/application-forms-wizard/contributions/probes/run-draft-persistence-round-trip.mjs +4 -0
- package/blueprints/application-forms-wizard/contributions/probes/run-step-page-shape.mjs +4 -0
- package/blueprints/application-forms-wizard/contributions/probes/run-task-list-surface.mjs +4 -0
- package/blueprints/application-forms-wizard/contributions/probes/step-page-shape.mjs +61 -0
- package/blueprints/application-forms-wizard/contributions/probes/task-list-surface.mjs +109 -0
- package/blueprints/application-forms-wizard/contributions/requirements/application-forms-wizard-req-001.json +1 -1
- package/blueprints/application-forms-wizard/contributions/requirements/application-forms-wizard-req-002.json +1 -1
- package/blueprints/application-forms-wizard/contributions/requirements/application-forms-wizard-req-003.json +1 -1
- package/blueprints/application-forms-wizard/contributions/requirements/application-forms-wizard-req-004.json +1 -1
- package/blueprints/application-forms-wizard/contributions/requirements/application-forms-wizard-req-005.json +1 -1
- package/blueprints/application-forms-wizard/probe-packs/application-forms-wizard.pack.mjs +1 -1
- package/blueprints/application-notifications-in-app/CHANGELOG.md +38 -5
- package/blueprints/application-notifications-in-app/README.md +4 -4
- package/blueprints/application-notifications-in-app/blueprint.json +4 -2
- package/blueprints/application-notifications-in-app/contributions/adrs/adr-2101-application-notifications-in-app-live-region-role-mapping.json +1 -1
- package/blueprints/application-notifications-in-app/contributions/probes/centre-acknowledge-round-trip.mjs +210 -0
- package/blueprints/application-notifications-in-app/contributions/probes/live-region-preseeding.mjs +93 -0
- package/blueprints/application-notifications-in-app/contributions/probes/probe-utils.mjs +177 -0
- package/blueprints/application-notifications-in-app/contributions/probes/run-centre-acknowledge-round-trip.mjs +5 -0
- package/blueprints/application-notifications-in-app/contributions/probes/run-live-region-preseeding.mjs +5 -0
- package/blueprints/application-notifications-in-app/contributions/probes/run-toast-contract.mjs +5 -0
- package/blueprints/application-notifications-in-app/contributions/probes/toast-contract.mjs +92 -0
- package/blueprints/application-notifications-in-app/contributions/tacs/tac-2101-application-notifications-in-app-live-region.json +3 -3
- package/blueprints/application-notifications-in-app/contributions/tacs/tac-2102-application-notifications-in-app-centre.json +1 -1
- package/blueprints/application-notifications-in-app/contributions/user-stories/application-notifications-in-app-us-20101.json +1 -1
- package/blueprints/application-notifications-in-app/contributions/user-stories/application-notifications-in-app-us-20102.json +1 -1
- package/blueprints/application-notifications-in-app/contributions/user-stories/application-notifications-in-app-us-20103.json +1 -1
- package/blueprints/application-notifications-in-app/contributions/user-stories/application-notifications-in-app-us-20105.json +1 -1
- package/blueprints/application-notifications-in-app/guide/application-notifications-in-app.md +3 -3
- package/blueprints/application-onboarding-tour/CHANGELOG.md +31 -5
- package/blueprints/application-onboarding-tour/README.md +1 -1
- package/blueprints/application-onboarding-tour/blueprint.json +5 -3
- package/blueprints/application-onboarding-tour/contributions/probes/checklist-anchor-open.mjs +81 -0
- package/blueprints/application-onboarding-tour/contributions/probes/completion-persistence.mjs +159 -0
- package/blueprints/application-onboarding-tour/contributions/probes/first-run-detection.mjs +67 -0
- package/blueprints/application-onboarding-tour/contributions/probes/probe-utils.mjs +177 -0
- package/blueprints/application-onboarding-tour/contributions/probes/run-checklist-anchor-open.mjs +5 -0
- package/blueprints/application-onboarding-tour/contributions/probes/run-completion-persistence.mjs +5 -0
- package/blueprints/application-onboarding-tour/contributions/probes/run-first-run-detection.mjs +5 -0
- package/blueprints/application-onboarding-tour/contributions/probes/run-stepper-role-dialog.mjs +5 -0
- package/blueprints/application-onboarding-tour/contributions/probes/stepper-role-dialog.mjs +45 -0
- package/blueprints/application-spa/CHANGELOG.md +20 -11
- package/blueprints/application-spa/README.md +9 -10
- package/blueprints/application-spa/blueprint.json +3 -2
- package/blueprints/application-spa/contributions/adrs/adr-202-application-spa-theming.json +1 -1
- package/blueprints/application-spa/contributions/adrs/adr-206-application-spa-iconography.json +1 -1
- package/blueprints/application-spa/contributions/probes/designed-empty-state.mjs +72 -0
- package/blueprints/application-spa/contributions/probes/probe-utils.mjs +177 -0
- package/blueprints/application-spa/contributions/probes/route-inventory-published.mjs +185 -0
- package/blueprints/application-spa/contributions/probes/run-designed-empty-state.mjs +5 -0
- package/blueprints/application-spa/contributions/probes/run-route-inventory-published.mjs +5 -0
- package/blueprints/application-spa/contributions/probes/run-shell-nav-present.mjs +5 -0
- package/blueprints/application-spa/contributions/probes/shell-nav-present.mjs +69 -0
- package/blueprints/application-spa/contributions/tacs/tac-207-application-spa-token-adherence-probe.json +1 -1
- package/blueprints/application-spa/contributions/tacs/tac-208-application-spa-icon-adherence-probe.json +2 -2
- package/blueprints/application-spa/contributions/tacs/tac-209-application-spa-csp-styled-adherence-probe.json +3 -3
- package/blueprints/application-spa/contributions/tacs/tac-210-application-spa-external-dependency-provisioning-probe.json +2 -2
- package/blueprints/application-spa/contributions/tacs/tac-211-application-spa-core-flow-e2e-probe.json +2 -2
- package/blueprints/application-spa/contributions/user-stories/application-spa-us-1131.json +1 -1
- package/blueprints/application-spa/docs/topics.md +1 -1
- package/blueprints/delivery-ci-workflows/CHANGELOG.md +31 -11
- package/blueprints/delivery-ci-workflows/README.md +3 -3
- package/blueprints/delivery-ci-workflows/blueprint.json +3 -2
- package/blueprints/delivery-ci-workflows/contributions/adrs/adr-702-delivery-ci-workflows-strict-coverage-gate.json +2 -2
- package/blueprints/delivery-ci-workflows/contributions/probes/node-gate-entrypoint.mjs +76 -0
- package/blueprints/delivery-ci-workflows/contributions/probes/probe-utils.mjs +56 -0
- package/blueprints/delivery-ci-workflows/contributions/probes/real-account-github-actions-run-record.mjs +139 -0
- package/blueprints/delivery-ci-workflows/contributions/probes/run-node-gate-entrypoint.mjs +3 -0
- package/blueprints/delivery-ci-workflows/contributions/probes/run-real-account-github-actions-run-record.mjs +3 -0
- package/blueprints/delivery-ci-workflows/contributions/probes/run-workflow-template-shape.mjs +3 -0
- package/blueprints/delivery-ci-workflows/contributions/probes/workflow-template-shape.mjs +94 -0
- package/blueprints/delivery-ci-workflows/contributions/requirements/delivery-ci-workflows-req-004.json +1 -1
- package/blueprints/delivery-ci-workflows/docs/topics.md +2 -3
- package/blueprints/deploy-cloudflare-workers/CHANGELOG.md +4 -4
- package/blueprints/deploy-cloudflare-workers/README.md +3 -3
- package/blueprints/deploy-cloudflare-workers/contributions/adrs/adr-1306-deploy-cloudflare-workers-spa-shape.json +2 -2
- package/blueprints/deploy-cloudflare-workers/docs/topics.md +2 -2
- package/blueprints/deploy-hetzner-server/CHANGELOG.md +98 -7
- package/blueprints/deploy-hetzner-server/blueprint.json +7 -6
- package/blueprints/deploy-hetzner-server/contributions/probes/cloud-init-render-lint.mjs +46 -21
- package/blueprints/deploy-hetzner-server/contributions/probes/hcloud-dry-run-mock.mjs +344 -83
- package/blueprints/deploy-hetzner-server/contributions/probes/manifest-schema-validate.mjs +211 -42
- package/blueprints/deploy-hetzner-server/contributions/probes/probe-utils.mjs +140 -22
- package/blueprints/deploy-hetzner-server/contributions/probes/real-account-cloud-init-hardened.mjs +111 -30
- package/blueprints/deploy-hetzner-server/contributions/probes/real-account-snapshot-on-demand.mjs +158 -30
- package/blueprints/deploy-hetzner-server/contributions/probes/real-account-throwaway-server-provision.mjs +154 -32
- package/blueprints/edge-cloudflare-access/CHANGELOG.md +6 -5
- package/blueprints/edge-cloudflare-access/blueprint.json +1 -1
- package/blueprints/edge-cloudflare-access/contributions/probes/admin-console-gate-surface.mjs +9 -1
- package/blueprints/edge-cloudflare-access/docs/topics.md +1 -1
- package/blueprints/edge-cloudflare-rate-limiting/CHANGELOG.md +4 -7
- package/blueprints/edge-cloudflare-rate-limiting/docs/topics.md +1 -1
- package/blueprints/edge-cloudflare-tunnel/CHANGELOG.md +4 -6
- package/blueprints/edge-cloudflare-tunnel/README.md +1 -2
- package/blueprints/edge-cloudflare-tunnel/docs/topics.md +1 -1
- package/blueprints/edge-cloudflare-turnstile/CHANGELOG.md +2 -3
- package/blueprints/edge-cloudflare-turnstile/docs/topics.md +1 -1
- package/blueprints/email-smtp-resend/CHANGELOG.md +24 -8
- package/blueprints/email-smtp-resend/README.md +2 -2
- package/blueprints/email-smtp-resend/blueprint.json +3 -2
- package/blueprints/email-smtp-resend/contributions/probes/probe-utils.mjs +50 -0
- package/blueprints/email-smtp-resend/contributions/probes/real-account-resend-send.mjs +50 -0
- package/blueprints/email-smtp-resend/contributions/probes/run-real-account-resend-send.mjs +3 -0
- package/blueprints/email-smtp-resend/contributions/probes/run-smtp-round-trip.mjs +3 -0
- package/blueprints/email-smtp-resend/contributions/probes/run-unverified-sender-refusal.mjs +3 -0
- package/blueprints/email-smtp-resend/contributions/probes/smtp-round-trip.mjs +43 -0
- package/blueprints/email-smtp-resend/contributions/probes/unverified-sender-refusal.mjs +99 -0
- package/blueprints/email-smtp-resend/docs/topics.md +2 -3
- package/blueprints/jobs-background/CHANGELOG.md +66 -5
- package/blueprints/jobs-background/README.md +2 -2
- package/blueprints/jobs-background/blueprint.json +3 -2
- package/blueprints/jobs-background/contributions/probes/apply-time-override.mjs +38 -10
- package/blueprints/jobs-background/contributions/probes/apply-time-refusal.mjs +28 -6
- package/blueprints/jobs-background/contributions/probes/event-secrecy.mjs +16 -2
- package/blueprints/jobs-background/contributions/probes/fake-clock-cron.mjs +102 -21
- package/blueprints/jobs-background/contributions/probes/probe-utils.mjs +10 -2
- package/blueprints/jobs-background/contributions/probes/retry-and-fail-real-account.mjs +355 -0
- package/blueprints/jobs-background/contributions/probes/retry-and-fail.mjs +33 -2
- package/blueprints/jobs-background/contributions/probes/run-retry-and-fail-real-account.mjs +12 -0
- package/blueprints/jobs-background/docs/topics.md +1 -1
- package/blueprints/jobs-background/guide/jobs-background.md +1 -1
- package/blueprints/messaging-queue-cloudflare/CHANGELOG.md +25 -19
- package/blueprints/messaging-queue-cloudflare/README.md +12 -12
- package/blueprints/messaging-queue-cloudflare/blueprint.json +1 -1
- package/blueprints/messaging-queue-cloudflare/contributions/adrs/adr-3001-messaging-queue-cloudflare-adapter.json +2 -2
- package/blueprints/messaging-queue-cloudflare/contributions/adrs/adr-3002-messaging-queue-cloudflare-delivery-semantics.json +1 -1
- package/blueprints/messaging-queue-cloudflare/contributions/probes/real-account-concurrency-smoke.mjs +180 -12
- package/blueprints/messaging-queue-cloudflare/contributions/requirements/messaging-queue-cloudflare-req-006.json +1 -1
- package/blueprints/messaging-queue-cloudflare/docs/topics.md +2 -2
- package/blueprints/messaging-queue-cloudflare/guide/messaging-queue-cloudflare.md +2 -2
- package/blueprints/object-storage-s3/CHANGELOG.md +75 -4
- package/blueprints/object-storage-s3/blueprint.json +3 -2
- package/blueprints/object-storage-s3/contributions/probes/event-secrecy.mjs +73 -12
- package/blueprints/object-storage-s3/contributions/probes/facade-round-trip.mjs +55 -7
- package/blueprints/object-storage-s3/contributions/probes/hetzner-object-storage-round-trip.mjs +102 -18
- package/blueprints/object-storage-s3/contributions/probes/multipart-upload.mjs +105 -36
- package/blueprints/object-storage-s3/contributions/probes/presigned-url.mjs +104 -55
- package/blueprints/object-storage-s3/contributions/probes/probe-utils.mjs +129 -7
- package/blueprints/object-storage-s3/contributions/probes/put-get-round-trip.mjs +80 -18
- package/blueprints/object-storage-s3/contributions/probes/r2-real-account-smoke.mjs +291 -37
- package/blueprints/object-storage-s3/contributions/probes/run-event-secrecy.mjs +8 -2
- package/blueprints/object-storage-s3/contributions/probes/run-facade-round-trip.mjs +5 -5
- package/blueprints/object-storage-s3/contributions/probes/run-hetzner-object-storage-round-trip.mjs +8 -5
- package/blueprints/object-storage-s3/contributions/probes/run-multipart-upload.mjs +8 -2
- package/blueprints/object-storage-s3/contributions/probes/run-presigned-url.mjs +8 -2
- package/blueprints/object-storage-s3/contributions/probes/run-put-get-round-trip.mjs +6 -3
- package/blueprints/object-storage-s3/contributions/probes/run-r2-real-account-smoke.mjs +10 -2
- package/blueprints/object-storage-s3/contributions/requirements/object-storage-s3-req-006.json +1 -1
- package/blueprints/object-storage-s3/docs/topics.md +1 -1
- package/blueprints/object-storage-s3/guide/object-storage-s3.md +1 -1
- package/blueprints/observability-essentials/CHANGELOG.md +23 -7
- package/blueprints/observability-essentials/README.md +2 -2
- package/blueprints/observability-essentials/assets/probe-samples/probe-response-baseline.v2.json +1 -1
- package/blueprints/observability-essentials/blueprint.json +3 -2
- package/blueprints/observability-essentials/contributions/probes/liveness-probe.mjs +84 -0
- package/blueprints/observability-essentials/contributions/probes/metrics-endpoint.mjs +96 -0
- package/blueprints/observability-essentials/contributions/probes/probe-utils.mjs +52 -0
- package/blueprints/observability-essentials/contributions/probes/readiness-probe.mjs +171 -0
- package/blueprints/observability-essentials/contributions/probes/run-liveness-probe.mjs +3 -0
- package/blueprints/observability-essentials/contributions/probes/run-metrics-endpoint.mjs +3 -0
- package/blueprints/observability-essentials/contributions/probes/run-readiness-probe.mjs +3 -0
- package/blueprints/observability-essentials/docs/topics.md +2 -3
- package/blueprints/observability-logging/CHANGELOG.md +29 -4
- package/blueprints/observability-logging/README.md +2 -2
- package/blueprints/observability-logging/blueprint.json +3 -2
- package/blueprints/observability-logging/contributions/probes/correlation-id-flow.mjs +173 -0
- package/blueprints/observability-logging/contributions/probes/line-shape-and-fields.mjs +82 -0
- package/blueprints/observability-logging/contributions/probes/probe-utils.mjs +47 -0
- package/blueprints/observability-logging/contributions/probes/redaction-boundary.mjs +130 -0
- package/blueprints/observability-logging/contributions/probes/run-correlation-id-flow.mjs +3 -0
- package/blueprints/observability-logging/contributions/probes/run-line-shape-and-fields.mjs +3 -0
- package/blueprints/observability-logging/contributions/probes/run-redaction-boundary.mjs +3 -0
- package/blueprints/observability-probe-endpoints/CHANGELOG.md +23 -8
- package/blueprints/observability-probe-endpoints/README.md +3 -3
- package/blueprints/observability-probe-endpoints/blueprint.json +3 -2
- package/blueprints/observability-probe-endpoints/contributions/probes/kubernetes-startup-enabled.mjs +80 -0
- package/blueprints/observability-probe-endpoints/contributions/probes/partial-profile-refusal.mjs +101 -0
- package/blueprints/observability-probe-endpoints/contributions/probes/probe-utils.mjs +49 -0
- package/blueprints/observability-probe-endpoints/contributions/probes/profile-boot-materialisation.mjs +69 -0
- package/blueprints/observability-probe-endpoints/contributions/probes/run-kubernetes-startup-enabled.mjs +3 -0
- package/blueprints/observability-probe-endpoints/contributions/probes/run-partial-profile-refusal.mjs +3 -0
- package/blueprints/observability-probe-endpoints/contributions/probes/run-profile-boot-materialisation.mjs +3 -0
- package/blueprints/observability-probe-endpoints/docs/topics.md +2 -2
- package/blueprints/persistence-data-d1/CHANGELOG.md +16 -3
- package/blueprints/persistence-data-d1/README.md +2 -2
- package/blueprints/persistence-data-d1/blueprint.json +3 -2
- package/blueprints/persistence-data-d1/contributions/adrs/adr-1404-persistence-data-d1-store-boundary.json +1 -1
- package/blueprints/persistence-data-d1/contributions/probes/facade-round-trip.mjs +140 -0
- package/blueprints/persistence-data-d1/contributions/probes/migrations-forward-only.mjs +66 -0
- package/blueprints/persistence-data-d1/contributions/probes/probe-utils.mjs +51 -0
- package/blueprints/persistence-data-d1/contributions/probes/real-account-d1-round-trip.mjs +133 -0
- package/blueprints/persistence-data-d1/contributions/probes/run-facade-round-trip.mjs +3 -0
- package/blueprints/persistence-data-d1/contributions/probes/run-migrations-forward-only.mjs +3 -0
- package/blueprints/persistence-data-d1/contributions/probes/run-real-account-d1-round-trip.mjs +3 -0
- package/blueprints/persistence-data-d1/docs/topics.md +2 -3
- package/blueprints/persistence-data-postgres/CHANGELOG.md +84 -4
- package/blueprints/persistence-data-postgres/README.md +2 -2
- package/blueprints/persistence-data-postgres/blueprint.json +3 -2
- package/blueprints/persistence-data-postgres/contributions/adrs/adr-2801-persistence-data-postgres-driver.json +1 -1
- package/blueprints/persistence-data-postgres/contributions/probes/facade-round-trip.mjs +87 -12
- package/blueprints/persistence-data-postgres/contributions/probes/migration-apply.mjs +245 -19
- package/blueprints/persistence-data-postgres/contributions/probes/pool-posture-smoke.mjs +109 -26
- package/blueprints/persistence-data-postgres/contributions/probes/prepared-statement-scan.mjs +151 -38
- package/blueprints/persistence-data-postgres/contributions/probes/probe-utils.mjs +24 -6
- package/blueprints/persistence-data-postgres/contributions/probes/recovery-restore-round-trip.mjs +261 -48
- package/blueprints/persistence-data-postgres/contributions/probes/transaction-atomicity.mjs +76 -20
- package/blueprints/persistence-data-postgres/contributions/requirements/persistence-data-postgres-req-003.json +1 -1
- package/blueprints/persistence-data-postgres/docs/topics.md +1 -1
- package/blueprints/persistence-data-sqlite/CHANGELOG.md +16 -2
- package/blueprints/persistence-data-sqlite/README.md +2 -2
- package/blueprints/persistence-data-sqlite/blueprint.json +3 -2
- package/blueprints/persistence-data-sqlite/contributions/probes/boot-open-migrate.mjs +90 -0
- package/blueprints/persistence-data-sqlite/contributions/probes/facade-round-trip.mjs +82 -0
- package/blueprints/persistence-data-sqlite/contributions/probes/probe-utils.mjs +83 -0
- package/blueprints/persistence-data-sqlite/contributions/probes/run-boot-open-migrate.mjs +5 -0
- package/blueprints/persistence-data-sqlite/contributions/probes/run-facade-round-trip.mjs +5 -0
- package/blueprints/persistence-data-sqlite/contributions/probes/run-wal-checkpoint.mjs +5 -0
- package/blueprints/persistence-data-sqlite/contributions/probes/wal-checkpoint.mjs +137 -0
- package/blueprints/persistence-data-sqlite/docs/topics.md +2 -3
- package/blueprints/platform-cloudflare-cron-triggers/CHANGELOG.md +5 -5
- package/blueprints/platform-cloudflare-cron-triggers/README.md +2 -3
- package/blueprints/platform-cloudflare-cron-triggers/docs/topics.md +1 -1
- package/blueprints/platform-cloudflare-durable-objects/CHANGELOG.md +6 -10
- package/blueprints/platform-cloudflare-durable-objects/docs/topics.md +1 -1
- package/blueprints/platform-cloudflare-kv/CHANGELOG.md +16 -12
- package/blueprints/platform-cloudflare-kv/README.md +2 -4
- package/blueprints/platform-cloudflare-kv/blueprint.json +2 -2
- package/blueprints/platform-cloudflare-kv/docs/topics.md +1 -1
- package/blueprints/platform-docker-compose-host/CHANGELOG.md +92 -5
- package/blueprints/platform-docker-compose-host/blueprint.json +2 -2
- package/blueprints/platform-docker-compose-host/contributions/probes/caddyfile-validate.mjs +116 -29
- package/blueprints/platform-docker-compose-host/contributions/probes/compose-config-lint.mjs +181 -109
- package/blueprints/platform-docker-compose-host/contributions/probes/probe-utils.mjs +146 -26
- package/blueprints/platform-docker-compose-host/contributions/probes/real-account-minimal-stack-up.mjs +238 -24
- package/blueprints/platform-docker-compose-host/contributions/probes/real-account-reload-burst.mjs +207 -21
- package/blueprints/platform-docker-compose-host/contributions/probes/secrets-as-files-scan.mjs +246 -42
- package/blueprints/platform-docker-compose-host/docs/topics.md +1 -1
- package/blueprints/security-auth-clerk/CHANGELOG.md +18 -6
- package/blueprints/security-auth-clerk/README.md +3 -3
- package/blueprints/security-auth-clerk/assets/wiring/workers-wrangler-toml-shape.md +1 -1
- package/blueprints/security-auth-clerk/blueprint.json +3 -2
- package/blueprints/security-auth-clerk/contributions/probes/hosted-identity-ui-config.mjs +61 -0
- package/blueprints/security-auth-clerk/contributions/probes/probe-utils.mjs +188 -0
- package/blueprints/security-auth-clerk/contributions/probes/real-account-principal-directory-round-trip.mjs +216 -0
- package/blueprints/security-auth-clerk/contributions/probes/real-account-session-inventory.mjs +260 -0
- package/blueprints/security-auth-clerk/contributions/probes/role-model-adapter.mjs +53 -0
- package/blueprints/security-auth-clerk/contributions/probes/run-hosted-identity-ui-config.mjs +4 -0
- package/blueprints/security-auth-clerk/contributions/probes/run-real-account-principal-directory-round-trip.mjs +4 -0
- package/blueprints/security-auth-clerk/contributions/probes/run-real-account-session-inventory.mjs +4 -0
- package/blueprints/security-auth-clerk/contributions/probes/run-role-model-adapter.mjs +4 -0
- package/blueprints/security-auth-clerk/docs/topics.md +2 -3
- package/blueprints/security-auth-keycloak/CHANGELOG.md +18 -7
- package/blueprints/security-auth-keycloak/README.md +2 -2
- package/blueprints/security-auth-keycloak/blueprint.json +3 -2
- package/blueprints/security-auth-keycloak/contributions/probes/discovery-shape.mjs +68 -0
- package/blueprints/security-auth-keycloak/contributions/probes/introspection-shape.mjs +88 -0
- package/blueprints/security-auth-keycloak/contributions/probes/jwt-verifier-shape.mjs +86 -0
- package/blueprints/security-auth-keycloak/contributions/probes/probe-utils.mjs +180 -0
- package/blueprints/security-auth-keycloak/contributions/probes/real-account-realm-round-trip.mjs +91 -0
- package/blueprints/security-auth-keycloak/contributions/probes/role-adapter-shape.mjs +69 -0
- package/blueprints/security-auth-keycloak/contributions/probes/run-discovery-shape.mjs +4 -0
- package/blueprints/security-auth-keycloak/contributions/probes/run-introspection-shape.mjs +4 -0
- package/blueprints/security-auth-keycloak/contributions/probes/run-jwt-verifier-shape.mjs +4 -0
- package/blueprints/security-auth-keycloak/contributions/probes/run-real-account-realm-round-trip.mjs +4 -0
- package/blueprints/security-auth-keycloak/contributions/probes/run-role-adapter-shape.mjs +4 -0
- package/blueprints/security-auth-keycloak/docs/topics.md +1 -2
- package/blueprints/security-auth-magic-link/CHANGELOG.md +15 -4
- package/blueprints/security-auth-magic-link/README.md +2 -2
- package/blueprints/security-auth-magic-link/assets/principal-registry-samples/single-address.md +1 -1
- package/blueprints/security-auth-magic-link/blueprint.json +3 -2
- package/blueprints/security-auth-magic-link/contributions/probes/probe-utils.mjs +174 -0
- package/blueprints/security-auth-magic-link/contributions/probes/real-account-magic-link-send.mjs +139 -0
- package/blueprints/security-auth-magic-link/contributions/probes/run-real-account-magic-link-send.mjs +4 -0
- package/blueprints/security-auth-magic-link/contributions/probes/run-token-entropy-shape.mjs +4 -0
- package/blueprints/security-auth-magic-link/contributions/probes/run-token-issue-verify.mjs +4 -0
- package/blueprints/security-auth-magic-link/contributions/probes/token-entropy-shape.mjs +60 -0
- package/blueprints/security-auth-magic-link/contributions/probes/token-issue-verify.mjs +90 -0
- package/blueprints/security-auth-magic-link/docs/topics.md +1 -1
- package/blueprints/security-auth-oauth2/CHANGELOG.md +16 -5
- package/blueprints/security-auth-oauth2/README.md +2 -2
- package/blueprints/security-auth-oauth2/blueprint.json +3 -2
- package/blueprints/security-auth-oauth2/contributions/probes/authorisation-code-flow-shape.mjs +259 -0
- package/blueprints/security-auth-oauth2/contributions/probes/pkce-challenge-shape.mjs +58 -0
- package/blueprints/security-auth-oauth2/contributions/probes/probe-utils.mjs +190 -0
- package/blueprints/security-auth-oauth2/contributions/probes/provider-adapter-shape.mjs +64 -0
- package/blueprints/security-auth-oauth2/contributions/probes/real-account-authorisation-code-flow.mjs +93 -0
- package/blueprints/security-auth-oauth2/contributions/probes/run-authorisation-code-flow-shape.mjs +4 -0
- package/blueprints/security-auth-oauth2/contributions/probes/run-pkce-challenge-shape.mjs +4 -0
- package/blueprints/security-auth-oauth2/contributions/probes/run-provider-adapter-shape.mjs +4 -0
- package/blueprints/security-auth-oauth2/contributions/probes/run-real-account-authorisation-code-flow.mjs +4 -0
- package/blueprints/security-auth-oauth2/contributions/probes/run-session-bridge-shape.mjs +4 -0
- package/blueprints/security-auth-oauth2/contributions/probes/session-bridge-shape.mjs +78 -0
- package/blueprints/security-auth-oauth2/docs/topics.md +1 -2
- package/blueprints/security-secrets-management/CHANGELOG.md +15 -4
- package/blueprints/security-secrets-management/README.md +2 -2
- package/blueprints/security-secrets-management/blueprint.json +3 -2
- package/blueprints/security-secrets-management/contributions/probes/add-recipient-rotation.mjs +107 -0
- package/blueprints/security-secrets-management/contributions/probes/encrypt-decrypt-round-trip.mjs +122 -0
- package/blueprints/security-secrets-management/contributions/probes/key-rotation.mjs +93 -0
- package/blueprints/security-secrets-management/contributions/probes/mismatched-key-refusal.mjs +74 -0
- package/blueprints/security-secrets-management/contributions/probes/probe-utils.mjs +214 -0
- package/blueprints/security-secrets-management/contributions/probes/run-add-recipient-rotation.mjs +4 -0
- package/blueprints/security-secrets-management/contributions/probes/run-encrypt-decrypt-round-trip.mjs +4 -0
- package/blueprints/security-secrets-management/contributions/probes/run-key-rotation.mjs +4 -0
- package/blueprints/security-secrets-management/contributions/probes/run-mismatched-key-refusal.mjs +4 -0
- package/blueprints/security-secrets-management/docs/topics.md +2 -3
- package/fixtures/canary-manifest.json +9 -9
- package/guidance/harness-template.md +25 -0
- package/guidance/managed/agent-instructions-block.hash +1 -1
- package/guidance/managed/agent-instructions-block.md +25 -0
- package/package.json +2 -2
- package/rcf/adrs/adr-4101-feedback-store-gitignored.json +20 -0
- package/rcf/adrs/adr-4102-fingerprint-and-labels.json +25 -0
- package/rcf/adrs/adr-4103-redaction-rule-based.json +20 -0
- package/rcf/adrs/adr-4104-destination-on-library.json +25 -0
- package/rcf/adrs/adr-4105-gh-ambient-auth.json +20 -0
- package/rcf/adrs/adr-4106-bundled-entries-terminal.json +20 -0
- package/rcf/adrs/adr-4107-stop-is-ask-event.json +30 -0
- package/rcf/adrs/adr-4108-hooks-in-committed-config.json +25 -0
- package/rcf/adrs/adr-4109-referee-validate-adr-crosslinks.json +25 -0
- package/rcf/adrs/adr-4110-referee-coverage-strict-by-default.json +25 -0
- package/rcf/adrs/adr-4111-referee-finalise-refusals.json +20 -0
- package/rcf/adrs/adr-4112-referee-finalise-verified-invariant.json +30 -0
- package/rcf/code-nodes/cn-600.json +45 -0
- package/rcf/code-nodes/cn-601.json +18 -0
- package/rcf/code-nodes/cn-602.json +15 -0
- package/rcf/code-nodes/cn-603.json +12 -0
- package/rcf/code-nodes/cn-604.json +14 -0
- package/rcf/code-nodes/cn-605.json +17 -0
- package/rcf/code-nodes/cn-606.json +12 -0
- package/rcf/code-nodes/cn-607.json +12 -0
- package/rcf/code-nodes/cn-608.json +14 -0
- package/rcf/code-nodes/cn-609.json +17 -0
- package/rcf/code-nodes/cn-620.json +18 -0
- package/rcf/code-nodes/cn-621.json +14 -0
- package/rcf/code-nodes/cn-622.json +15 -0
- package/rcf/code-nodes/cn-623.json +16 -0
- package/rcf/code-nodes/cn-624.json +14 -0
- package/rcf/code-nodes/cn-625.json +15 -0
- package/rcf/code-nodes/cn-626.json +13 -0
- package/rcf/code-nodes/cn-627.json +13 -0
- package/rcf/code-nodes/cn-628.json +14 -0
- package/rcf/code-nodes/cn-629.json +12 -0
- package/rcf/code-nodes/cn-630.json +12 -0
- package/rcf/code-nodes/cn-631.json +13 -0
- package/rcf/code-nodes/cn-632.json +13 -0
- package/rcf/fbs/fbs-180.json +45 -0
- package/rcf/fbs/fbs-181.json +45 -0
- package/rcf/fbs/fbs-182.json +42 -0
- package/rcf/fbs/fbs-183.json +50 -0
- package/rcf/fbs/fbs-184.json +49 -0
- package/rcf/fbs/fbs-185.json +34 -0
- package/rcf/fbs/fbs-186.json +16 -0
- package/rcf/fbs/fbs-187.json +17 -0
- package/rcf/fbs/fbs-188.json +17 -0
- package/rcf/fbs/fbs-189.json +17 -0
- package/rcf/requirements/req-155.json +13 -0
- package/rcf/requirements/req-156.json +13 -0
- package/rcf/requirements/req-157.json +13 -0
- package/rcf/requirements/req-158.json +13 -0
- package/rcf/requirements/req-159.json +13 -0
- package/rcf/requirements/req-160.json +13 -0
- package/rcf/requirements/req-161.json +13 -0
- package/rcf/requirements/req-162.json +13 -0
- package/rcf/requirements/req-163.json +13 -0
- package/rcf/requirements/req-164.json +13 -0
- package/rcf/requirements/req-165.json +13 -0
- package/rcf/tacs/tac-4101-feedback-cli.json +77 -0
- package/rcf/tacs/tac-4102-feedback-store.json +50 -0
- package/rcf/tacs/tac-4103-feedback-redact.json +39 -0
- package/rcf/tacs/tac-4104-feedback-fingerprint.json +33 -0
- package/rcf/tacs/tac-4105-feedback-render.json +45 -0
- package/rcf/tacs/tac-4106-feedback-destination.json +39 -0
- package/rcf/tacs/tac-4107-feedback-gh.json +43 -0
- package/rcf/tacs/tac-4108-feedback-hook.json +46 -0
- package/rcf/tacs/tac-4109-referee-validate-adr-crosslinks.json +20 -0
- package/rcf/tacs/tac-4110-referee-coverage-mode-selector.json +21 -0
- package/rcf/tacs/tac-4111-referee-finalise-per-ac-refusals.json +21 -0
- package/rcf/tacs/tac-4112-referee-finalise-verified-invariant.json +22 -0
- package/rcf/test-suites/ts-140.json +9 -9
- package/rcf/test-suites/ts-150.json +9 -9
- package/rcf/test-suites/ts-185.json +54 -0
- package/rcf/test-suites/ts-186.json +58 -0
- package/rcf/test-suites/ts-187.json +44 -0
- package/rcf/test-suites/ts-188.json +166 -0
- package/rcf/test-suites/ts-189.json +38 -0
- package/rcf/test-suites/ts-190.json +30 -0
- package/rcf/test-suites/ts-191.json +51 -0
- package/rcf/test-suites/ts-192.json +37 -0
- package/rcf/test-suites/ts-193.json +60 -0
- package/rcf/test-suites/ts-194.json +67 -0
- package/rcf/test-suites/ts-195.json +52 -0
- package/rcf/test-suites/ts-196.json +58 -0
- package/rcf/test-suites/ts-197.json +66 -0
- package/rcf/test-suites/ts-198.json +87 -0
- package/rcf/test-suites/ts-199.json +51 -0
- package/rcf/test-suites/ts-200.json +30 -0
- package/rcf/test-suites/ts-201.json +38 -0
- package/rcf/test-suites/ts-202.json +38 -0
- package/rcf/test-suites/ts-203.json +38 -0
- package/rcf/user-stories/us-15501.json +60 -0
- package/rcf/user-stories/us-15502.json +33 -0
- package/rcf/user-stories/us-15503.json +33 -0
- package/rcf/user-stories/us-15601.json +51 -0
- package/rcf/user-stories/us-15701.json +42 -0
- package/rcf/user-stories/us-15801.json +42 -0
- package/rcf/user-stories/us-15802.json +33 -0
- package/rcf/user-stories/us-15901.json +33 -0
- package/rcf/user-stories/us-15902.json +51 -0
- package/rcf/user-stories/us-16001.json +51 -0
- package/rcf/user-stories/us-16101.json +42 -0
- package/rcf/user-stories/us-16102.json +33 -0
- package/rcf/user-stories/us-16103.json +42 -0
- package/rcf/user-stories/us-16104.json +42 -0
- package/rcf/user-stories/us-16201.json +33 -0
- package/rcf/user-stories/us-16301.json +36 -0
- package/rcf/user-stories/us-16401.json +45 -0
- package/rcf/user-stories/us-16501.json +45 -0
- package/rcf/user-stories/us-16502.json +45 -0
- package/releases/releases.yaml +11 -1
- package/src/blueprint/library-loader.js +48 -0
- package/src/blueprint/library-registry.js +13 -0
- package/src/browser-verify/pack-runner.js +7 -12
- package/src/build/mark.js +1 -1
- package/src/cli/blueprint-library.js +149 -0
- package/src/cli/coverage.js +49 -24
- package/src/cli/doctor.js +195 -7
- package/src/cli/feedback.js +2204 -0
- package/src/cli/finalise.js +158 -1
- package/src/cli/help.js +6 -0
- package/src/cli/init.js +63 -0
- package/src/cli/update.js +21 -1
- package/src/core/store/walker.js +33 -0
- package/src/core/store/writer.js +23 -0
- package/src/feedback/destination.js +361 -0
- package/src/feedback/fingerprint.js +132 -0
- package/src/feedback/gh.js +376 -0
- package/src/feedback/hook.js +183 -0
- package/src/feedback/labels.js +87 -0
- package/src/feedback/redact-allowlist.json +14 -0
- package/src/feedback/redact.js +1108 -0
- package/src/feedback/render.js +267 -0
- package/src/feedback/store.js +604 -0
- package/src/finalise/index.js +4 -0
- package/src/finalise/ingest.js +61 -0
- package/src/finalise/ship-without-eval.js +19 -7
- package/src/mcp/tools.js +8 -2
- package/src/setup/feedback-hooks.js +397 -0
- package/src/setup/managed-gitignore.js +3 -0
- package/src/view/html-page.js +5 -5
- package/src/view/style.css +2 -2
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
// Correlation-id-flow probe for observability-logging.
|
|
2
|
+
//
|
|
3
|
+
// Positive-evidence shape: the probe VARIES its inputs (a distinct
|
|
4
|
+
// correlation-id supplied on an inbound HTTP request header per call)
|
|
5
|
+
// and observes the DERIVED outputs the fixture computes: the emitted
|
|
6
|
+
// log line's correlationId + a fixture-computed sequence + a hash the
|
|
7
|
+
// fixture calculates from the id and its own sequence. The response
|
|
8
|
+
// body carries the fixture-computed sequence and hash; the response
|
|
9
|
+
// header carries the id.
|
|
10
|
+
// The probe RECOMPUTES the hash locally (SHA-256(id + ":" + sequence)
|
|
11
|
+
// truncated to 16 hex chars) and asserts it equals the fixture's
|
|
12
|
+
// value. The fixture never publishes the id into a value the probe
|
|
13
|
+
// asserts against a copy of itself; the assertion is on the derived
|
|
14
|
+
// hash and the sequence's monotonic step, both of which the fixture
|
|
15
|
+
// computes from the varied input.
|
|
16
|
+
//
|
|
17
|
+
// AC-15102-1 has two clauses: (a) header present -> header value on
|
|
18
|
+
// every emitted log line for the request; (b) header absent -> the
|
|
19
|
+
// application mints a v4 UUID and the same value appears on every
|
|
20
|
+
// log line for the request. This probe exercises BOTH clauses.
|
|
21
|
+
//
|
|
22
|
+
// The nested no-context emission proves the ambient store falls back
|
|
23
|
+
// to correlationId=null when nothing set it, so the http-set path
|
|
24
|
+
// isn't a lucky coincidence with a module-level default.
|
|
25
|
+
|
|
26
|
+
import { createHash, randomUUID } from 'node:crypto';
|
|
27
|
+
import { createLogger, createLoggerHttp } from '../../../../packages/rcf-lite/test/fixtures/probe-pack-observability-logging/src/logger-factory.mjs';
|
|
28
|
+
|
|
29
|
+
export const anchorAcId = 'AC-15102-1';
|
|
30
|
+
export const accountBound = false;
|
|
31
|
+
const AC1 = 'A request arriving with the elicited correlation header';
|
|
32
|
+
const AC3 = 'A log emission with no ambient correlation context';
|
|
33
|
+
|
|
34
|
+
const HEADER = 'X-Correlation-Id';
|
|
35
|
+
const UUID_V4_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
36
|
+
|
|
37
|
+
function expectedHash(id, sequence) {
|
|
38
|
+
return createHash('sha256').update(`${id}:${sequence}`).digest('hex').slice(0, 16);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export default async function runProbe() {
|
|
42
|
+
const outBuf = [];
|
|
43
|
+
const logger = createLogger({ environment: 'qa', serviceName: 'probe-svc', serviceVersion: '0.0.1', outSink: (s) => outBuf.push(s), errSink: () => {} });
|
|
44
|
+
const http = createLoggerHttp({ headerName: HEADER.toLowerCase(), logger });
|
|
45
|
+
const { port } = await http.listen(0);
|
|
46
|
+
const results = [];
|
|
47
|
+
const inputIds = [randomUUID(), randomUUID(), randomUUID()];
|
|
48
|
+
const observed = [];
|
|
49
|
+
try {
|
|
50
|
+
for (const inbound of inputIds) {
|
|
51
|
+
const res = await fetch(`http://127.0.0.1:${port}/hello`, {
|
|
52
|
+
method: 'POST',
|
|
53
|
+
headers: { [HEADER]: inbound, 'content-type': 'text/plain' },
|
|
54
|
+
body: 'body-' + inbound.slice(0, 4),
|
|
55
|
+
});
|
|
56
|
+
const bodyText = await res.text();
|
|
57
|
+
let body = null; try { body = JSON.parse(bodyText); } catch {}
|
|
58
|
+
observed.push({
|
|
59
|
+
supplied: inbound,
|
|
60
|
+
headerEcho: res.headers.get(HEADER.toLowerCase()),
|
|
61
|
+
bodySequence: body?.sequence,
|
|
62
|
+
bodyHash: body?.hash,
|
|
63
|
+
bodyCorrelationId: body?.correlationId,
|
|
64
|
+
bodyMintedFromAbsent: body?.mintedFromAbsent,
|
|
65
|
+
status: res.status,
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
const emittedLines = outBuf.join('').split('\n').filter(Boolean).map((l) => JSON.parse(l));
|
|
69
|
+
|
|
70
|
+
for (let i = 0; i < inputIds.length; i++) {
|
|
71
|
+
const supplied = inputIds[i];
|
|
72
|
+
const o = observed[i];
|
|
73
|
+
const line = emittedLines.find((l) => l.correlationId === supplied && l.sequence === o.bodySequence);
|
|
74
|
+
const localHash = (typeof o.bodySequence === 'number') ? expectedHash(supplied, o.bodySequence) : null;
|
|
75
|
+
const lineOk = Boolean(line) && line.hash === localHash;
|
|
76
|
+
const bodyOk = o.status === 200 && typeof o.bodySequence === 'number' && o.bodyHash === localHash && o.bodyMintedFromAbsent === false;
|
|
77
|
+
const headerOk = o.headerEcho === supplied;
|
|
78
|
+
results.push({
|
|
79
|
+
anchorAcId: 'AC-15102-1',
|
|
80
|
+
verdict: lineOk && bodyOk && headerOk ? 'pass' : 'fail',
|
|
81
|
+
detail: `${AC1} - observed supplied inbound '${HEADER}'='${supplied}' -> line.correlationId='${line?.correlationId}' sequence=${line?.sequence} line.hash='${line?.hash}' locallyRecomputedHash='${localHash}' body.sequence=${o.bodySequence} body.hash='${o.bodyHash}' header='${o.headerEcho}' mintedFromAbsent=${o.bodyMintedFromAbsent}; observes AC-15102-1 header-present clause via header echo and derived hash equality.`,
|
|
82
|
+
evidence: {
|
|
83
|
+
suppliedInput: supplied,
|
|
84
|
+
derivedLogLine: line ? { message: line.message, correlationId: line.correlationId, path: line.path, sequence: line.sequence, hash: line.hash } : null,
|
|
85
|
+
derivedResponseHeader: o.headerEcho,
|
|
86
|
+
derivedResponseBodySequence: o.bodySequence,
|
|
87
|
+
derivedResponseBodyHash: o.bodyHash,
|
|
88
|
+
locallyRecomputedHash: localHash,
|
|
89
|
+
responseStatus: o.status,
|
|
90
|
+
},
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// AC-15102-1 header-absent clause: send with no correlation header,
|
|
95
|
+
// observe the fixture mints a v4 UUID and the same value appears on
|
|
96
|
+
// the emitted log line.
|
|
97
|
+
const absentRes = await fetch(`http://127.0.0.1:${port}/hello`, {
|
|
98
|
+
method: 'POST',
|
|
99
|
+
headers: { 'content-type': 'text/plain' },
|
|
100
|
+
body: 'no-header-body',
|
|
101
|
+
});
|
|
102
|
+
const absentBodyText = await absentRes.text();
|
|
103
|
+
let absentBody = null; try { absentBody = JSON.parse(absentBodyText); } catch {}
|
|
104
|
+
const mintedId = absentBody?.correlationId ?? '';
|
|
105
|
+
const mintedIsV4 = UUID_V4_RE.test(mintedId);
|
|
106
|
+
const echoedInHeader = absentRes.headers.get(HEADER.toLowerCase());
|
|
107
|
+
const linesAfter = outBuf.join('').split('\n').filter(Boolean).map((l) => JSON.parse(l));
|
|
108
|
+
const absentLine = linesAfter.find((l) => l.correlationId === mintedId && l.sequence === absentBody?.sequence);
|
|
109
|
+
const absentOk = absentRes.status === 200
|
|
110
|
+
&& mintedIsV4
|
|
111
|
+
&& absentBody?.mintedFromAbsent === true
|
|
112
|
+
&& echoedInHeader === mintedId
|
|
113
|
+
&& Boolean(absentLine);
|
|
114
|
+
results.push({
|
|
115
|
+
anchorAcId: 'AC-15102-1',
|
|
116
|
+
verdict: absentOk ? 'pass' : 'fail',
|
|
117
|
+
detail: `${AC1} - observed inbound with NO '${HEADER}' header -> body.correlationId='${mintedId}' (v4?${mintedIsV4}) mintedFromAbsent=${absentBody?.mintedFromAbsent} header echo='${echoedInHeader}' log-line.correlationId='${absentLine?.correlationId}' sequence=${absentLine?.sequence}; observes AC-15102-1 header-absent clause via minted v4 UUID appearing on the emitted line.`,
|
|
118
|
+
evidence: {
|
|
119
|
+
// No header supplied on this request; the fixture mints a v4
|
|
120
|
+
// UUID and echoes it verbatim on the response header, the
|
|
121
|
+
// response body and the emitted log line. The minted id is
|
|
122
|
+
// recorded as a request id (engine-minted lane) because it is
|
|
123
|
+
// the engine's response identifier, not a probe-supplied
|
|
124
|
+
// input; a bare `suppliedInput` sentinel would break the
|
|
125
|
+
// identifier-pairing equality rule.
|
|
126
|
+
requestId: mintedId,
|
|
127
|
+
absentSuppliedInput: true,
|
|
128
|
+
derivedLogLine: absentLine ? { message: absentLine.message, correlationId: absentLine.correlationId, path: absentLine.path, sequence: absentLine.sequence, hash: absentLine.hash } : null,
|
|
129
|
+
derivedResponseHeader: echoedInHeader,
|
|
130
|
+
derivedResponseBodySequence: absentBody?.sequence,
|
|
131
|
+
derivedResponseBodyHash: absentBody?.hash,
|
|
132
|
+
responseStatus: absentRes.status,
|
|
133
|
+
mintedFromAbsent: absentBody?.mintedFromAbsent,
|
|
134
|
+
mintedIsV4,
|
|
135
|
+
},
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
const seqs = observed.map((o) => o.bodySequence);
|
|
139
|
+
const monotonic = seqs.every((n, i) => typeof n === 'number' && (i === 0 || n === seqs[i - 1] + 1));
|
|
140
|
+
results.push({
|
|
141
|
+
anchorAcId: null,
|
|
142
|
+
conformanceOnly: true,
|
|
143
|
+
limitation: 'AC-15102-1: concerns the correlation ID travelling from the inbound header (or minted UUID) to every emitted log line during the request. Sequence monotonicity is anti-echo signalling that the fixture computes derived state; it is not the AC-15102-1 property.',
|
|
144
|
+
verdict: monotonic ? 'pass' : 'fail',
|
|
145
|
+
detail: `observed fixture per-server sequence as ${JSON.stringify(seqs)}; monotonic step of 1 (anti-echo signal that fixture computes derived state).`,
|
|
146
|
+
evidence: { suppliedInputs: inputIds, derivedSequences: seqs, derivedResponseHeader: observed[0]?.headerEcho, suppliedInput: inputIds[0], bodyExcerpt: 'seq=' + JSON.stringify(seqs) },
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
outBuf.length = 0;
|
|
150
|
+
logger.info('bare');
|
|
151
|
+
const bare = JSON.parse(outBuf.join('').split('\n').filter(Boolean)[0]);
|
|
152
|
+
results.push({
|
|
153
|
+
anchorAcId: null,
|
|
154
|
+
conformanceOnly: true,
|
|
155
|
+
limitation: `AC-15102-3: the bare emission with no ambient correlation context is a single emitted log line whose only recorded value is the null correlationId itself. The row observes the property but carries no request or resource identifier the engine returned; identifier-plus-derived evidence is not available here (the strict-evidence contract tightening).`,
|
|
156
|
+
verdict: bare.correlationId === null ? 'pass' : 'fail',
|
|
157
|
+
detail: `${AC3} - observed bare emission (no runWithCorrelation) carries correlationId=${JSON.stringify(bare.correlationId)} (expected null per AC-15102-3); de-claimed to conformanceOnly per the strict-evidence contract because no engine-returned identifier is available for a bare emission.`,
|
|
158
|
+
evidence: { bareLineCorrelationId: bare.correlationId, bodyExcerpt: JSON.stringify(bare).slice(0, 200) },
|
|
159
|
+
});
|
|
160
|
+
} finally {
|
|
161
|
+
await http.close();
|
|
162
|
+
}
|
|
163
|
+
return {
|
|
164
|
+
results,
|
|
165
|
+
extra: {
|
|
166
|
+
envDeclared: ['RCF_FIXTURE_LOGGER_CORRELATION_HEADER'],
|
|
167
|
+
headerName: HEADER,
|
|
168
|
+
port,
|
|
169
|
+
variedInputs: inputIds,
|
|
170
|
+
observedRoundTrips: observed,
|
|
171
|
+
},
|
|
172
|
+
};
|
|
173
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
// Line-shape probe for observability-logging.
|
|
2
|
+
// Anchors AC-15101-1 (with the row extended to type-check each of the
|
|
3
|
+
// shared minimum fields, so a numeric or object value cannot pass a
|
|
4
|
+
// presence-only check), AC-15101-3 (BigInt-safe folding) and
|
|
5
|
+
// AC-15101-4 (reserved-key collision safety).
|
|
6
|
+
import { randomUUID } from 'node:crypto';
|
|
7
|
+
import { createLogger, LEVEL_ORDER, runWithCorrelation } from '../../../../packages/rcf-lite/test/fixtures/probe-pack-observability-logging/src/logger-factory.mjs';
|
|
8
|
+
|
|
9
|
+
export const anchorAcId = 'AC-15101-1';
|
|
10
|
+
export const accountBound = false;
|
|
11
|
+
const AC1 = 'A log emission at any level from any';
|
|
12
|
+
const AC3 = 'A log emission whose payload contains a BigInt';
|
|
13
|
+
const AC4 = 'The seven shared minimum fields (message, level, timestamp,';
|
|
14
|
+
|
|
15
|
+
export default async function runProbe() {
|
|
16
|
+
const outBuf = []; const errBuf = [];
|
|
17
|
+
const clock = () => '2026-09-11T12:00:00.000Z';
|
|
18
|
+
const log = createLogger({ environment: 'qa', serviceName: 'probe-svc', serviceVersion: '0.0.1', minLevel: 'trace', outSink: (s) => outBuf.push(s), errSink: (s) => errBuf.push(s), clock });
|
|
19
|
+
const perLevelIds = [];
|
|
20
|
+
for (const lvl of LEVEL_ORDER) {
|
|
21
|
+
const cid = randomUUID();
|
|
22
|
+
perLevelIds.push({ level: lvl, correlationId: cid });
|
|
23
|
+
runWithCorrelation(cid, () => log[lvl](`hello-${lvl}`));
|
|
24
|
+
}
|
|
25
|
+
const lines = outBuf.join('').split('\n').filter(Boolean);
|
|
26
|
+
const required = ['message', 'level', 'timestamp', 'correlationId', 'environment', 'serviceName', 'serviceVersion'];
|
|
27
|
+
const results = [];
|
|
28
|
+
const parsed = [];
|
|
29
|
+
let allOk = lines.length === LEVEL_ORDER.length;
|
|
30
|
+
let typeFailures = [];
|
|
31
|
+
for (const ln of lines) {
|
|
32
|
+
let obj = null; let ok = true;
|
|
33
|
+
try { obj = JSON.parse(ln); } catch { ok = false; }
|
|
34
|
+
parsed.push(obj);
|
|
35
|
+
if (!ok) { allOk = false; continue; }
|
|
36
|
+
for (const k of required) {
|
|
37
|
+
if (!(k in obj)) { allOk = false; typeFailures.push({ key: k, reason: 'missing' }); continue; }
|
|
38
|
+
// correlationId is explicitly nullable when the emission has no
|
|
39
|
+
// ambient correlation context (AC-15102-3). Every other field
|
|
40
|
+
// must be a non-empty string.
|
|
41
|
+
if (k === 'correlationId') {
|
|
42
|
+
if (obj[k] !== null && (typeof obj[k] !== 'string' || obj[k].length === 0)) { allOk = false; typeFailures.push({ key: k, reason: `correlationId must be null or non-empty string (got ${typeof obj[k]})` }); }
|
|
43
|
+
} else if (typeof obj[k] !== 'string' || obj[k].length === 0) {
|
|
44
|
+
allOk = false; typeFailures.push({ key: k, reason: `not-non-empty-string (got ${typeof obj[k]})` });
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
// timestamp additionally must ISO-8601 parse.
|
|
48
|
+
if (typeof obj.timestamp === 'string' && Number.isNaN(Date.parse(obj.timestamp))) { allOk = false; typeFailures.push({ key: 'timestamp', reason: 'not ISO-8601 parseable' }); }
|
|
49
|
+
}
|
|
50
|
+
results.push({
|
|
51
|
+
anchorAcId: 'AC-15101-1',
|
|
52
|
+
verdict: allOk ? 'pass' : 'fail',
|
|
53
|
+
detail: `${AC1} call site - observed ${lines.length} lines on stdout; each JSON.parses and carries the seven minimum fields as non-empty strings (timestamp parses ISO-8601); expected=${LEVEL_ORDER.length}; typeFailures=${JSON.stringify(typeFailures)}.`,
|
|
54
|
+
evidence: { linesExcerpt: lines.slice(0, 3), levelsSeen: parsed.filter(Boolean).map((o) => o.level), typeFailures, observedEmissions: perLevelIds, suppliedInput: perLevelIds[0]?.correlationId, line: parsed[0] },
|
|
55
|
+
});
|
|
56
|
+
outBuf.length = 0; errBuf.length = 0;
|
|
57
|
+
const bigCid = randomUUID();
|
|
58
|
+
runWithCorrelation(bigCid, () => log.info('bigint', { id: 9007199254740993n }));
|
|
59
|
+
const bLines = outBuf.join('').split('\n').filter(Boolean);
|
|
60
|
+
let bParsed = null;
|
|
61
|
+
try { bParsed = JSON.parse(bLines[0]); } catch {}
|
|
62
|
+
results.push({
|
|
63
|
+
anchorAcId: 'AC-15101-3',
|
|
64
|
+
verdict: bParsed && bParsed.id === '9007199254740993' && errBuf.join('').length === 0 ? 'pass' : 'fail',
|
|
65
|
+
detail: `${AC3} value - observed BigInt folded to '${bParsed?.id}' on the emitted line; stderr='${errBuf.join('').trim()}'.`,
|
|
66
|
+
evidence: { line: bParsed, bodyExcerpt: bLines[0], suppliedInput: bigCid },
|
|
67
|
+
});
|
|
68
|
+
outBuf.length = 0; errBuf.length = 0;
|
|
69
|
+
const collCid = randomUUID();
|
|
70
|
+
runWithCorrelation(collCid, () => log.info('coll', { level: 'boom', timestamp: 'yesterday', custom: 'ok' }));
|
|
71
|
+
const cLine = outBuf.join('').split('\n').filter(Boolean)[0];
|
|
72
|
+
let cParsed = null;
|
|
73
|
+
try { cParsed = JSON.parse(cLine); } catch {}
|
|
74
|
+
const errCombined = errBuf.join('');
|
|
75
|
+
results.push({
|
|
76
|
+
anchorAcId: 'AC-15101-4',
|
|
77
|
+
verdict: cParsed?.level === 'info' && cParsed?.timestamp === '2026-09-11T12:00:00.000Z' && errCombined.includes("'level'") && errCombined.includes("'timestamp'") ? 'pass' : 'fail',
|
|
78
|
+
detail: `${AC4} correlationId, - observed factory-authored level=${cParsed?.level} timestamp=${cParsed?.timestamp}; stderr excerpt='${errCombined.trim()}' names the reserved keys.`,
|
|
79
|
+
evidence: { line: cParsed, bodyExcerpt: cLine, stderr: errCombined, suppliedInput: collCid },
|
|
80
|
+
});
|
|
81
|
+
return { results, extra: { envDeclared: ['RCF_FIXTURE_LOGGER_CORRELATION_HEADER'], capturedStdoutBytes: outBuf.reduce((n, s) => n + s.length, 0) } };
|
|
82
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
// Shared helpers for observability-logging probes.
|
|
2
|
+
import { mkdir, writeFile } from 'node:fs/promises';
|
|
3
|
+
import { dirname, resolve } from 'node:path';
|
|
4
|
+
import { fileURLToPath } from 'node:url';
|
|
5
|
+
|
|
6
|
+
const HERE = dirname(fileURLToPath(import.meta.url));
|
|
7
|
+
export const PROJECT_ROOT = resolve(HERE, '..', '..', '..', '..');
|
|
8
|
+
export const FIXTURE_DIR = resolve(PROJECT_ROOT, 'packages/rcf-lite/test/fixtures/probe-pack-observability-logging');
|
|
9
|
+
export const REPORT_DIR = resolve(PROJECT_ROOT, '.rcf/reports/blueprints/observability-logging');
|
|
10
|
+
export const DECLARED_ENV = new Set(['RCF_FIXTURE_LOGGER_CORRELATION_HEADER']);
|
|
11
|
+
|
|
12
|
+
export function aggregate(results) {
|
|
13
|
+
if (!Array.isArray(results) || results.length === 0) return 'fail';
|
|
14
|
+
if (results.some((r) => r.verdict === 'fail')) return 'fail';
|
|
15
|
+
if (results.some((r) => r.verdict === 'warn')) return 'warn';
|
|
16
|
+
return 'pass';
|
|
17
|
+
}
|
|
18
|
+
export function isSkipped(results) { return Array.isArray(results) && results.length > 0 && results.every((r) => r.accountBoundSkipped === true); }
|
|
19
|
+
export async function writeReport({ probeName, engine, results, extra }) {
|
|
20
|
+
await mkdir(REPORT_DIR, { recursive: true });
|
|
21
|
+
const normalised = (Array.isArray(results) && results.length > 0)
|
|
22
|
+
? results
|
|
23
|
+
: [{ anchorAcId: null, harnessError: true, verdict: 'fail', detail: 'no checks ran', evidence: { reason: 'no checks ran', probeName, runAt: new Date().toISOString(), engine } }];
|
|
24
|
+
const raw = aggregate(normalised);
|
|
25
|
+
const aggregateVerdict = isSkipped(normalised) ? 'pass' : raw;
|
|
26
|
+
const report = { slug: 'observability-logging', probeName, runAt: new Date().toISOString(), engine, results: normalised, aggregateVerdict, ...(extra ?? {}) };
|
|
27
|
+
const path = resolve(REPORT_DIR, `${probeName}.json`);
|
|
28
|
+
await writeFile(path, JSON.stringify(report, null, 2) + '\n', 'utf8');
|
|
29
|
+
return { report, path };
|
|
30
|
+
}
|
|
31
|
+
export async function runShim(probeName, engine, mainFn) {
|
|
32
|
+
try {
|
|
33
|
+
const outcome = (await mainFn()) ?? { results: [] };
|
|
34
|
+
const { results, extra } = outcome;
|
|
35
|
+
const { report, path } = await writeReport({ probeName, engine, results, extra });
|
|
36
|
+
process.stdout.write(JSON.stringify(report, null, 2) + '\n');
|
|
37
|
+
process.stdout.write(`report written to ${path}\n`);
|
|
38
|
+
if (report.aggregateVerdict === 'fail') process.exitCode = 1;
|
|
39
|
+
} catch (err) {
|
|
40
|
+
const results = [{ anchorAcId: null, harnessError: true, verdict: 'fail', detail: `probe threw: ${err?.message ?? err}`, evidence: { thrown: true, message: err?.message ?? String(err), name: err?.name ?? 'Error', probeName, runAt: new Date().toISOString(), engine } }];
|
|
41
|
+
const { report, path } = await writeReport({ probeName, engine, results });
|
|
42
|
+
process.stdout.write(JSON.stringify(report, null, 2) + '\n');
|
|
43
|
+
process.stderr.write(`probe error: ${err?.stack ?? err}\n`);
|
|
44
|
+
process.stderr.write(`report written to ${path}\n`);
|
|
45
|
+
process.exitCode = 1;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
// Redaction-boundary probe for observability-logging.
|
|
2
|
+
//
|
|
3
|
+
// Emits one payload per recommended-default category (credential,
|
|
4
|
+
// token, bearer, pii.email, pii.name, pii.address) inside its own
|
|
5
|
+
// runWithCorrelation(randomUUID(), ...) so each emission carries a
|
|
6
|
+
// real, per-emission correlation id. For each category the probe
|
|
7
|
+
// records the supplied correlation id, the emitted line's correlation
|
|
8
|
+
// id (proving pairing on the wire), the redacted field value and the
|
|
9
|
+
// caller-payload-unmutated observation - anchoring AC-15103-1 for
|
|
10
|
+
// every one of the six mandatory categories the AC names.
|
|
11
|
+
//
|
|
12
|
+
// AC-15103-4 requires the SPECIFIC shape `{ user: { id: "u-1",
|
|
13
|
+
// pii: { email: "a@b" } } }` with `user.id` PRESERVED and
|
|
14
|
+
// `user.pii.email` redacted. That emission is a separate row anchored
|
|
15
|
+
// on AC-15103-4, again with a per-emission correlation id paired to
|
|
16
|
+
// the emitted line.
|
|
17
|
+
//
|
|
18
|
+
// AC-15103-3 (unrecognised category left unredacted) requires a
|
|
19
|
+
// specifically-shaped `custom.internal.token`-style field name. A
|
|
20
|
+
// bare `note` field does not exercise the "valid-but-unconfigured
|
|
21
|
+
// kebab/dotted grammar" the AC names. Row de-claimed with the
|
|
22
|
+
// limitation naming AC-15103-3.
|
|
23
|
+
import { randomUUID } from 'node:crypto';
|
|
24
|
+
import { createLogger, runWithCorrelation } from '../../../../packages/rcf-lite/test/fixtures/probe-pack-observability-logging/src/logger-factory.mjs';
|
|
25
|
+
|
|
26
|
+
export const anchorAcId = 'AC-15103-1';
|
|
27
|
+
export const accountBound = false;
|
|
28
|
+
const AC1 = 'A log payload containing a field named or';
|
|
29
|
+
const AC4 = 'The redaction boundary reads a nested payload path:';
|
|
30
|
+
const AC3_LIM_NOTE = `AC-15103-3: requires a valid-but-unconfigured category name (kebab or dotted-namespace grammar), e.g. custom.internal.token, that looks like a redaction path but is not in defaults or additions. A bare field name 'note' with no category-shaped label does not exercise the AC's grammar constraint.`;
|
|
31
|
+
|
|
32
|
+
function deepClone(v) { return JSON.parse(JSON.stringify(v)); }
|
|
33
|
+
function sameShape(a, b) { return JSON.stringify(a) === JSON.stringify(b); }
|
|
34
|
+
|
|
35
|
+
const CATEGORIES = [
|
|
36
|
+
{ path: 'credential', build: () => ({ credential: 'SAMPLE_CRED_VALUE' }), read: (l) => l.credential, expected: '[REDACTED:credential]' },
|
|
37
|
+
{ path: 'token', build: () => ({ token: 'SAMPLE_TOKEN_VALUE' }), read: (l) => l.token, expected: '[REDACTED:token]' },
|
|
38
|
+
{ path: 'bearer', build: () => ({ bearer: 'SAMPLE_BEARER_VALUE' }), read: (l) => l.bearer, expected: '[REDACTED:bearer]' },
|
|
39
|
+
{ path: 'pii.email', build: () => ({ pii: { email: 'sample@example.com' } }), read: (l) => l.pii?.email, expected: '[REDACTED:pii.email]' },
|
|
40
|
+
{ path: 'pii.name', build: () => ({ pii: { name: 'Sample Person' } }), read: (l) => l.pii?.name, expected: '[REDACTED:pii.name]' },
|
|
41
|
+
{ path: 'pii.address', build: () => ({ pii: { address: '1 Sample St' } }), read: (l) => l.pii?.address, expected: '[REDACTED:pii.address]' },
|
|
42
|
+
];
|
|
43
|
+
|
|
44
|
+
export default async function runProbe() {
|
|
45
|
+
const outBuf = [];
|
|
46
|
+
const log = createLogger({ environment: 'qa', serviceName: 'probe-svc', serviceVersion: '0.0.1', outSink: (s) => outBuf.push(s), errSink: () => {} });
|
|
47
|
+
const results = [];
|
|
48
|
+
const emittedCategoryLines = [];
|
|
49
|
+
|
|
50
|
+
for (const cat of CATEGORIES) {
|
|
51
|
+
outBuf.length = 0;
|
|
52
|
+
const payload = cat.build();
|
|
53
|
+
const beforePayload = deepClone(payload);
|
|
54
|
+
const supplied = randomUUID();
|
|
55
|
+
await runWithCorrelation(supplied, async () => { log.info(`redact-${cat.path}`, payload); });
|
|
56
|
+
const emitted = JSON.parse(outBuf.join('').split('\n').filter(Boolean)[0]);
|
|
57
|
+
emittedCategoryLines.push({ path: cat.path, supplied, emitted });
|
|
58
|
+
const got = cat.read(emitted);
|
|
59
|
+
const payloadUnmutated = sameShape(payload, beforePayload);
|
|
60
|
+
const paired = emitted.correlationId === supplied;
|
|
61
|
+
results.push({
|
|
62
|
+
anchorAcId: 'AC-15103-1',
|
|
63
|
+
verdict: got === cat.expected && payloadUnmutated && paired ? 'pass' : 'fail',
|
|
64
|
+
detail: `${AC1} - category '${cat.path}': supplied correlationId='${supplied}' -> emitted line.correlationId='${emitted.correlationId}' (paired=${paired}); field value on line='${got}' (expect '${cat.expected}'); caller payload unmutated=${payloadUnmutated}. Observes both AC-15103-1 clauses (redacted output AND caller object not mutated) for this category.`,
|
|
65
|
+
evidence: {
|
|
66
|
+
path: cat.path,
|
|
67
|
+
suppliedInput: supplied,
|
|
68
|
+
derivedResponseHeader: emitted.correlationId,
|
|
69
|
+
valueOnLine: got,
|
|
70
|
+
payloadUnmutated,
|
|
71
|
+
line: { correlationId: emitted.correlationId, level: emitted.level, message: emitted.message },
|
|
72
|
+
bodyExcerpt: JSON.stringify(emitted).slice(0, 300),
|
|
73
|
+
},
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// AC-15103-3 negative-control: a plain 'note' field with no category
|
|
78
|
+
// grammar passes through unredacted. Emitted in its own correlation
|
|
79
|
+
// context but only observed against AC-15103-3 (which requires the
|
|
80
|
+
// dotted-namespace grammar this row does not exercise) so it stays
|
|
81
|
+
// de-claimed to conformanceOnly.
|
|
82
|
+
outBuf.length = 0;
|
|
83
|
+
const notePayload = { note: 'this stays' };
|
|
84
|
+
const noteSupplied = randomUUID();
|
|
85
|
+
await runWithCorrelation(noteSupplied, async () => { log.info('note-passthrough', notePayload); });
|
|
86
|
+
const noteLine = JSON.parse(outBuf.join('').split('\n').filter(Boolean)[0]);
|
|
87
|
+
results.push({
|
|
88
|
+
anchorAcId: null,
|
|
89
|
+
conformanceOnly: true,
|
|
90
|
+
limitation: AC3_LIM_NOTE,
|
|
91
|
+
verdict: noteLine.note === 'this stays' && noteLine.correlationId === noteSupplied ? 'pass' : 'fail',
|
|
92
|
+
detail: `observed negative-control top-level field 'note'='${noteLine.note}' (no category tag at all -- passes through unredacted); supplied correlationId='${noteSupplied}' -> emitted line.correlationId='${noteLine.correlationId}'.`,
|
|
93
|
+
evidence: { note: noteLine.note, valueOnLine: noteLine.note, line: { correlationId: noteLine.correlationId, level: noteLine.level, message: noteLine.message, note: noteLine.note } },
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
// AC-15103-4-shaped emission: { user: { id: 'u-1', pii: { email: 'a@b' } } }.
|
|
97
|
+
outBuf.length = 0;
|
|
98
|
+
const acShapedPayload = { user: { id: 'u-1', pii: { email: 'a@b' } } };
|
|
99
|
+
const acShapedBefore = deepClone(acShapedPayload);
|
|
100
|
+
const acShapedSupplied = randomUUID();
|
|
101
|
+
await runWithCorrelation(acShapedSupplied, async () => { log.info('ac-15103-4-shape', acShapedPayload); });
|
|
102
|
+
const acShapedUnmutated = sameShape(acShapedPayload, acShapedBefore);
|
|
103
|
+
const acShapedLine = JSON.parse(outBuf.join('').split('\n').filter(Boolean)[0]);
|
|
104
|
+
const emailRedactedOk = acShapedLine.user?.pii?.email === '[REDACTED:pii.email]';
|
|
105
|
+
const idPreservedOk = acShapedLine.user?.id === 'u-1';
|
|
106
|
+
const acShapedPaired = acShapedLine.correlationId === acShapedSupplied;
|
|
107
|
+
results.push({
|
|
108
|
+
anchorAcId: 'AC-15103-4',
|
|
109
|
+
verdict: emailRedactedOk && idPreservedOk && acShapedUnmutated && acShapedPaired ? 'pass' : 'fail',
|
|
110
|
+
detail: `${AC4} - observed emitted line with payload { user: { id: 'u-1', pii: { email: 'a@b' } } }: user.id='${acShapedLine.user?.id}' (expect 'u-1' PRESERVED); user.pii.email='${acShapedLine.user?.pii?.email}' (expect '[REDACTED:pii.email]'); acShapedPayload unmutated=${acShapedUnmutated}; supplied correlationId='${acShapedSupplied}' -> emitted line.correlationId='${acShapedLine.correlationId}' (paired=${acShapedPaired}).`,
|
|
111
|
+
evidence: {
|
|
112
|
+
suppliedInput: acShapedSupplied,
|
|
113
|
+
derivedResponseHeader: acShapedLine.correlationId,
|
|
114
|
+
userIdOnLine: acShapedLine.user?.id,
|
|
115
|
+
userPiiEmailOnLine: acShapedLine.user?.pii?.email,
|
|
116
|
+
acShapedUnmutated,
|
|
117
|
+
line: { correlationId: acShapedLine.correlationId, level: acShapedLine.level, message: acShapedLine.message, user: acShapedLine.user },
|
|
118
|
+
},
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
return {
|
|
122
|
+
results,
|
|
123
|
+
extra: {
|
|
124
|
+
envDeclared: ['RCF_FIXTURE_LOGGER_CORRELATION_HEADER'],
|
|
125
|
+
categoriesObserved: emittedCategoryLines.map((c) => ({ path: c.path, supplied: c.supplied, emittedCorrelationId: c.emitted.correlationId, valueOnLine: c.path.includes('.') ? c.emitted.pii?.[c.path.split('.')[1]] : c.emitted[c.path] })),
|
|
126
|
+
acShapedExcerpt: acShapedLine,
|
|
127
|
+
acShapedUnmutated,
|
|
128
|
+
},
|
|
129
|
+
};
|
|
130
|
+
}
|
|
@@ -1,17 +1,32 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 1.2.5 - 2026-09-11
|
|
4
|
+
|
|
5
|
+
Anatomy suite tracks the strengthened shared helper (WARN-only shortcut removed, log objects and content lists no longer identifiers, retained anchor existence check). No probe changes required.
|
|
6
|
+
|
|
7
|
+
## 1.2.4 - 2026-09-11
|
|
8
|
+
|
|
9
|
+
shared anatomy helper tightened; probe-endpoints anatomy test passes shippedAcIds and browserOnlyAcIds into the helper and additionally checks every accountBoundSkipped row names exactly one declared env variable.
|
|
10
|
+
|
|
1
11
|
# observability-probe-endpoints CHANGELOG
|
|
2
12
|
|
|
13
|
+
## 1.2.3 - 2026-09-11
|
|
14
|
+
|
|
15
|
+
Adds a contributions/probes/ pack (profile-boot-materialisation, kubernetes-startup-enabled, partial-profile-refusal) with a fixture-side profile registry and HTTP materialiser under packages/rcf-lite/test/fixtures/probe-pack-observability-probe-endpoints/. Probes run against the fixture on Node 24. No account gate.
|
|
16
|
+
|
|
17
|
+
Anchoring: kubernetes-startup-enabled anchors AC-14102-4 with BOTH the enabled clause (three-path resolution; pre-ready GET /startup answers HTTP 503 body.status='fail'; post-markStartupReady GET answers HTTP 200 body.status='pass') AND the disabled clause (no enable flag: resolver returns two paths, GET /startup returns 404 with no /startup handler registered). profile-boot-materialisation observes bound-path behaviour for /live and /ready under the shipped kubernetes profile; the row de-claims (conformanceOnly, anchorAcId=null) with the limitation naming AC-14101-1 (port topology and handler-absence not observed). partial-profile-refusal observes an in-process refuseIfPartial refusal (stripped transport; startupEnabled without paths.startup) with the row de-claiming AC-14103-2 (process-level non-zero exit not observed at shelf); the shape presence check for the six shipped profiles de-claims AC-14103-1 (enum-membership per field not observed); the loadBalancer profile shape row de-claims AC-14103-3 (profile is not materialised and probed for handler absence). probe-utils normalisation and thrown-error rows carry an evidence object; the fallback anchorAcId is null.
|
|
18
|
+
|
|
3
19
|
## 1.2.1 (register-sweep patch, 2026-09-10)
|
|
4
20
|
|
|
5
21
|
- Register: neutral wording in shipped prose (no capability change).
|
|
6
22
|
|
|
7
|
-
## 1.2.0 (
|
|
23
|
+
## 1.2.0 (2026-09-09)
|
|
8
24
|
|
|
9
25
|
- Adds `elicits[]` with four apply-time answers: `probe-interface-profile` (enum kubernetes/loadBalancer/uptimeMonitor/systemd/dockerHealthcheck/reverseProxy/custom, default kubernetes; REQ-001), `probe-paths-override` (string JSON; REQ-002/003), `probe-listener-separate-port` (string; REQ-004), `kubernetes-startup-enabled` (enum off/on, default off; ADR-1503). Every option value is backed by a must-priority REQ description.
|
|
10
|
-
- Adds `deliveredBy` to every REQ (REQ-001-008 -> TAC-1501/1502/1503/1504 interface names; REQ-006 -> ADR-1505).
|
|
11
|
-
-
|
|
12
|
-
-
|
|
13
|
-
-
|
|
14
|
-
-
|
|
15
|
-
-
|
|
26
|
+
- Adds `deliveredBy` to every REQ (REQ-001-008 -> TAC-1501/1502/1503/1504 interface names; REQ-006 -> ADR-1505).
|
|
27
|
+
- Missing-profile semantics settle as fallback-to-Kubernetes-default (per ADR-1503), not refuse. REQ-001 names precedence (explicit declaration wins, absent falls back, unknown/malformed refused with stable codes PROBE_PROFILE_UNKNOWN / PROBE_PROFILE_MALFORMED). AC-14101-2 is on the fallback path; AC-14101-4 covers malformed.
|
|
28
|
+
- The liveness failure without AC coverage gap is fixed: adds AC-14102-5 asserting a response-capable in-process liveness self-check predicate answers HTTP 503 with content-length 0 on fail; `template` because the predicate is project-owned.
|
|
29
|
+
- The guide's `Boundary with observability-essentials` section reflects the current shelf: essentials v2 dropped its `scope: global` claims on `healthProbes` and `readinessSemantics`; probe-endpoints is the sole claimant on both topics; both orders compose cleanly. The pre-v2 conflict-resolution paths move to a historical migration note.
|
|
30
|
+
- The systemd + TCP transport families with no AC gap is fixed: adds AC-14105-4 (systemd Type=notify: exactly-once READY=1 plus periodic WATCHDOG=1 at cadence; supervisor pull when the watchdog cadence lapses), AC-14105-5 (TCP transport: accept on pass, refuse on fail, zero bytes on the connection), AC-14105-6 (missing platform adapter refused at boot with PROBE_ADAPTER_MISSING).
|
|
31
|
+
- Adds the missing coverage on AC-14106-3: `then` now uses the canonical lowercase `content-length` string owned by TAC-1502.responsibilities[2].
|
|
16
32
|
- Re-sweeps every existing AC's `disposition` per section 7b: ACs whose text references profile names, dependency names, or the elicited separate-port option flipped to `template` with `templateFillIns`; the remaining ACs stay `fixed`.
|
|
17
|
-
- Review fix pass (register scan): the band-spacing paragraph in `docs/topics.md` reads `shelf-lane`/`shelf lane` so shipped content carries no internal team labels.
|
|
@@ -29,9 +29,9 @@ The doc set is contributions (copied into the project tree by `rcf define bluepr
|
|
|
29
29
|
|
|
30
30
|
## What it contributes, and what it deliberately does not
|
|
31
31
|
|
|
32
|
-
Contributed kinds: REQ, US (with inline ACs), TAC, ADR. Adherence is expressed as ACs; the blueprint ships no test files (
|
|
32
|
+
Contributed kinds: REQ, US (with inline ACs), TAC, ADR. Adherence is expressed as ACs; the blueprint ships no test files (shipped policy 5) and no code.
|
|
33
33
|
|
|
34
|
-
No FBS contributions, as a matter of principle (
|
|
34
|
+
No FBS contributions, as a matter of principle (policy): FBSs are the work of the implementing agent, not the blueprint; project constraints have to be applied at the time of creation. The blueprint contributes the WHAT (the elicitation surface, the six shipped profile contracts, the two-listener topology option, the auth-exempt-list emission, the response-contract secrecy rule, the profile-swap-is-config invariant); the implementing agent derives the HOW-tasks (FBS) in the host project, where the ACs contributed here get picked up by the project's own build sequencing.
|
|
35
35
|
|
|
36
36
|
Deliberately not contributed: a public status page (observability-essentials owns `statusPageContract` for that audience); a notification outcome sink (observability-essentials owns that); an authenticated operator dashboard for granular internal state (project-authored on top of the readiness predicate); a metrics-export surface (a future `metrics-export` blueprint composes alongside); a distributed-tracing surface (a future `tracing` blueprint composes alongside); a log-shipping surface (application-api-rest's `logging` topic governs the wire-log shape of the HTTP tier); the readiness predicate implementation itself (project-authored; the blueprint fixes the boundary and each profile's default aggregation rule, not the per-dependency check code); the auth middleware installer (project-authored; the blueprint emits an exact-match exempt list the installer consumes); the vendor-CLI or client-library binding for any supervisor beyond the profile contract (project-authored inside a `custom:<name>` profile).
|
|
37
37
|
|
|
@@ -49,7 +49,7 @@ The probe surface always follows the operator-declared target integration profil
|
|
|
49
49
|
|
|
50
50
|
## Known mechanism-reach gaps
|
|
51
51
|
|
|
52
|
-
- **Custom-profile contract adherence.** Projects that author a `custom:<name>` profile against the profile contract are expected to satisfy the same transport/paths/responseContract/semanticModel shape the shipped profiles do; the profile contract validator (TAC-1501) refuses a partial profile at boot, which is where the mechanism reach lands. What the validator cannot compel is that a project-authored custom profile's response shape is minimal in the AC-14105 and AC-14106 sense (a custom profile could in principle enumerate a rich field set the validator would accept as complete). Recorded here rather than smuggled in as an AC that would only apply to the shipped profiles. Promotion signal: a `custom-profile-shape-lint` addition to the profile contract validator that enforces the minimalism rule per field-set-size heuristic (harder than it sounds; some legitimate custom profiles do have wider fields); or a project-side grep gate. Project-side workaround until then:
|
|
52
|
+
- **Custom-profile contract adherence.** Projects that author a `custom:<name>` profile against the profile contract are expected to satisfy the same transport/paths/responseContract/semanticModel shape the shipped profiles do; the profile contract validator (TAC-1501) refuses a partial profile at boot, which is where the mechanism reach lands. What the validator cannot compel is that a project-authored custom profile's response shape is minimal in the AC-14105 and AC-14106 sense (a custom profile could in principle enumerate a rich field set the validator would accept as complete). Recorded here rather than smuggled in as an AC that would only apply to the shipped profiles. Promotion signal: a `custom-profile-shape-lint` addition to the profile contract validator that enforces the minimalism rule per field-set-size heuristic (harder than it sounds; some legitimate custom profiles do have wider fields); or a project-side grep gate. Project-side workaround until then: at project-side check, compare the custom profile's enumerated field set against the pattern the shipped six carry.
|
|
53
53
|
- **Kubernetes gRPC probe transport.** The `kubernetes` profile ships HTTPGet and TCPSocket transports (via TAC-1504's tcpAdapter selection) but not gRPC. A project on a gRPC-only mesh that wants the standard gRPC health protocol supersedes ADR-1503 with a project-level ADR selecting the gRPC transport, or authors a `custom:kubernetes-grpc` profile. Promotion signal: a shipped gRPC-transport handler in a v1.1 pass if enough rcf-lite projects reach for it. Project-side workaround: the `custom:<name>` slot is the mechanism escape hatch.
|
|
54
54
|
|
|
55
55
|
## Optional startup path (v1.1.0)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"slug": "observability-probe-endpoints",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.5",
|
|
4
4
|
"category": "observability",
|
|
5
5
|
"elicits": [
|
|
6
6
|
{
|
|
@@ -171,5 +171,6 @@
|
|
|
171
171
|
"kind": "adr",
|
|
172
172
|
"path": "adrs/adr-1505-observability-probe-endpoints-external-response-secrecy.json"
|
|
173
173
|
}
|
|
174
|
-
]
|
|
174
|
+
],
|
|
175
|
+
"updatedAt": "2026-09-11"
|
|
175
176
|
}
|
package/blueprints/observability-probe-endpoints/contributions/probes/kubernetes-startup-enabled.mjs
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
// Kubernetes-startup-enabled probe for observability-probe-endpoints.
|
|
2
|
+
//
|
|
3
|
+
// Anchors AC-14102-4. The AC has two clauses:
|
|
4
|
+
// - enabled: probeInterface.options.kubernetes.startup.enabled=true
|
|
5
|
+
// -> resolver returns a three-path set including /startup; first
|
|
6
|
+
// GET on /startup returns 503 body {status:fail}; a second GET
|
|
7
|
+
// after the predicate returns pass returns 200 body {status:pass}.
|
|
8
|
+
// - disabled (without the enable flag): resolver returns two paths
|
|
9
|
+
// and no /startup handler is registered.
|
|
10
|
+
// This probe exercises BOTH clauses.
|
|
11
|
+
|
|
12
|
+
import { randomUUID } from 'node:crypto';
|
|
13
|
+
import { materialise, resolveProfile } from '../../../../packages/rcf-lite/test/fixtures/probe-pack-observability-probe-endpoints/src/profile-registry.mjs';
|
|
14
|
+
import { primaryPort } from './probe-utils.mjs';
|
|
15
|
+
|
|
16
|
+
export const anchorAcId = 'AC-14102-4';
|
|
17
|
+
export const accountBound = false;
|
|
18
|
+
const AC4 = 'When the operator sets probeInterface.options.kubernetes.startup.enabled: true on the';
|
|
19
|
+
|
|
20
|
+
async function get(url, rid) {
|
|
21
|
+
const res = await fetch(url, { headers: { 'x-request-id': rid } });
|
|
22
|
+
const text = await res.text();
|
|
23
|
+
let parsed = null; try { parsed = JSON.parse(text); } catch {}
|
|
24
|
+
return { status: res.status, requestId: res.headers.get('x-request-id'), body: text, parsed };
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export default async function runProbe() {
|
|
28
|
+
const results = [];
|
|
29
|
+
|
|
30
|
+
// ENABLED clause
|
|
31
|
+
const resolvedEnabled = resolveProfile('kubernetes', { startup: { enabled: true } });
|
|
32
|
+
const enabledPathCount = Object.keys(resolvedEnabled.paths ?? {}).length;
|
|
33
|
+
const enabledHasStartup = Boolean(resolvedEnabled.paths?.startup);
|
|
34
|
+
const inst = await materialise({ profile: resolvedEnabled, listenerPort: primaryPort() });
|
|
35
|
+
const suppliedStarting = randomUUID();
|
|
36
|
+
const suppliedReady = randomUUID();
|
|
37
|
+
let starting, ready;
|
|
38
|
+
try {
|
|
39
|
+
starting = await get(`http://127.0.0.1:${inst.requestPort}/startup`, suppliedStarting);
|
|
40
|
+
results.push({
|
|
41
|
+
anchorAcId: 'AC-14102-4',
|
|
42
|
+
verdict: enabledPathCount === 3 && enabledHasStartup && starting.status === 503 && starting.requestId === suppliedStarting && starting.parsed?.status === 'fail' && starting.parsed?.profile === 'kubernetes' ? 'pass' : 'fail',
|
|
43
|
+
detail: `${AC4} shipped kubernetes profile - ENABLED clause: paths=${JSON.stringify(Object.keys(resolvedEnabled.paths ?? {}))} startup path='${resolvedEnabled.paths?.startup}'; pre-ready GET /startup -> ${starting.status} body.status='${starting.parsed?.status}'; echoed requestId=${starting.requestId === suppliedStarting}.`,
|
|
44
|
+
evidence: { variedInput: suppliedStarting, suppliedInput: suppliedStarting, derived: { status: starting.status, requestId: starting.requestId, bodyExcerpt: starting.body.slice(0, 300) }, derivedStarting: { status: starting.status, requestId: starting.requestId, bodyExcerpt: starting.body.slice(0, 300) } },
|
|
45
|
+
});
|
|
46
|
+
inst.markStartupReady();
|
|
47
|
+
ready = await get(`http://127.0.0.1:${inst.requestPort}/startup`, suppliedReady);
|
|
48
|
+
results.push({
|
|
49
|
+
anchorAcId: 'AC-14102-4',
|
|
50
|
+
verdict: ready.status === 200 && ready.requestId === suppliedReady && ready.parsed?.status === 'pass' && ready.parsed?.profile === 'kubernetes' ? 'pass' : 'fail',
|
|
51
|
+
detail: `${AC4} shipped kubernetes profile - ENABLED clause: post-markStartupReady GET /startup -> ${ready.status} body.status='${ready.parsed?.status}'; echoed requestId=${ready.requestId === suppliedReady}.`,
|
|
52
|
+
evidence: { variedInput: suppliedReady, suppliedInput: suppliedReady, derived: { status: ready.status, requestId: ready.requestId, bodyExcerpt: ready.body.slice(0, 300) }, derivedReady: { status: ready.status, requestId: ready.requestId, bodyExcerpt: ready.body.slice(0, 300) } },
|
|
53
|
+
});
|
|
54
|
+
} finally { await inst.close(); }
|
|
55
|
+
|
|
56
|
+
// DISABLED clause: no enable flag; resolver must yield two paths and
|
|
57
|
+
// /startup must be a 404 (no handler registered).
|
|
58
|
+
const resolvedDisabled = resolveProfile('kubernetes');
|
|
59
|
+
const disabledPathCount = Object.keys(resolvedDisabled.paths ?? {}).length;
|
|
60
|
+
const disabledHasStartup = Boolean(resolvedDisabled.paths?.startup);
|
|
61
|
+
const inst2 = await materialise({ profile: resolvedDisabled, listenerPort: primaryPort() });
|
|
62
|
+
let disabledResp;
|
|
63
|
+
const disabledId = randomUUID();
|
|
64
|
+
try {
|
|
65
|
+
disabledResp = await get(`http://127.0.0.1:${inst2.requestPort}/startup`, disabledId);
|
|
66
|
+
results.push({
|
|
67
|
+
anchorAcId: 'AC-14102-4',
|
|
68
|
+
verdict: disabledPathCount === 2 && !disabledHasStartup && disabledResp.status === 404 ? 'pass' : 'fail',
|
|
69
|
+
detail: `${AC4} shipped kubernetes profile - DISABLED clause (no enable flag): paths=${JSON.stringify(Object.keys(resolvedDisabled.paths ?? {}))} (expect two paths); GET /startup -> ${disabledResp.status} (expect 404 with no /startup handler registered).`,
|
|
70
|
+
evidence: { variedInput: disabledId, suppliedInput: disabledId, derived: { status: disabledResp.status, requestId: disabledResp.requestId, bodyExcerpt: disabledResp.body.slice(0, 300) }, resolvedPaths: resolvedDisabled.paths, acceptedProfile: resolvedDisabled.name },
|
|
71
|
+
});
|
|
72
|
+
} finally { await inst2.close(); }
|
|
73
|
+
|
|
74
|
+
return { results, extra: { envDeclared: ['RCF_FIXTURE_OBS_PROBE_PORT', 'RCF_FIXTURE_OBS_PROBE_SEPARATE_PORT'], boundPort: inst.requestPort,
|
|
75
|
+
variedInputs: { starting: suppliedStarting, ready: suppliedReady, disabled: disabledId },
|
|
76
|
+
derivedStarting: starting && { status: starting.status, requestId: starting.requestId, bodyExcerpt: starting.body.slice(0, 300) },
|
|
77
|
+
derivedReady: ready && { status: ready.status, requestId: ready.requestId, bodyExcerpt: ready.body.slice(0, 300) },
|
|
78
|
+
derivedDisabled: disabledResp && { status: disabledResp.status, requestId: disabledResp.requestId, bodyExcerpt: disabledResp.body.slice(0, 300) },
|
|
79
|
+
} };
|
|
80
|
+
}
|