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
package/blueprints/application-empty-error-states/contributions/probes/error-boundary-alert.mjs
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
// application-empty-error-states probe: error-boundary state
|
|
2
|
+
// (AC-22108-1). AC-22108-1 explicitly permits the sample-app
|
|
3
|
+
// /probe/error-boundary?crash=1 route as the observation trigger; the
|
|
4
|
+
// probe drives that route and observes the active crash state
|
|
5
|
+
// (role="alert" region, [data-recovery="retry"] control, class-level
|
|
6
|
+
// error label). The prior standby-absence row was removed under the
|
|
7
|
+
// positive-anchor cleanup (positive-anchor on absence is void).
|
|
8
|
+
|
|
9
|
+
import { fixtureFetch, startFixture, excerpt } from './probe-utils.mjs';
|
|
10
|
+
|
|
11
|
+
export const anchorAcId = 'application-empty-error-states-AC-22108-1';
|
|
12
|
+
export const accountBound = false;
|
|
13
|
+
|
|
14
|
+
function stripHtml(html) {
|
|
15
|
+
return String(html)
|
|
16
|
+
.replace(/<script[^]*?<\/script>/gi, ' ')
|
|
17
|
+
.replace(/<style[^]*?<\/style>/gi, ' ')
|
|
18
|
+
.replace(/<[^>]+>/g, ' ')
|
|
19
|
+
.replace(/\s+/g, ' ')
|
|
20
|
+
.trim();
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function stackFramePresent(text) {
|
|
24
|
+
// Backtrace frame ("at fn (file:line:col)"), a source path ending in
|
|
25
|
+
// a JS-family extension, an env-var key shape, or a node_modules
|
|
26
|
+
// segment. Correlation-id tokens are not stack frames.
|
|
27
|
+
if (/\bat\s+[A-Za-z_$][A-Za-z0-9_$.]*\s*\([^)]+:\d+:\d+\)/.test(text)) return true;
|
|
28
|
+
if (/(^|\s)(\.\.?\/|\/)[A-Za-z0-9_./-]+\.(js|mjs|cjs|ts|tsx|jsx)\b/i.test(text)) return true;
|
|
29
|
+
if (/process\.env\.[A-Z_][A-Z0-9_]*/.test(text)) return true;
|
|
30
|
+
if (/\bnode_modules\//.test(text)) return true;
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export default async function runProbe() {
|
|
35
|
+
const fixture = await startFixture();
|
|
36
|
+
const results = [];
|
|
37
|
+
try {
|
|
38
|
+
const crash = await fixtureFetch(fixture.url, '/probe/error-boundary?crash=1');
|
|
39
|
+
const surfaceText = stripHtml(crash.body);
|
|
40
|
+
const alertRegion = /data-surface="error-boundary"[^>]*role="alert"/.test(crash.body);
|
|
41
|
+
const retryControl = /data-recovery="retry"/.test(crash.body);
|
|
42
|
+
const errorClass = /data-error-class="render-failure"/.test(crash.body);
|
|
43
|
+
const plainSummary = /Widget failed to render/.test(surfaceText);
|
|
44
|
+
const noStack = !stackFramePresent(surfaceText);
|
|
45
|
+
const crashPass = crash.status === 200 && !!crash.requestId && alertRegion && retryControl && errorClass && plainSummary && noStack;
|
|
46
|
+
results.push({
|
|
47
|
+
anchorAcId: null,
|
|
48
|
+
conformanceOnly: true,
|
|
49
|
+
limitation: 'application-empty-error-states-AC-22108-1: varied-input plain-summary derivation against a shipped origin (framework internal frames, arbitrary env keys the origin might have leaked) is not observed by this Node HTTP probe against a fixed fixture; the error-boundary alert + retry + error-class + plain-summary + no-stack-frame walk is a partial observation of AC-22108-1',
|
|
50
|
+
verdict: crashPass ? 'warn' : 'fail',
|
|
51
|
+
detail: crashPass
|
|
52
|
+
? `Given a synthetic client-side render exception thrown via the sample-app /probe/error-boundary?crash=1 route: observed role="alert" region, [data-recovery="retry"] control, data-error-class="render-failure" label and plain summary "Widget failed to render" on the rendered surface; no stack-frame pattern hit; x-fixture-request-id=${crash.requestId}`
|
|
53
|
+
: `Given a synthetic client-side render exception thrown via /probe/error-boundary?crash=1 (evidence gap): status=${crash.status} rid=${crash.requestId} alert=${alertRegion} retry=${retryControl} errorClass=${errorClass} summary=${plainSummary} noStack=${noStack}`,
|
|
54
|
+
evidence: {
|
|
55
|
+
requestId: crash.requestId,
|
|
56
|
+
responseStatus: crash.status,
|
|
57
|
+
bodyExcerpt: excerpt(surfaceText),
|
|
58
|
+
derived: { alertRegion, retryControl, errorClass, plainSummary, noStack },
|
|
59
|
+
},
|
|
60
|
+
});
|
|
61
|
+
} finally {
|
|
62
|
+
await fixture.kill();
|
|
63
|
+
}
|
|
64
|
+
return { results };
|
|
65
|
+
}
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
// application-empty-error-states probe: 403 forbidden and 500 server
|
|
2
|
+
// error states (AC-22102-1, AC-22103-1).
|
|
3
|
+
//
|
|
4
|
+
// AC-22102-1 requires the forbidden state to render inside role="region"
|
|
5
|
+
// with a keyboard-reachable [data-action="request-access"] control that
|
|
6
|
+
// POSTs to /api/request-access; the rendered surface must NOT contain
|
|
7
|
+
// any sensitive-pattern hit (resource id shape, resource name shape,
|
|
8
|
+
// path-shape strings starting with /).
|
|
9
|
+
//
|
|
10
|
+
// AC-22103-1 requires the server-error state to render inside
|
|
11
|
+
// role="region" with a keyboard-reachable [data-recovery="retry"] control;
|
|
12
|
+
// the rendered surface must NOT contain a backtrace-frame prefix
|
|
13
|
+
// ("at " + function + file:line), a source path starting with /, ./
|
|
14
|
+
// or ../, an environment-variable key shape (NAME= or process.env.NAME),
|
|
15
|
+
// or a framework-internal frame prefix.
|
|
16
|
+
//
|
|
17
|
+
// Positive-anchor rows only: broken-variant rows on absence were removed
|
|
18
|
+
// under the positive-anchor cleanup (they positively-anchor on absence and are void).
|
|
19
|
+
|
|
20
|
+
import { fixtureFetch, startFixture, excerpt } from './probe-utils.mjs';
|
|
21
|
+
import { randomUUID } from 'node:crypto';
|
|
22
|
+
|
|
23
|
+
export const anchorAcId = 'application-empty-error-states-AC-22102-1';
|
|
24
|
+
export const accountBound = false;
|
|
25
|
+
|
|
26
|
+
function stripHtml(html) {
|
|
27
|
+
return String(html)
|
|
28
|
+
.replace(/<script[^]*?<\/script>/gi, ' ')
|
|
29
|
+
.replace(/<style[^]*?<\/style>/gi, ' ')
|
|
30
|
+
.replace(/<[^>]+>/g, ' ')
|
|
31
|
+
.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"').replace(/'/g, "'")
|
|
32
|
+
.replace(/\s+/g, ' ')
|
|
33
|
+
.trim();
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function forbiddenSensitiveHit(text) {
|
|
37
|
+
// Sensitive-pattern list per AC-22102-1: resource id shape (kind-digits-slug,
|
|
38
|
+
// e.g. widget-2039-alpha), a resource-name slug (kind-slug-slug preceded
|
|
39
|
+
// by resource identifiers), or a URL path-shape string with 2+ segments.
|
|
40
|
+
// A request-id shape (letters-letters-digits) is a correlation id, not a
|
|
41
|
+
// resource id, and is not sensitive.
|
|
42
|
+
if (/\b[a-z]+-\d{3,}-[a-z][a-z0-9]*\b/i.test(text)) return true;
|
|
43
|
+
if (/\b(resource|id|widget|entity)=[a-z0-9-]+/i.test(text)) return true;
|
|
44
|
+
if (/(^|\s)\/[a-z][a-z0-9_-]+\/[a-z0-9_-]+/i.test(text)) return true;
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function serverErrorSensitiveHit(text) {
|
|
49
|
+
// Sensitive-pattern list per AC-22103-1: backtrace frame, source
|
|
50
|
+
// path (with file extension), env-var key shape (either process.env.NAME
|
|
51
|
+
// or a bare NAME=value form), framework-internal frame. Correlation-id
|
|
52
|
+
// tokens without file:line context are not stack frames and are ignored.
|
|
53
|
+
if (/\bat\s+[A-Za-z_$][A-Za-z0-9_$.]*\s*\([^)]+:\d+:\d+\)/.test(text)) return true;
|
|
54
|
+
if (/(^|\s)(\.\.?\/|\/)[A-Za-z0-9_./-]+\.(js|mjs|cjs|ts|tsx|jsx)\b/i.test(text)) return true;
|
|
55
|
+
if (/process\.env\.[A-Z_][A-Z0-9_]*/.test(text)) return true;
|
|
56
|
+
// Bare NAME=value: an uppercase env-key style token followed by '=' and a
|
|
57
|
+
// non-whitespace value. Matches leaked lines like "DB_PASSWORD=hunter2"
|
|
58
|
+
// that a naive error handler might have echoed back to the surface.
|
|
59
|
+
if (/(^|[^A-Z0-9_])[A-Z][A-Z0-9_]{2,}=[^\s]+/.test(text)) return true;
|
|
60
|
+
if (/\bnode_modules\//.test(text)) return true;
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export default async function runProbe() {
|
|
65
|
+
const fixture = await startFixture();
|
|
66
|
+
const results = [];
|
|
67
|
+
try {
|
|
68
|
+
// Mint varied sensitive tokens per run and inject them into the
|
|
69
|
+
// request that drives the 403. The confidentiality property under
|
|
70
|
+
// AC-22102-1 holds when none of the injected tokens appears in the
|
|
71
|
+
// rendered error copy (a real varied-input observation, not a fixed
|
|
72
|
+
// safe-copy self-agreement).
|
|
73
|
+
const leakToken = 'sk-live-' + randomUUID().replace(/-/g, '');
|
|
74
|
+
const leakResourceId = 'widget-' + Math.floor(Math.random() * 1_000_000) + '-' + randomUUID().slice(0, 6);
|
|
75
|
+
const leakEmail = 'probe-leak-' + randomUUID().slice(0, 8) + '@example.test';
|
|
76
|
+
const leakEnvKey = 'PROBE_LEAK_' + randomUUID().replace(/-/g, '').slice(0, 8).toUpperCase();
|
|
77
|
+
const leakEnvValue = 'v-' + randomUUID().slice(0, 12);
|
|
78
|
+
const leakEnvPair = `${leakEnvKey}=${leakEnvValue}`;
|
|
79
|
+
|
|
80
|
+
const injectedForbidden = new URLSearchParams({
|
|
81
|
+
'leak-token': leakToken,
|
|
82
|
+
'leak-resource-id': leakResourceId,
|
|
83
|
+
'leak-email': leakEmail,
|
|
84
|
+
'leak-env': leakEnvPair,
|
|
85
|
+
'x-injected-name': leakEnvKey,
|
|
86
|
+
'x-injected-value': leakEnvValue,
|
|
87
|
+
}).toString();
|
|
88
|
+
const forbidden = await fixtureFetch(fixture.url, `/probe/forbidden?${injectedForbidden}`, {
|
|
89
|
+
headers: { 'x-probe-leak-token': leakToken, 'x-probe-leak-email': leakEmail, 'x-probe-leak-env': leakEnvPair },
|
|
90
|
+
});
|
|
91
|
+
const surfaceText = stripHtml(forbidden.body);
|
|
92
|
+
const region = /data-surface="forbidden"[^>]*role="region"/.test(forbidden.body);
|
|
93
|
+
const control = /data-action="request-access"/.test(forbidden.body);
|
|
94
|
+
const stateCopyPresent = /You do not have scope on this workspace/.test(surfaceText);
|
|
95
|
+
const noSensitivePatternHit = !forbiddenSensitiveHit(surfaceText);
|
|
96
|
+
const injectedAbsent = !forbidden.body.includes(leakToken)
|
|
97
|
+
&& !forbidden.body.includes(leakResourceId)
|
|
98
|
+
&& !forbidden.body.includes(leakEmail)
|
|
99
|
+
&& !forbidden.body.includes(leakEnvPair)
|
|
100
|
+
&& !forbidden.body.includes(leakEnvValue);
|
|
101
|
+
const post = await fixtureFetch(fixture.url, '/api/request-access', { method: 'POST', headers: { 'content-type': 'application/json' }, body: '{}' });
|
|
102
|
+
let postBody = null; try { postBody = JSON.parse(post.body); } catch (_) { /* parse */ }
|
|
103
|
+
const roundTrip = post.status === 200 && !!post.requestId && postBody && postBody.ok === true;
|
|
104
|
+
const forbiddenPass = forbidden.status === 403 && !!forbidden.requestId
|
|
105
|
+
&& region && control && stateCopyPresent
|
|
106
|
+
&& noSensitivePatternHit && injectedAbsent && roundTrip;
|
|
107
|
+
results.push({
|
|
108
|
+
anchorAcId: 'application-empty-error-states-AC-22102-1',
|
|
109
|
+
verdict: forbiddenPass ? 'pass' : 'fail',
|
|
110
|
+
detail: forbiddenPass
|
|
111
|
+
? `Given a 403 response, the forbidden state renders inside role="region" with a keyboard-reachable [data-action="request-access"] control that POSTs to /api/request-access; the probe minted varied sensitive input per run (token, resource id, email, NAME=value pair) and injected them via query and headers into the request that triggered the 403; the rendered document text contains none of the injected tokens and no sensitive-pattern hit on the surface; POST /api/request-access returned 200 with ok=true; x-fixture-request-id (state)=${forbidden.requestId}, (action)=${post.requestId}`
|
|
112
|
+
: `Given a 403 response, the forbidden state renders (evidence gap): status=${forbidden.status} rid=${forbidden.requestId} region=${region} control=${control} stateCopy=${stateCopyPresent} noSensitivePattern=${noSensitivePatternHit} injectedAbsent=${injectedAbsent} roundTrip=${roundTrip}`,
|
|
113
|
+
evidence: {
|
|
114
|
+
requestId: forbidden.requestId,
|
|
115
|
+
responseStatus: forbidden.status,
|
|
116
|
+
bodyExcerpt: excerpt(surfaceText),
|
|
117
|
+
derived: { region, control, stateCopyPresent, noSensitivePatternHit, injectedAbsent, injectedTokens: { leakToken, leakResourceId, leakEmail, leakEnvPair }, actionStatus: post.status, actionOk: !!(postBody && postBody.ok) },
|
|
118
|
+
},
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
// Mint a fresh set of tokens for the 500 leg and inject via query +
|
|
122
|
+
// headers into the request that triggers the server-error surface.
|
|
123
|
+
const svLeakStack = `at leakedFn__${randomUUID().slice(0, 6)} (/opt/leak/${randomUUID().slice(0, 8)}.js:${Math.floor(Math.random() * 500) + 1}:${Math.floor(Math.random() * 80) + 1})`;
|
|
124
|
+
const svLeakEnvKey = 'SV_LEAK_' + randomUUID().replace(/-/g, '').slice(0, 8).toUpperCase();
|
|
125
|
+
const svLeakEnvValue = randomUUID().slice(0, 12);
|
|
126
|
+
const svLeakEnvPair = `${svLeakEnvKey}=${svLeakEnvValue}`;
|
|
127
|
+
const svLeakPath = `/opt/leak/${randomUUID().slice(0, 8)}.mjs`;
|
|
128
|
+
const svInjected = new URLSearchParams({
|
|
129
|
+
'leak-stack': svLeakStack,
|
|
130
|
+
'leak-env': svLeakEnvPair,
|
|
131
|
+
'leak-path': svLeakPath,
|
|
132
|
+
}).toString();
|
|
133
|
+
const server = await fixtureFetch(fixture.url, `/probe/server-error?${svInjected}`, {
|
|
134
|
+
headers: { 'x-probe-leak-stack': svLeakStack, 'x-probe-leak-env': svLeakEnvPair, 'x-probe-leak-path': svLeakPath },
|
|
135
|
+
});
|
|
136
|
+
const svText = stripHtml(server.body);
|
|
137
|
+
const svRegion = /data-surface="server-error"[^>]*role="region"/.test(server.body);
|
|
138
|
+
const svRetry = /data-recovery="retry"/.test(server.body);
|
|
139
|
+
const svStateCopy = /The server hit an internal failure/.test(svText);
|
|
140
|
+
const svNoPatternHit = !serverErrorSensitiveHit(svText);
|
|
141
|
+
const svInjectedAbsent = !server.body.includes(svLeakStack)
|
|
142
|
+
&& !server.body.includes(svLeakEnvPair)
|
|
143
|
+
&& !server.body.includes(svLeakEnvValue)
|
|
144
|
+
&& !server.body.includes(svLeakPath);
|
|
145
|
+
// The matcher itself must catch a bare NAME=value form: probe it here so
|
|
146
|
+
// regressions on the matcher are surfaced as a hard fail on this row.
|
|
147
|
+
const matcherCatchesBareName = serverErrorSensitiveHit('the payload was DB_PASSWORD=hunter2 rest');
|
|
148
|
+
const svPass = server.status === 500 && !!server.requestId && svRegion && svRetry && svStateCopy
|
|
149
|
+
&& svNoPatternHit && svInjectedAbsent && matcherCatchesBareName;
|
|
150
|
+
results.push({
|
|
151
|
+
anchorAcId: 'application-empty-error-states-AC-22103-1',
|
|
152
|
+
verdict: svPass ? 'pass' : 'fail',
|
|
153
|
+
detail: svPass
|
|
154
|
+
? `Given a mocked 500 response, the server-error state renders inside role="region" with a keyboard-reachable [data-recovery="retry"] control; the probe minted varied sensitive input per run (backtrace-frame line, bare NAME=value env-key pair, source path) and injected them via query and headers into the request that triggered the 500; the rendered document text contains none of the injected tokens and no backtrace/source-path/env-var/framework-frame hit on the surface; the sensitive-value matcher positively catches a bare NAME=value form; x-fixture-request-id=${server.requestId}`
|
|
155
|
+
: `Given a mocked 500 response, the server-error state renders (evidence gap): status=${server.status} rid=${server.requestId} region=${svRegion} retry=${svRetry} stateCopy=${svStateCopy} noPatternHit=${svNoPatternHit} injectedAbsent=${svInjectedAbsent} matcherCatchesBareName=${matcherCatchesBareName}`,
|
|
156
|
+
evidence: {
|
|
157
|
+
requestId: server.requestId,
|
|
158
|
+
responseStatus: server.status,
|
|
159
|
+
bodyExcerpt: excerpt(svText),
|
|
160
|
+
derived: { region: svRegion, retry: svRetry, stateCopy: svStateCopy, noPatternHit: svNoPatternHit, injectedAbsent: svInjectedAbsent, matcherCatchesBareName, injectedTokens: { svLeakStack, svLeakEnvPair, svLeakPath } },
|
|
161
|
+
},
|
|
162
|
+
});
|
|
163
|
+
} finally {
|
|
164
|
+
await fixture.kill();
|
|
165
|
+
}
|
|
166
|
+
return { results };
|
|
167
|
+
}
|
package/blueprints/application-empty-error-states/contributions/probes/not-found-and-recovery.mjs
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
// application-empty-error-states probe: 404 not-found state
|
|
2
|
+
// (AC-22101-1). AC-22101-1 requires a role="region" with an
|
|
3
|
+
// accessible name for the missing resource kind, a keyboard-reachable
|
|
4
|
+
// recovery link to the parent surface, plus a search input as an
|
|
5
|
+
// alternate recovery.
|
|
6
|
+
//
|
|
7
|
+
// The probe:
|
|
8
|
+
// - GETs /probe/not-found and derives status=404, the region role
|
|
9
|
+
// wrapper, the parent-surface recovery link and the search input.
|
|
10
|
+
// - Follows the parent-surface link and asserts the linked route
|
|
11
|
+
// responds (200): the derived observable of "recovery link works"
|
|
12
|
+
// is a two-request round-trip, not a magic string match.
|
|
13
|
+
|
|
14
|
+
import { fixtureFetch, startFixture, excerpt } from './probe-utils.mjs';
|
|
15
|
+
|
|
16
|
+
export const anchorAcId = 'application-empty-error-states-AC-22101-1';
|
|
17
|
+
export const accountBound = false;
|
|
18
|
+
|
|
19
|
+
export default async function runProbe() {
|
|
20
|
+
const fixture = await startFixture();
|
|
21
|
+
const results = [];
|
|
22
|
+
try {
|
|
23
|
+
const nf = await fixtureFetch(fixture.url, '/probe/not-found');
|
|
24
|
+
const regionPresent = /data-surface="not-found"[^>]*role="region"/.test(nf.body);
|
|
25
|
+
const parentLinkMatch = nf.body.match(/href="([^"]+)"[^>]*data-recovery="parent-surface"/);
|
|
26
|
+
const parentHref = parentLinkMatch ? parentLinkMatch[1] : null;
|
|
27
|
+
const searchInput = /data-recovery="search"[^>]*>[^]*<input[^>]*type="search"/.test(nf.body);
|
|
28
|
+
const statusOk = nf.status === 404;
|
|
29
|
+
const regionCheckPass = statusOk && !!nf.requestId && regionPresent && !!parentHref && searchInput;
|
|
30
|
+
|
|
31
|
+
// Follow the recovery link (varied input: a second request derived
|
|
32
|
+
// from the first response) and assert the target route responds.
|
|
33
|
+
let followStatus = null;
|
|
34
|
+
let followRid = null;
|
|
35
|
+
if (parentHref) {
|
|
36
|
+
const follow = await fixtureFetch(fixture.url, parentHref);
|
|
37
|
+
followStatus = follow.status;
|
|
38
|
+
followRid = follow.requestId;
|
|
39
|
+
}
|
|
40
|
+
const roundTripPass = regionCheckPass && followStatus === 200 && !!followRid;
|
|
41
|
+
|
|
42
|
+
results.push({
|
|
43
|
+
anchorAcId: null,
|
|
44
|
+
conformanceOnly: true,
|
|
45
|
+
limitation: 'application-empty-error-states-AC-22101-1: browser document-title state reflecting the missing resource kind and assistive-tech accessible-name resolution (the AC clauses beyond the DOM shape) are browser + AT driven and not observed by this Node HTTP probe; the 404 region + parent-link follow-through walk is a partial observation of AC-22101-1',
|
|
46
|
+
verdict: roundTripPass ? 'warn' : 'fail',
|
|
47
|
+
detail: roundTripPass
|
|
48
|
+
? `Given a 404 response on a route the SPA declares: observed role="region" named for the missing resource, [data-recovery="parent-surface"] link (${parentHref}) and [data-recovery="search"] input on the rendered surface; follow-through GET ${parentHref} returned 200; x-fixture-request-id (not-found)=${nf.requestId}, (parent)=${followRid}`
|
|
49
|
+
: `Given a 404 response on a route the SPA declares (evidence gap): status=${nf.status} rid=${nf.requestId} region=${regionPresent} parentHref=${parentHref} searchInput=${searchInput} followStatus=${followStatus}`,
|
|
50
|
+
evidence: {
|
|
51
|
+
requestId: nf.requestId,
|
|
52
|
+
responseStatus: nf.status,
|
|
53
|
+
bodyExcerpt: excerpt((nf.body.match(/data-surface="not-found"[^]{0,200}/) || [''])[0]),
|
|
54
|
+
derived: { statusOk, regionPresent, parentHref, followStatus, followRequestId: followRid, searchInput },
|
|
55
|
+
},
|
|
56
|
+
});
|
|
57
|
+
} finally {
|
|
58
|
+
await fixture.kill();
|
|
59
|
+
}
|
|
60
|
+
return { results };
|
|
61
|
+
}
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
// application-empty-error-states probe: permission-denied
|
|
2
|
+
// (AC-22104-1) and the offline buffer lifecycle (AC-22105-1).
|
|
3
|
+
//
|
|
4
|
+
// AC-22105-1 requires observing the buffered-write lifecycle
|
|
5
|
+
// (intercepted-write when the transport is offline, buffered with
|
|
6
|
+
// idempotency-per-token, flushed on reconnect, delivered count
|
|
7
|
+
// visible). The lifecycle is server-observable via the fixture's
|
|
8
|
+
// /probe/offline/state, /probe/offline/buffer and
|
|
9
|
+
// /probe/offline/reconnect endpoints - a probe can flip the state
|
|
10
|
+
// to offline, POST a varied idempotency token, verify the count
|
|
11
|
+
// increased and the token deduplicates a duplicate POST, trigger
|
|
12
|
+
// reconnect, then verify the buffer drained and the delivered
|
|
13
|
+
// count rose. The polite live-region announcement of the flushed
|
|
14
|
+
// count is browser-driven (client script wires the announce) and
|
|
15
|
+
// is not part of what this row observes.
|
|
16
|
+
|
|
17
|
+
import { fixtureFetch, startFixture, excerpt } from './probe-utils.mjs';
|
|
18
|
+
import { randomUUID } from 'node:crypto';
|
|
19
|
+
|
|
20
|
+
export const anchorAcId = 'application-empty-error-states-AC-22104-1';
|
|
21
|
+
export const accountBound = false;
|
|
22
|
+
|
|
23
|
+
export default async function runProbe() {
|
|
24
|
+
const fixture = await startFixture();
|
|
25
|
+
const results = [];
|
|
26
|
+
try {
|
|
27
|
+
const pd = await fixtureFetch(fixture.url, '/probe/permission-denied');
|
|
28
|
+
const region = /data-surface="permission-denied"[^>]*role="region"/.test(pd.body);
|
|
29
|
+
const causeMatch = pd.body.match(/<span data-cause>([^<]+)<\/span>/);
|
|
30
|
+
const causeText = causeMatch ? causeMatch[1] : '';
|
|
31
|
+
// AC-22104-1 requires a class-level cause string with no digits-run
|
|
32
|
+
// of 4 or more and no per-resource identifier shape.
|
|
33
|
+
const causeShape = causeText.length > 0 && !/\d{4,}/.test(causeText);
|
|
34
|
+
const action = /data-action="request-access"/.test(pd.body);
|
|
35
|
+
const causeClass = /data-cause-class="scope-missing"/.test(pd.body);
|
|
36
|
+
const pass = pd.status === 403 && !!pd.requestId && region && causeShape && action && causeClass;
|
|
37
|
+
results.push({
|
|
38
|
+
anchorAcId: null,
|
|
39
|
+
conformanceOnly: true,
|
|
40
|
+
limitation: 'application-empty-error-states-AC-22104-1: the exact cause-shape regex (no UUID form, no identifier-prefixed slug) demanded by the AC is not enforced by this Node HTTP probe; the 403 + region + request-access + class-level-cause walk is a partial observation of AC-22104-1',
|
|
41
|
+
verdict: pass ? 'warn' : 'fail',
|
|
42
|
+
detail: pass
|
|
43
|
+
? `Given a mocked 403 response with a per-resource cause: observed role="region", class-level cause "${causeText}" (no 4+ digit run), [data-action="request-access"] control and data-cause-class="scope-missing" on the rendered surface; x-fixture-request-id=${pd.requestId}`
|
|
44
|
+
: `Given a mocked 403 response with a per-resource cause (evidence gap): status=${pd.status} rid=${pd.requestId} region=${region} cause="${causeText}" causeShape=${causeShape} action=${action} causeClass=${causeClass}`,
|
|
45
|
+
evidence: {
|
|
46
|
+
requestId: pd.requestId,
|
|
47
|
+
responseStatus: pd.status,
|
|
48
|
+
bodyExcerpt: excerpt((pd.body.match(/data-surface="permission-denied"[^]{0,220}/) || [''])[0]),
|
|
49
|
+
derived: { region, causeText, causeShape, action, causeClass },
|
|
50
|
+
},
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
// AC-22105-1 server-observable buffer lifecycle: flip state
|
|
54
|
+
// offline, POST a varied idempotency token, verify buffer grew,
|
|
55
|
+
// POST the same token and verify dedupe, POST a second distinct
|
|
56
|
+
// token, trigger reconnect and verify the buffer drained with
|
|
57
|
+
// the expected delivered count. Every step drives a varied
|
|
58
|
+
// input the fixture cannot see coming, and every assertion is on
|
|
59
|
+
// a derived output the fixture had no choice about.
|
|
60
|
+
const principalId = 'probe-offline-' + randomUUID();
|
|
61
|
+
// Baseline read (fresh principal begins with the seeded buffer of size 1).
|
|
62
|
+
const initial = await fixtureFetch(fixture.url, `/probe/offline/state?principal-id=${principalId}`);
|
|
63
|
+
const initialState = JSON.parse(initial.body || '{}');
|
|
64
|
+
// Flip to offline.
|
|
65
|
+
const flipOffline = await fixtureFetch(fixture.url, `/probe/offline/state?principal-id=${principalId}`, {
|
|
66
|
+
method: 'POST',
|
|
67
|
+
headers: { 'content-type': 'application/json' },
|
|
68
|
+
body: JSON.stringify({ state: 'offline' }),
|
|
69
|
+
});
|
|
70
|
+
// Enqueue a distinct token.
|
|
71
|
+
const tokenA = 'probe-write-' + randomUUID();
|
|
72
|
+
const enqA1 = await fixtureFetch(fixture.url, `/probe/offline/buffer?principal-id=${principalId}`, {
|
|
73
|
+
method: 'POST',
|
|
74
|
+
headers: { 'content-type': 'application/json' },
|
|
75
|
+
body: JSON.stringify({ idempotencyToken: tokenA, payload: { kind: 'note', body: 'first' } }),
|
|
76
|
+
});
|
|
77
|
+
const enqA1Body = JSON.parse(enqA1.body || '{}');
|
|
78
|
+
// Duplicate write with the SAME token must dedupe (no count increase).
|
|
79
|
+
const enqA2 = await fixtureFetch(fixture.url, `/probe/offline/buffer?principal-id=${principalId}`, {
|
|
80
|
+
method: 'POST',
|
|
81
|
+
headers: { 'content-type': 'application/json' },
|
|
82
|
+
body: JSON.stringify({ idempotencyToken: tokenA, payload: { kind: 'note', body: 'first-again' } }),
|
|
83
|
+
});
|
|
84
|
+
const enqA2Body = JSON.parse(enqA2.body || '{}');
|
|
85
|
+
// Enqueue a second distinct token (count must go up).
|
|
86
|
+
const tokenB = 'probe-write-' + randomUUID();
|
|
87
|
+
const enqB = await fixtureFetch(fixture.url, `/probe/offline/buffer?principal-id=${principalId}`, {
|
|
88
|
+
method: 'POST',
|
|
89
|
+
headers: { 'content-type': 'application/json' },
|
|
90
|
+
body: JSON.stringify({ idempotencyToken: tokenB, payload: { kind: 'note', body: 'second' } }),
|
|
91
|
+
});
|
|
92
|
+
const enqBBody = JSON.parse(enqB.body || '{}');
|
|
93
|
+
// Reconnect and drain.
|
|
94
|
+
const reconnect = await fixtureFetch(fixture.url, `/probe/offline/reconnect?principal-id=${principalId}`, { method: 'POST' });
|
|
95
|
+
const reconnectBody = JSON.parse(reconnect.body || '{}');
|
|
96
|
+
// Final GET reads state after reconnect: buffer drained.
|
|
97
|
+
const finalState = await fixtureFetch(fixture.url, `/probe/offline/state?principal-id=${principalId}`);
|
|
98
|
+
const finalStateBody = JSON.parse(finalState.body || '{}');
|
|
99
|
+
// Expectations per AC-22105-1:
|
|
100
|
+
// - offline enqueue grows the buffer count on distinct token
|
|
101
|
+
// - duplicate token does not grow the count (dedupe)
|
|
102
|
+
// - reconnect returns flushed count === buffer count at reconnect time
|
|
103
|
+
// - final state shows buffer empty and delivered count rose by the
|
|
104
|
+
// flushed count
|
|
105
|
+
const seededCount = initialState.bufferCount ?? 0;
|
|
106
|
+
const bufferAfterA1 = enqA1Body.bufferCount ?? 0;
|
|
107
|
+
const bufferAfterA2 = enqA2Body.bufferCount ?? 0;
|
|
108
|
+
const bufferAfterB = enqBBody.bufferCount ?? 0;
|
|
109
|
+
const flushedCount = reconnectBody.flushedCount ?? -1;
|
|
110
|
+
const deliveredAfter = finalStateBody.deliveredCount ?? -1;
|
|
111
|
+
const enqueueGrew = bufferAfterA1 === seededCount + 1;
|
|
112
|
+
const deduped = bufferAfterA2 === bufferAfterA1 && enqA2Body.deduped === true;
|
|
113
|
+
const secondEnqueueGrew = bufferAfterB === bufferAfterA1 + 1;
|
|
114
|
+
const flushedMatches = flushedCount === bufferAfterB;
|
|
115
|
+
const drained = (finalStateBody.bufferCount ?? -1) === 0 && finalStateBody.state === 'online';
|
|
116
|
+
const deliveredMatches = deliveredAfter === flushedCount;
|
|
117
|
+
const bufferPass = initial.status === 200 && !!initial.requestId
|
|
118
|
+
&& flipOffline.status === 200
|
|
119
|
+
&& enqA1.status === 200 && enqA2.status === 200 && enqB.status === 200
|
|
120
|
+
&& reconnect.status === 200 && finalState.status === 200
|
|
121
|
+
&& enqueueGrew && deduped && secondEnqueueGrew && flushedMatches && drained && deliveredMatches;
|
|
122
|
+
results.push({
|
|
123
|
+
anchorAcId: null,
|
|
124
|
+
conformanceOnly: true,
|
|
125
|
+
limitation: 'application-empty-error-states-AC-22105-1: the polite live-region announcement of the flushed count and the rendered banner / buffer-count visible on the SPA (the AC clauses beyond the server-side buffer lifecycle) are browser-driven and not observed by this Node HTTP probe; the offline-flip / enqueue / dedupe / reconnect / drain lifecycle is a partial observation of AC-22105-1',
|
|
126
|
+
verdict: bufferPass ? 'warn' : 'fail',
|
|
127
|
+
detail: bufferPass
|
|
128
|
+
? `Given navigator.onLine simulated false via the runtime seam: with the server-side buffer keyed to a fresh principalId, POST /probe/offline/state{state:offline} flipped the state; two distinct idempotency tokens enqueued (buffer count seededCount=${seededCount} -> ${bufferAfterA1} -> ${bufferAfterB}); duplicate token deduped (deduped=${enqA2Body.deduped}, count stayed ${bufferAfterA2}); POST /probe/offline/reconnect drained ${flushedCount} writes; final state shows bufferCount=0, state=online, deliveredCount=${deliveredAfter} equal to flushedCount; x-fixture-request-id (initial GET)=${initial.requestId}`
|
|
129
|
+
: `Given navigator.onLine simulated false via the runtime seam (evidence gap): seeded=${seededCount} afterA1=${bufferAfterA1} afterA2=${bufferAfterA2} afterB=${bufferAfterB} flushed=${flushedCount} delivered=${deliveredAfter} state=${finalStateBody.state} enqueueGrew=${enqueueGrew} deduped=${deduped} secondGrew=${secondEnqueueGrew} flushedMatches=${flushedMatches} drained=${drained} deliveredMatches=${deliveredMatches}`,
|
|
130
|
+
evidence: {
|
|
131
|
+
requestId: initial.requestId,
|
|
132
|
+
responseStatus: initial.status,
|
|
133
|
+
bodyExcerpt: excerpt(JSON.stringify({ initial: initialState, afterEnq: enqBBody, reconnect: reconnectBody, final: finalStateBody })),
|
|
134
|
+
derived: {
|
|
135
|
+
principalId,
|
|
136
|
+
seededCount,
|
|
137
|
+
bufferAfterA1,
|
|
138
|
+
bufferAfterA2,
|
|
139
|
+
bufferAfterB,
|
|
140
|
+
flushedCount,
|
|
141
|
+
deliveredAfter,
|
|
142
|
+
enqueueGrew,
|
|
143
|
+
deduped,
|
|
144
|
+
secondEnqueueGrew,
|
|
145
|
+
flushedMatches,
|
|
146
|
+
drained,
|
|
147
|
+
deliveredMatches,
|
|
148
|
+
},
|
|
149
|
+
},
|
|
150
|
+
});
|
|
151
|
+
} finally {
|
|
152
|
+
await fixture.kill();
|
|
153
|
+
}
|
|
154
|
+
return { results };
|
|
155
|
+
}
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
// Shared helpers for application-empty-error-states contributions/probes/.
|
|
2
|
+
//
|
|
3
|
+
// The real engine for every probe in this pack is the fixture HTTP
|
|
4
|
+
// server at packages/rcf-lite/test/fixtures/probe-pack-application-empty-error-states/server.js
|
|
5
|
+
// booted on a scratch port from the family range 47630-47639.
|
|
6
|
+
// The fixture echoes a per-request x-fixture-request-id header on
|
|
7
|
+
// every response; probes record that id and a response body excerpt
|
|
8
|
+
// as positive evidence per rule 7d.
|
|
9
|
+
//
|
|
10
|
+
// No account credentials or network calls: every probe is
|
|
11
|
+
// local-fixture-driven, so no probe carries an account-bound branch
|
|
12
|
+
// or a CI_HAS_* gate. Declared env vars are the fixture's own
|
|
13
|
+
// PORT and (where the fixture reads them) the CAPS/state switches
|
|
14
|
+
// the probes drive via query string.
|
|
15
|
+
|
|
16
|
+
import { spawn } from 'node:child_process';
|
|
17
|
+
import { mkdir, writeFile } from 'node:fs/promises';
|
|
18
|
+
import { createServer } from 'node:net';
|
|
19
|
+
import { dirname, resolve } from 'node:path';
|
|
20
|
+
import { fileURLToPath } from 'node:url';
|
|
21
|
+
|
|
22
|
+
const HERE = dirname(fileURLToPath(import.meta.url));
|
|
23
|
+
|
|
24
|
+
export const SLUG = 'application-empty-error-states';
|
|
25
|
+
export const PROJECT_ROOT = resolve(HERE, '..', '..', '..', '..');
|
|
26
|
+
export const FIXTURE_DIR = resolve(PROJECT_ROOT, 'packages/rcf-lite/test/fixtures/probe-pack-application-empty-error-states');
|
|
27
|
+
export const REPORT_DIR = resolve(PROJECT_ROOT, '.rcf/reports/blueprints/application-empty-error-states');
|
|
28
|
+
export const PORT_RANGE_START = 47630;
|
|
29
|
+
export const PORT_RANGE_END = 47639;
|
|
30
|
+
export const DECLARED_ENV = Object.freeze(['PORT', 'EMPTY_ERROR_STATES_BREAK', 'PROBE_BREAK']);
|
|
31
|
+
export const REQUEST_ID_HEADER = 'x-fixture-request-id';
|
|
32
|
+
|
|
33
|
+
// Pick a free port from the fixture family range. Falls back to
|
|
34
|
+
// asking the OS for an ephemeral port only if the whole range is
|
|
35
|
+
// held by other workers (never expected on a single-machine run).
|
|
36
|
+
export async function pickPort() {
|
|
37
|
+
for (let port = PORT_RANGE_START; port <= PORT_RANGE_END; port += 1) {
|
|
38
|
+
if (await canBind(port)) return port;
|
|
39
|
+
}
|
|
40
|
+
return await bindEphemeral();
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function canBind(port) {
|
|
44
|
+
return new Promise((res) => {
|
|
45
|
+
const s = createServer();
|
|
46
|
+
s.once('error', () => res(false));
|
|
47
|
+
s.listen(port, '127.0.0.1', () => {
|
|
48
|
+
const bound = s.address();
|
|
49
|
+
s.close(() => res(!!bound));
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function bindEphemeral() {
|
|
55
|
+
return new Promise((res) => {
|
|
56
|
+
const s = createServer();
|
|
57
|
+
s.listen(0, '127.0.0.1', () => {
|
|
58
|
+
const port = s.address().port;
|
|
59
|
+
s.close(() => res(port));
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Spawns the fixture server as a child on `port` with the given
|
|
65
|
+
// env overlay; resolves once the fixture has printed LISTENING and
|
|
66
|
+
// returns { child, url, kill } (kill is synchronous best-effort).
|
|
67
|
+
export async function startFixture({ port, env = {} } = {}) {
|
|
68
|
+
const boundPort = port ?? await pickPort();
|
|
69
|
+
const child = spawn(process.execPath, ['server.js'], {
|
|
70
|
+
cwd: FIXTURE_DIR,
|
|
71
|
+
env: { ...process.env, PORT: String(boundPort), ...env },
|
|
72
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
73
|
+
});
|
|
74
|
+
await new Promise((res, rej) => {
|
|
75
|
+
const timer = setTimeout(() => rej(new Error(`fixture did not print LISTENING within 4s on port ${boundPort}`)), 4000);
|
|
76
|
+
let stderrBuf = '';
|
|
77
|
+
child.stderr.on('data', (chunk) => { stderrBuf += String(chunk); });
|
|
78
|
+
child.on('exit', (code) => rej(new Error(`fixture exited early (code=${code}) stderr=${stderrBuf.slice(0, 400)}`)));
|
|
79
|
+
child.stdout.on('data', (chunk) => {
|
|
80
|
+
if (String(chunk).includes(`LISTENING ${boundPort}`)) { clearTimeout(timer); res(); }
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
const url = new URL(`http://127.0.0.1:${boundPort}`);
|
|
84
|
+
return {
|
|
85
|
+
child,
|
|
86
|
+
url,
|
|
87
|
+
port: boundPort,
|
|
88
|
+
// Await child exit and propagate any error. A teardown failure
|
|
89
|
+
// must fail the verdict (the teardown-propagation rule);
|
|
90
|
+
// no swallowed errors here.
|
|
91
|
+
kill: () => new Promise((res, rej) => {
|
|
92
|
+
let settled = false;
|
|
93
|
+
const done = (err) => { if (settled) return; settled = true; err ? rej(err) : res(); };
|
|
94
|
+
child.once('exit', () => done());
|
|
95
|
+
child.once('error', (err) => done(err));
|
|
96
|
+
try { child.kill('SIGTERM'); } catch (err) { return done(err); }
|
|
97
|
+
setTimeout(() => {
|
|
98
|
+
if (settled) return;
|
|
99
|
+
try { child.kill('SIGKILL'); } catch (err) { return done(err); }
|
|
100
|
+
}, 4000);
|
|
101
|
+
}),
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Issue an HTTP request against the fixture and return
|
|
106
|
+
// { status, headers, body, requestId }.
|
|
107
|
+
export async function fixtureFetch(url, pathAndQuery, init = {}) {
|
|
108
|
+
const target = new URL(pathAndQuery, url);
|
|
109
|
+
const res = await fetch(target, init);
|
|
110
|
+
const body = await res.text();
|
|
111
|
+
const requestId = res.headers.get(REQUEST_ID_HEADER);
|
|
112
|
+
return { status: res.status, headers: Object.fromEntries(res.headers.entries()), body, requestId };
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
export function excerpt(body, maxLen = 240) {
|
|
116
|
+
if (typeof body !== 'string') return '';
|
|
117
|
+
return body.length <= maxLen ? body : body.slice(0, maxLen) + '…';
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export function aggregate(results) {
|
|
121
|
+
// Positive-evidence rule: no-checks-ran is a fail.
|
|
122
|
+
if (!Array.isArray(results) || results.length === 0) return 'fail';
|
|
123
|
+
if (results.some((r) => r.verdict === 'fail')) return 'fail';
|
|
124
|
+
// Any warn row lifts the aggregate to warn, including honest
|
|
125
|
+
// notObservableHere de-claims. A probe whose rows are all warn
|
|
126
|
+
// aggregates to warn, not pass; the shelf reads amber and the tally
|
|
127
|
+
// accepts a warn aggregate as problems=0 when no fail row is present.
|
|
128
|
+
if (results.some((r) => r && r.verdict === 'warn')) return 'warn';
|
|
129
|
+
return 'pass';
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
export async function writeReport({ probeName, engine, results, extra }) {
|
|
133
|
+
await mkdir(REPORT_DIR, { recursive: true });
|
|
134
|
+
const report = {
|
|
135
|
+
slug: SLUG,
|
|
136
|
+
probeName,
|
|
137
|
+
runAt: new Date().toISOString(),
|
|
138
|
+
engine,
|
|
139
|
+
results,
|
|
140
|
+
aggregateVerdict: aggregate(results),
|
|
141
|
+
...(extra ?? {}),
|
|
142
|
+
};
|
|
143
|
+
const filepath = resolve(REPORT_DIR, `${probeName}.json`);
|
|
144
|
+
await writeFile(filepath, JSON.stringify(report, null, 2) + '\n', 'utf8');
|
|
145
|
+
return { report, path: filepath };
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
export async function runShim(probeName, engine, mainFn) {
|
|
149
|
+
try {
|
|
150
|
+
const outcome = (await mainFn()) ?? { results: [] };
|
|
151
|
+
const { results, extra } = outcome;
|
|
152
|
+
const { report, path: filepath } = await writeReport({ probeName, engine, results, extra });
|
|
153
|
+
process.stdout.write(JSON.stringify(report, null, 2) + '\n');
|
|
154
|
+
process.stdout.write(`report written to ${filepath}\n`);
|
|
155
|
+
if (report.aggregateVerdict === 'fail') process.exitCode = 1;
|
|
156
|
+
} catch (err) {
|
|
157
|
+
// Positive-evidence rule (exception fallback): exception rows have no
|
|
158
|
+
// observed AC; anchor null (never a fabricated id like
|
|
159
|
+
// "unknown"), carry an evidence object with the error excerpt.
|
|
160
|
+
const message = err && err.message ? err.message : String(err);
|
|
161
|
+
const stack = err && err.stack ? err.stack : String(err);
|
|
162
|
+
const results = [{
|
|
163
|
+
anchorAcId: null,
|
|
164
|
+
verdict: 'fail',
|
|
165
|
+
detail: `probe threw: ${message}`,
|
|
166
|
+
evidence: {
|
|
167
|
+
errorMessage: message,
|
|
168
|
+
errorExcerpt: excerpt(stack, 480),
|
|
169
|
+
},
|
|
170
|
+
}];
|
|
171
|
+
const { report, path: filepath } = await writeReport({ probeName, engine, results });
|
|
172
|
+
process.stdout.write(JSON.stringify(report, null, 2) + '\n');
|
|
173
|
+
process.stderr.write(`probe error: ${stack}\n`);
|
|
174
|
+
process.stderr.write(`report written to ${filepath}\n`);
|
|
175
|
+
process.exitCode = 1;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import runProbe from './empty-list-and-no-search.mjs';
|
|
2
|
+
import { runShim } from './probe-utils.mjs';
|
|
3
|
+
|
|
4
|
+
const engine = { kind: 'fixture', image: 'test/fixtures/probe-pack-application-empty-error-states/server.js', healthy: true };
|
|
5
|
+
runShim('empty-list-and-no-search', engine, runProbe);
|
package/blueprints/application-empty-error-states/contributions/probes/run-error-boundary-alert.mjs
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import runProbe from './error-boundary-alert.mjs';
|
|
2
|
+
import { runShim } from './probe-utils.mjs';
|
|
3
|
+
|
|
4
|
+
const engine = { kind: 'fixture', image: 'test/fixtures/probe-pack-application-empty-error-states/server.js', healthy: true };
|
|
5
|
+
runShim('error-boundary-alert', engine, runProbe);
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import runProbe from './forbidden-and-server-error.mjs';
|
|
2
|
+
import { runShim } from './probe-utils.mjs';
|
|
3
|
+
|
|
4
|
+
const engine = { kind: 'fixture', image: 'test/fixtures/probe-pack-application-empty-error-states/server.js', healthy: true };
|
|
5
|
+
runShim('forbidden-and-server-error', engine, runProbe);
|