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,376 @@
|
|
|
1
|
+
// Feedback gh adapter (TAC-4107-feedback-gh, ADR-4105). The one place
|
|
2
|
+
// that shells out to gh. Slice 4 (FBS-183) ships:
|
|
3
|
+
//
|
|
4
|
+
// - ghAuthStatus({ host }) probe gh auth for a host
|
|
5
|
+
// - ghLabelList({ repo }) list existing label names
|
|
6
|
+
// - ghRepoView({ repo }) visibility + viewerPermission + hasIssuesEnabled
|
|
7
|
+
// - ghIssueSearch({ repo, query, state, limit }) dedupe search
|
|
8
|
+
// - ghIssueCreate({ repo, title, body, labels }) create one issue
|
|
9
|
+
// - ghIssueComment({ repo, number, body }) +1 comment
|
|
10
|
+
// - ghLabelCreate({ repo, name, description, color }) bootstrap only
|
|
11
|
+
//
|
|
12
|
+
// Every function returns a typed result. Errors are classified into
|
|
13
|
+
// { kind: 'network' | 'notFound' | 'ratelimit' | 'client' | 'server' |
|
|
14
|
+
// 'auth' | 'notInstalled' | 'unknown', message, exitCode? }. The
|
|
15
|
+
// tool never spawns `gh auth login`, never reads GH_TOKEN or
|
|
16
|
+
// GITHUB_TOKEN, never mutates process.env.
|
|
17
|
+
//
|
|
18
|
+
// The RCF_FEEDBACK_GH_MODULE env var names an alternative module the
|
|
19
|
+
// caller can import in place of this file; tests use it to record
|
|
20
|
+
// calls without touching gh. This mirrors the verifier launchAgent
|
|
21
|
+
// override in src/verify/engine/launcher.js.
|
|
22
|
+
|
|
23
|
+
import { spawn } from 'node:child_process';
|
|
24
|
+
import process from 'node:process';
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* @typedef {object} GhOk
|
|
28
|
+
* @property {true} ok
|
|
29
|
+
* @property {any} value
|
|
30
|
+
*/
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* @typedef {object} GhErr
|
|
34
|
+
* @property {false} ok
|
|
35
|
+
* @property {'network' | 'notFound' | 'ratelimit' | 'client' | 'server' | 'auth' | 'notInstalled' | 'search-unavailable' | 'unknown'} kind
|
|
36
|
+
* @property {string} message
|
|
37
|
+
* @property {number} [exitCode]
|
|
38
|
+
*/
|
|
39
|
+
|
|
40
|
+
/** @typedef {GhOk | GhErr} GhResult */
|
|
41
|
+
|
|
42
|
+
const DEFAULT_HOST = 'github.com';
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Load the gh adapter. When RCF_FEEDBACK_GH_MODULE is set, import that
|
|
46
|
+
* module and return it; otherwise return this module's own default
|
|
47
|
+
* exports. The consumer (`src/cli/feedback.js:handleSubmit`) calls
|
|
48
|
+
* this once per invocation.
|
|
49
|
+
*
|
|
50
|
+
* @param {NodeJS.ProcessEnv} [env]
|
|
51
|
+
* @returns {Promise<GhAdapter>}
|
|
52
|
+
*/
|
|
53
|
+
export async function loadGhAdapter(env = process.env) {
|
|
54
|
+
const override = env.RCF_FEEDBACK_GH_MODULE;
|
|
55
|
+
if (typeof override === 'string' && override.length > 0) {
|
|
56
|
+
const mod = await import(override);
|
|
57
|
+
return normaliseAdapter(mod);
|
|
58
|
+
}
|
|
59
|
+
return DEFAULT_ADAPTER;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Adapter shape (also what a test fake must provide). Every function
|
|
64
|
+
* takes an options object and returns a Promise<GhResult>.
|
|
65
|
+
*
|
|
66
|
+
* @typedef {object} GhAdapter
|
|
67
|
+
* @property {(opts?: { host?: string }) => Promise<GhResult>} ghAuthStatus
|
|
68
|
+
* @property {(opts: { repo: string }) => Promise<GhResult>} ghLabelList
|
|
69
|
+
* @property {(opts: { repo: string }) => Promise<GhResult>} ghRepoView
|
|
70
|
+
* @property {(opts: { repo: string, query: string, state?: 'open' | 'closed', limit?: number }) => Promise<GhResult>} ghIssueSearch
|
|
71
|
+
* @property {(opts: { repo: string, title: string, body: string, labels: string[] }) => Promise<GhResult>} ghIssueCreate
|
|
72
|
+
* @property {(opts: { repo: string, number: number, body: string }) => Promise<GhResult>} ghIssueComment
|
|
73
|
+
* @property {(opts: { repo: string, name: string, description?: string, color?: string }) => Promise<GhResult>} ghLabelCreate
|
|
74
|
+
* @property {() => Promise<GhResult>} [ghOnPath]
|
|
75
|
+
*/
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Return an { ok: true, value: { present: boolean } } result naming
|
|
79
|
+
* whether the `gh` binary is on PATH. The default adapter shells out
|
|
80
|
+
* to `gh --version`; a test fake overrides through the seam.
|
|
81
|
+
*
|
|
82
|
+
* @returns {Promise<GhResult>}
|
|
83
|
+
*/
|
|
84
|
+
export async function ghOnPath() {
|
|
85
|
+
const r = await runGh(['--version']);
|
|
86
|
+
if (r.ok) return { ok: true, value: { present: true } };
|
|
87
|
+
if (r.kind === 'notInstalled') return { ok: true, value: { present: false } };
|
|
88
|
+
return r;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* `gh auth status --hostname <host>` exit 0 means logged in on that
|
|
93
|
+
* host. gh writes the status to stderr; a non-zero exit is the auth
|
|
94
|
+
* failure the design section 7 fallback keys off.
|
|
95
|
+
*
|
|
96
|
+
* @param {{ host?: string }} [opts]
|
|
97
|
+
* @returns {Promise<GhResult>}
|
|
98
|
+
*/
|
|
99
|
+
export async function ghAuthStatus(opts = {}) {
|
|
100
|
+
const host = opts.host ?? DEFAULT_HOST;
|
|
101
|
+
const r = await runGh(['auth', 'status', '--hostname', host]);
|
|
102
|
+
if (r.ok) return { ok: true, value: { authed: true, host } };
|
|
103
|
+
if (r.kind === 'notInstalled') return r;
|
|
104
|
+
return { ok: false, kind: 'auth', message: `not logged in to ${host}`, exitCode: r.exitCode };
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* `gh label list --repo <repo> --json name` returns [{ name }, ...].
|
|
109
|
+
* A repo without labels returns []. A repo you cannot see returns
|
|
110
|
+
* an auth or notFound error; the caller treats either as "labels
|
|
111
|
+
* unknown" and drops all label requests.
|
|
112
|
+
*
|
|
113
|
+
* @param {{ repo: string }} opts
|
|
114
|
+
* @returns {Promise<GhResult>}
|
|
115
|
+
*/
|
|
116
|
+
export async function ghLabelList(opts) {
|
|
117
|
+
const r = await runGh(['label', 'list', '--repo', opts.repo, '--json', 'name', '--limit', '100']);
|
|
118
|
+
if (!r.ok) return r;
|
|
119
|
+
try {
|
|
120
|
+
const parsed = JSON.parse(r.value.stdout);
|
|
121
|
+
const names = Array.isArray(parsed) ? parsed.map((row) => row?.name).filter((n) => typeof n === 'string') : [];
|
|
122
|
+
return { ok: true, value: { names } };
|
|
123
|
+
} catch (err) {
|
|
124
|
+
return { ok: false, kind: 'unknown', message: `label list parse failed: ${err.message}` };
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* `gh repo view <repo> --json visibility,viewerPermission,hasIssuesEnabled`.
|
|
130
|
+
*
|
|
131
|
+
* @param {{ repo: string }} opts
|
|
132
|
+
* @returns {Promise<GhResult>}
|
|
133
|
+
*/
|
|
134
|
+
export async function ghRepoView(opts) {
|
|
135
|
+
const r = await runGh(['repo', 'view', opts.repo, '--json', 'visibility,viewerPermission,hasIssuesEnabled']);
|
|
136
|
+
if (!r.ok) return r;
|
|
137
|
+
try {
|
|
138
|
+
const parsed = JSON.parse(r.value.stdout);
|
|
139
|
+
return {
|
|
140
|
+
ok: true,
|
|
141
|
+
value: {
|
|
142
|
+
visibility: parsed?.visibility ?? null,
|
|
143
|
+
viewerPermission: parsed?.viewerPermission ?? null,
|
|
144
|
+
hasIssuesEnabled: parsed?.hasIssuesEnabled ?? null,
|
|
145
|
+
},
|
|
146
|
+
};
|
|
147
|
+
} catch (err) {
|
|
148
|
+
return { ok: false, kind: 'unknown', message: `repo view parse failed: ${err.message}` };
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* `gh search issues <query> --repo <repo> --state <state> --json
|
|
154
|
+
* number,url,title --limit <n>`. Slice 4 uses `--match body` via the
|
|
155
|
+
* query syntax "in:body <query>" so the dedupe search hits the
|
|
156
|
+
* fingerprint line. Search may be off on GHES and rate-limited on
|
|
157
|
+
* github.com; both fold to a search-unavailable error the caller
|
|
158
|
+
* treats as "fall through to create".
|
|
159
|
+
*
|
|
160
|
+
* @param {{ repo: string, query: string, state?: 'open' | 'closed', limit?: number }} opts
|
|
161
|
+
* @returns {Promise<GhResult>}
|
|
162
|
+
*/
|
|
163
|
+
export async function ghIssueSearch(opts) {
|
|
164
|
+
const state = opts.state ?? 'open';
|
|
165
|
+
const limit = String(opts.limit ?? 5);
|
|
166
|
+
const args = [
|
|
167
|
+
'search', 'issues',
|
|
168
|
+
`in:body ${opts.query}`,
|
|
169
|
+
'--repo', opts.repo,
|
|
170
|
+
'--state', state,
|
|
171
|
+
'--json', 'number,url,title',
|
|
172
|
+
'--limit', limit,
|
|
173
|
+
];
|
|
174
|
+
const r = await runGh(args);
|
|
175
|
+
if (!r.ok) {
|
|
176
|
+
if (r.kind === 'ratelimit' || r.kind === 'server') {
|
|
177
|
+
return { ok: false, kind: 'search-unavailable', message: r.message, exitCode: r.exitCode };
|
|
178
|
+
}
|
|
179
|
+
return r;
|
|
180
|
+
}
|
|
181
|
+
try {
|
|
182
|
+
const parsed = JSON.parse(r.value.stdout);
|
|
183
|
+
const matches = Array.isArray(parsed)
|
|
184
|
+
? parsed.filter((m) => m && typeof m.number === 'number')
|
|
185
|
+
: [];
|
|
186
|
+
return { ok: true, value: { matches } };
|
|
187
|
+
} catch (err) {
|
|
188
|
+
return { ok: false, kind: 'search-unavailable', message: `search parse failed: ${err.message}` };
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* `gh issue create --repo <repo> --title <t> --body-file - --label
|
|
194
|
+
* <l1> --label <l2>...` reads the body from stdin so a long body is
|
|
195
|
+
* safe across every shell. Returns { url, number }.
|
|
196
|
+
*
|
|
197
|
+
* @param {{ repo: string, title: string, body: string, labels: string[] }} opts
|
|
198
|
+
* @returns {Promise<GhResult>}
|
|
199
|
+
*/
|
|
200
|
+
export async function ghIssueCreate(opts) {
|
|
201
|
+
const args = ['issue', 'create', '--repo', opts.repo, '--title', opts.title, '--body-file', '-'];
|
|
202
|
+
for (const l of opts.labels ?? []) args.push('--label', l);
|
|
203
|
+
const r = await runGh(args, { stdin: opts.body });
|
|
204
|
+
if (!r.ok) return r;
|
|
205
|
+
const url = extractIssueUrl(r.value.stdout);
|
|
206
|
+
const number = extractIssueNumber(url);
|
|
207
|
+
return { ok: true, value: { url, number } };
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* `gh issue comment <number> --repo <repo> --body-file -`. Returns
|
|
212
|
+
* { url }.
|
|
213
|
+
*
|
|
214
|
+
* @param {{ repo: string, number: number, body: string }} opts
|
|
215
|
+
* @returns {Promise<GhResult>}
|
|
216
|
+
*/
|
|
217
|
+
export async function ghIssueComment(opts) {
|
|
218
|
+
const args = ['issue', 'comment', String(opts.number), '--repo', opts.repo, '--body-file', '-'];
|
|
219
|
+
const r = await runGh(args, { stdin: opts.body });
|
|
220
|
+
if (!r.ok) return r;
|
|
221
|
+
const url = (r.value.stdout || '').trim().split(/\s+/).pop() || '';
|
|
222
|
+
return { ok: true, value: { url } };
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* `gh label create <name> --repo <repo> --description <d> --color <c>`.
|
|
227
|
+
* Only used by scripts/bootstrap-feedback-labels.mjs; the tool proper
|
|
228
|
+
* never creates labels on submit.
|
|
229
|
+
*
|
|
230
|
+
* @param {{ repo: string, name: string, description?: string, color?: string }} opts
|
|
231
|
+
* @returns {Promise<GhResult>}
|
|
232
|
+
*/
|
|
233
|
+
export async function ghLabelCreate(opts) {
|
|
234
|
+
const args = ['label', 'create', opts.name, '--repo', opts.repo];
|
|
235
|
+
if (opts.description) args.push('--description', opts.description);
|
|
236
|
+
if (opts.color) args.push('--color', opts.color);
|
|
237
|
+
const r = await runGh(args);
|
|
238
|
+
if (!r.ok) return r;
|
|
239
|
+
return { ok: true, value: { name: opts.name } };
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
// -- helpers --------------------------------------------------------------
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* Spawn gh with the given args, capture stdout/stderr, and classify
|
|
246
|
+
* failures. We pass a filtered environment (no synthesised TOKEN keys)
|
|
247
|
+
* so a test can assert the tool never invents credentials.
|
|
248
|
+
*
|
|
249
|
+
* @param {string[]} args
|
|
250
|
+
* @param {{ stdin?: string, env?: NodeJS.ProcessEnv }} [opts]
|
|
251
|
+
* @returns {Promise<GhResult>}
|
|
252
|
+
*/
|
|
253
|
+
async function runGh(args, opts = {}) {
|
|
254
|
+
return new Promise((resolvePromise) => {
|
|
255
|
+
let child;
|
|
256
|
+
try {
|
|
257
|
+
child = spawn('gh', args, {
|
|
258
|
+
env: opts.env ?? process.env,
|
|
259
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
260
|
+
});
|
|
261
|
+
} catch (err) {
|
|
262
|
+
resolvePromise({ ok: false, kind: classifySpawnError(err), message: err.message });
|
|
263
|
+
return;
|
|
264
|
+
}
|
|
265
|
+
let stdout = '';
|
|
266
|
+
let stderr = '';
|
|
267
|
+
child.stdout.on('data', (chunk) => { stdout += chunk.toString('utf8'); });
|
|
268
|
+
child.stderr.on('data', (chunk) => { stderr += chunk.toString('utf8'); });
|
|
269
|
+
child.on('error', (err) => {
|
|
270
|
+
resolvePromise({ ok: false, kind: classifySpawnError(err), message: err.message });
|
|
271
|
+
});
|
|
272
|
+
child.on('close', (code) => {
|
|
273
|
+
if (code === 0) {
|
|
274
|
+
resolvePromise({ ok: true, value: { stdout, stderr } });
|
|
275
|
+
return;
|
|
276
|
+
}
|
|
277
|
+
resolvePromise({
|
|
278
|
+
ok: false,
|
|
279
|
+
kind: classifyExit(code, stderr),
|
|
280
|
+
message: stderr.trim() || `gh exited with code ${code}`,
|
|
281
|
+
exitCode: code ?? undefined,
|
|
282
|
+
});
|
|
283
|
+
});
|
|
284
|
+
if (typeof opts.stdin === 'string') {
|
|
285
|
+
child.stdin.end(opts.stdin);
|
|
286
|
+
} else {
|
|
287
|
+
child.stdin.end();
|
|
288
|
+
}
|
|
289
|
+
});
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
/**
|
|
293
|
+
* Classify a spawn-time error. ENOENT means gh is not on PATH.
|
|
294
|
+
*
|
|
295
|
+
* @param {NodeJS.ErrnoException} err
|
|
296
|
+
* @returns {GhErr['kind']}
|
|
297
|
+
*/
|
|
298
|
+
function classifySpawnError(err) {
|
|
299
|
+
if (err && err.code === 'ENOENT') return 'notInstalled';
|
|
300
|
+
return 'unknown';
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
/**
|
|
304
|
+
* Classify a non-zero gh exit into one of the error kinds the caller
|
|
305
|
+
* keys off. Uses stderr substrings because gh does not emit machine
|
|
306
|
+
* codes; the shapes below are stable across recent gh versions.
|
|
307
|
+
*
|
|
308
|
+
* @param {number | null} code
|
|
309
|
+
* @param {string} stderr
|
|
310
|
+
* @returns {GhErr['kind']}
|
|
311
|
+
*/
|
|
312
|
+
function classifyExit(code, stderr) {
|
|
313
|
+
const s = (stderr || '').toLowerCase();
|
|
314
|
+
if (/(rate limit|abuse|secondary rate)/.test(s)) return 'ratelimit';
|
|
315
|
+
if (/(not found|could not resolve|http 404)/.test(s)) return 'notFound';
|
|
316
|
+
if (/(unauthorised|unauthorized|http 401|not logged in|authentication)/.test(s)) return 'auth';
|
|
317
|
+
if (/(http 5\d\d|internal server error)/.test(s)) return 'server';
|
|
318
|
+
if (/(http 4\d\d)/.test(s)) return 'client';
|
|
319
|
+
if (/(network|econnrefused|etimedout|dial tcp|dns)/.test(s)) return 'network';
|
|
320
|
+
return 'unknown';
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
/**
|
|
324
|
+
* Extract the issue url from gh's `issue create` stdout (which is
|
|
325
|
+
* usually just the URL on its own line, possibly followed by a
|
|
326
|
+
* trailing newline).
|
|
327
|
+
*
|
|
328
|
+
* @param {string} stdout
|
|
329
|
+
* @returns {string}
|
|
330
|
+
*/
|
|
331
|
+
function extractIssueUrl(stdout) {
|
|
332
|
+
const m = (stdout || '').match(/https?:\/\/[^\s]+/);
|
|
333
|
+
return m ? m[0] : '';
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
/**
|
|
337
|
+
* Extract the issue number from a gh issue url.
|
|
338
|
+
*
|
|
339
|
+
* @param {string} url
|
|
340
|
+
* @returns {number | null}
|
|
341
|
+
*/
|
|
342
|
+
function extractIssueNumber(url) {
|
|
343
|
+
const m = (url || '').match(/\/issues\/(\d+)/);
|
|
344
|
+
return m ? Number(m[1]) : null;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
/**
|
|
348
|
+
* Normalise an override module: allow either a default export or
|
|
349
|
+
* per-name exports; a partial module falls back to the default
|
|
350
|
+
* implementations here for anything it does not override.
|
|
351
|
+
*
|
|
352
|
+
* @param {any} mod
|
|
353
|
+
* @returns {GhAdapter}
|
|
354
|
+
*/
|
|
355
|
+
function normaliseAdapter(mod) {
|
|
356
|
+
const base = { ...DEFAULT_ADAPTER };
|
|
357
|
+
const src = mod && typeof mod === 'object' && mod.default && typeof mod.default === 'object'
|
|
358
|
+
? { ...mod, ...mod.default }
|
|
359
|
+
: mod;
|
|
360
|
+
for (const key of Object.keys(base)) {
|
|
361
|
+
if (typeof src?.[key] === 'function') base[key] = src[key];
|
|
362
|
+
}
|
|
363
|
+
return base;
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
/** Default adapter (this module's own implementations). */
|
|
367
|
+
export const DEFAULT_ADAPTER = Object.freeze({
|
|
368
|
+
ghOnPath,
|
|
369
|
+
ghAuthStatus,
|
|
370
|
+
ghLabelList,
|
|
371
|
+
ghRepoView,
|
|
372
|
+
ghIssueSearch,
|
|
373
|
+
ghIssueCreate,
|
|
374
|
+
ghIssueComment,
|
|
375
|
+
ghLabelCreate,
|
|
376
|
+
});
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
// Feedback harness hook (TAC-4108). Slice 5 (FBS-184): the ask.
|
|
2
|
+
//
|
|
3
|
+
// Two exports are the load-bearing surface:
|
|
4
|
+
// - `shouldAsk(state)` is a pure function over the design 3.5 inputs
|
|
5
|
+
// that returns 'ask' or 'silent'; every quiet-rule branch runs
|
|
6
|
+
// through it and every unit-test truth table drives it directly.
|
|
7
|
+
// - `emit(harness, decision, message)` writes the per-harness output
|
|
8
|
+
// shape (Claude Code: exit 2 + stderr; Codex: stdout JSON block)
|
|
9
|
+
// and returns the exit code the CLI wrapper propagates.
|
|
10
|
+
//
|
|
11
|
+
// The CLI wrapper (`rcf feedback hook stop|session-end|session-start`
|
|
12
|
+
// dispatched from `src/cli/feedback.js`) reads the harness JSON from
|
|
13
|
+
// stdin, gathers the store inputs (settings, pending entries, ask
|
|
14
|
+
// ledger, prior sessionId), calls `shouldAsk` and then `emit`, and
|
|
15
|
+
// (crucially) APPENDS the asked ledger record BEFORE the emit so a
|
|
16
|
+
// crash between emit and reply cannot cause a second ask.
|
|
17
|
+
//
|
|
18
|
+
// Design references: sections 3.5 (quiet rule + per-harness shape),
|
|
19
|
+
// 8 (settings and env vars), 9 (Stop is the ask event ADR), 10.3
|
|
20
|
+
// (quietMinutes default 15).
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Reason text the hook feeds Claude Code (stderr) or Codex (JSON
|
|
24
|
+
* `reason`). Exported so a caller can assemble a locally augmented
|
|
25
|
+
* variant (e.g. prefixing the outbox path from a carried-over session)
|
|
26
|
+
* without re-typing the four verb names. Kept STATIC so the managed
|
|
27
|
+
* block's hash-verified RULE 17 slice 6 text can pin the same verbs
|
|
28
|
+
* once, in one place.
|
|
29
|
+
*
|
|
30
|
+
* @param {number} pendingCount
|
|
31
|
+
* @returns {string}
|
|
32
|
+
*/
|
|
33
|
+
export function buildAskReason(pendingCount) {
|
|
34
|
+
const n = Math.max(1, Number(pendingCount) || 1);
|
|
35
|
+
const noun = n === 1 ? 'entry' : 'entries';
|
|
36
|
+
return `rcf feedback: ${n} unsubmitted ${noun} on this project. `
|
|
37
|
+
+ "Run 'rcf feedback preview', show the operator the titles, "
|
|
38
|
+
+ 'bodies and destination it prints, ask once whether to send '
|
|
39
|
+
+ "them, then run 'rcf feedback submit --yes', "
|
|
40
|
+
+ "'rcf feedback defer' or 'rcf feedback opt-out'. "
|
|
41
|
+
+ 'Do not ask again this session.';
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Reason text the SessionStart hook injects on either harness when
|
|
46
|
+
* one or more pending entries carried over from a prior session. The
|
|
47
|
+
* wording mirrors RULE 17's ask contract without prescribing verbs
|
|
48
|
+
* (SessionStart runs before any operator prompt; the ask itself
|
|
49
|
+
* arrives on Stop).
|
|
50
|
+
*
|
|
51
|
+
* @param {number} pendingCount
|
|
52
|
+
* @returns {string}
|
|
53
|
+
*/
|
|
54
|
+
export function buildCarryOverLine(pendingCount) {
|
|
55
|
+
const n = Math.max(1, Number(pendingCount) || 1);
|
|
56
|
+
const noun = n === 1 ? 'entry' : 'entries';
|
|
57
|
+
return `rcf feedback: ${n} unsubmitted ${noun} carried over `
|
|
58
|
+
+ 'from an earlier session; ask the operator once at a natural '
|
|
59
|
+
+ 'pause (RULE 17).';
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* @typedef {object} QuietRuleState
|
|
64
|
+
* @property {boolean} optedOut file `ask: false` or env silence
|
|
65
|
+
* @property {number} pendingCount pending entries visible to the
|
|
66
|
+
* hook right now
|
|
67
|
+
* @property {boolean} askedThisSession `state.json` already recorded
|
|
68
|
+
* an `asked` entry for the
|
|
69
|
+
* incoming sessionId
|
|
70
|
+
* @property {boolean} stopHookActive Claude Code / Codex loop guard
|
|
71
|
+
* @property {boolean} anyAskNow one or more pending entries
|
|
72
|
+
* carry askNow: true
|
|
73
|
+
* @property {number | null} newestPendingAgeMs
|
|
74
|
+
* milliseconds since the newest
|
|
75
|
+
* pending entry was recorded, or
|
|
76
|
+
* null when nothing is pending
|
|
77
|
+
* @property {number} quietMinutes operator-configurable gate; the
|
|
78
|
+
* caller resolves the default (15)
|
|
79
|
+
* @property {boolean} queueComplete `.rcf/feedback/state.json`
|
|
80
|
+
* `queueStateAt` cached
|
|
81
|
+
* complete / nothing-actionable
|
|
82
|
+
* @property {boolean} anyCarriedOver one or more pending entries were
|
|
83
|
+
* recorded under a prior sessionId
|
|
84
|
+
*/
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Pure quiet-rule decision (design 3.5, ADR-4107).
|
|
88
|
+
*
|
|
89
|
+
* Ask on `stop` when ALL hold:
|
|
90
|
+
* - not opted out (per-project file OR per-user env);
|
|
91
|
+
* - pending entries exist;
|
|
92
|
+
* - no `asked` record for this session_id in `state.json`;
|
|
93
|
+
* - `stop_hook_active` is false (Claude Code loop guard; Codex
|
|
94
|
+
* sends the same field);
|
|
95
|
+
* - AND one of: an entry carries askNow; the newest pending entry
|
|
96
|
+
* is older than quietMinutes; queue-state cache reports complete
|
|
97
|
+
* or nothing-actionable; the entry was carried over from an
|
|
98
|
+
* earlier session.
|
|
99
|
+
*
|
|
100
|
+
* Otherwise, exit silent. The function is total, deterministic, and
|
|
101
|
+
* has no side effects; unit tests drive it directly from a truth
|
|
102
|
+
* table and the wrapper only calls it once per invocation.
|
|
103
|
+
*
|
|
104
|
+
* @param {QuietRuleState} state
|
|
105
|
+
* @returns {'ask' | 'silent'}
|
|
106
|
+
*/
|
|
107
|
+
export function shouldAsk(state) {
|
|
108
|
+
if (!state) return 'silent';
|
|
109
|
+
if (state.optedOut) return 'silent';
|
|
110
|
+
if (!Number.isFinite(state.pendingCount) || state.pendingCount <= 0) return 'silent';
|
|
111
|
+
if (state.askedThisSession) return 'silent';
|
|
112
|
+
if (state.stopHookActive) return 'silent';
|
|
113
|
+
|
|
114
|
+
const quietMinutes = Number.isFinite(state.quietMinutes) && state.quietMinutes >= 0
|
|
115
|
+
? state.quietMinutes
|
|
116
|
+
: 15;
|
|
117
|
+
const ageMs = typeof state.newestPendingAgeMs === 'number'
|
|
118
|
+
? state.newestPendingAgeMs
|
|
119
|
+
: null;
|
|
120
|
+
const olderThanQuiet = ageMs !== null && ageMs >= quietMinutes * 60_000;
|
|
121
|
+
|
|
122
|
+
const triggerAny = Boolean(state.anyAskNow)
|
|
123
|
+
|| olderThanQuiet
|
|
124
|
+
|| Boolean(state.queueComplete)
|
|
125
|
+
|| Boolean(state.anyCarriedOver);
|
|
126
|
+
return triggerAny ? 'ask' : 'silent';
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Per-harness emit shape. Writes to the passed streams and returns
|
|
131
|
+
* the exit code the wrapper should propagate. The reason is written
|
|
132
|
+
* VERBATIM; callers pass the text `buildAskReason` (or their own
|
|
133
|
+
* augmented variant) produced. On `silent` no bytes are written on
|
|
134
|
+
* either stream and the exit code is 0 on both harnesses.
|
|
135
|
+
*
|
|
136
|
+
* @param {'claude-code' | 'codex'} harness
|
|
137
|
+
* @param {'ask' | 'silent'} decision
|
|
138
|
+
* @param {string} reason
|
|
139
|
+
* @param {{ stdout: NodeJS.WritableStream, stderr: NodeJS.WritableStream }} streams
|
|
140
|
+
* @returns {number} exit code the wrapper propagates
|
|
141
|
+
*/
|
|
142
|
+
export function emit(harness, decision, reason, streams) {
|
|
143
|
+
if (decision !== 'ask') return 0;
|
|
144
|
+
const stdout = streams?.stdout;
|
|
145
|
+
const stderr = streams?.stderr;
|
|
146
|
+
if (harness === 'codex') {
|
|
147
|
+
// Codex requires JSON on stdout with { decision: 'block', reason };
|
|
148
|
+
// plain text is invalid. The wrapper still exits 0 (Codex reads
|
|
149
|
+
// the decision, not the exit code, on Stop).
|
|
150
|
+
const payload = { decision: 'block', reason };
|
|
151
|
+
stdout?.write(`${JSON.stringify(payload)}\n`);
|
|
152
|
+
return 0;
|
|
153
|
+
}
|
|
154
|
+
// Claude Code default: exit 2 with the reason on stderr. Claude
|
|
155
|
+
// Code feeds the reason back to Claude, which speaks to the user.
|
|
156
|
+
stderr?.write(`${reason}\n`);
|
|
157
|
+
return 2;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* SessionStart emit: one plain line for Claude Code (harness picks it
|
|
162
|
+
* up as context), a JSON `additionalContext` shape for Codex. Both
|
|
163
|
+
* return exit 0; the ledger is NOT touched on SessionStart (ask still
|
|
164
|
+
* runs on Stop). If the Codex build in use does not accept a
|
|
165
|
+
* SessionStart additionalContext, the RULE 17 fallback ("check
|
|
166
|
+
* `rcf feedback status` at session start") carries the same posture;
|
|
167
|
+
* the wrapper falls back gracefully.
|
|
168
|
+
*
|
|
169
|
+
* @param {'claude-code' | 'codex'} harness
|
|
170
|
+
* @param {string} line
|
|
171
|
+
* @param {{ stdout: NodeJS.WritableStream }} streams
|
|
172
|
+
* @returns {number} exit code the wrapper propagates
|
|
173
|
+
*/
|
|
174
|
+
export function emitSessionStart(harness, line, streams) {
|
|
175
|
+
const stdout = streams?.stdout;
|
|
176
|
+
if (!line) return 0;
|
|
177
|
+
if (harness === 'codex') {
|
|
178
|
+
stdout?.write(`${JSON.stringify({ additionalContext: line })}\n`);
|
|
179
|
+
return 0;
|
|
180
|
+
}
|
|
181
|
+
stdout?.write(`${line}\n`);
|
|
182
|
+
return 0;
|
|
183
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
// Feedback label catalogue (TAC-4105-feedback-render, AC-15902-4). The
|
|
2
|
+
// six labels the tool asks GitHub to apply on create, and the same
|
|
3
|
+
// six the maintainer bootstrap script creates on a destination repo.
|
|
4
|
+
//
|
|
5
|
+
// F-6 gate finding: keep the catalogue as a single exported constant
|
|
6
|
+
// so the label pre-check on submit, the render.js default-labels
|
|
7
|
+
// helper, and the bootstrap script all consume one source of truth.
|
|
8
|
+
// A grep test (test/feedback/labels-catalogue.test.js) refuses bare
|
|
9
|
+
// literals for these names anywhere else under src/ or scripts/.
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* The six bootstrap labels (ADR-4102). Frozen so a downstream mutation
|
|
13
|
+
* would throw rather than silently drift.
|
|
14
|
+
*
|
|
15
|
+
* @type {readonly [string, string, string, string, string, string]}
|
|
16
|
+
*/
|
|
17
|
+
export const FEEDBACK_LABELS = Object.freeze([
|
|
18
|
+
'rcf-feedback',
|
|
19
|
+
'severity:blocker',
|
|
20
|
+
'severity:major',
|
|
21
|
+
'severity:minor',
|
|
22
|
+
'area:blueprint',
|
|
23
|
+
'area:core',
|
|
24
|
+
]);
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Machine-readable description of each label (for the bootstrap
|
|
28
|
+
* script's `gh label create` call, which wants a `--description` and
|
|
29
|
+
* a `--color`). Same order as `FEEDBACK_LABELS`.
|
|
30
|
+
*/
|
|
31
|
+
export const FEEDBACK_LABEL_DEFINITIONS = Object.freeze([
|
|
32
|
+
{ name: 'rcf-feedback', description: 'Filed by rcf-lite feedback verb', color: '5319E7' },
|
|
33
|
+
{ name: 'severity:blocker', description: 'Blocks a workflow with no workaround', color: 'B60205' },
|
|
34
|
+
{ name: 'severity:major', description: 'Significant impact, workaround exists', color: 'D93F0B' },
|
|
35
|
+
{ name: 'severity:minor', description: 'Small friction or cosmetic', color: 'FBCA04' },
|
|
36
|
+
{ name: 'area:blueprint', description: 'About a blueprint (shelf or library)', color: '0E8A16' },
|
|
37
|
+
{ name: 'area:core', description: 'About the rcf-lite core CLI or docs', color: '1D76DB' },
|
|
38
|
+
]);
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* The three labels the tool asks for on a given entry (subset of the
|
|
42
|
+
* six above). `severity:<sev>` and `area:<blueprint|core>` are picked
|
|
43
|
+
* per entry; `rcf-feedback` is always requested.
|
|
44
|
+
*
|
|
45
|
+
* Callers pass the severity and the kind; the returned array is the
|
|
46
|
+
* request, before the label pre-check narrows it to what exists on
|
|
47
|
+
* the destination repo.
|
|
48
|
+
*
|
|
49
|
+
* @param {'blocker' | 'major' | 'minor'} severity
|
|
50
|
+
* @param {'blueprint' | 'core'} kind
|
|
51
|
+
* @returns {string[]}
|
|
52
|
+
*/
|
|
53
|
+
export function labelsForEntry(severity, kind) {
|
|
54
|
+
const out = [FEEDBACK_LABELS[0]];
|
|
55
|
+
const sevLabel = severityLabel(severity);
|
|
56
|
+
if (sevLabel) out.push(sevLabel);
|
|
57
|
+
const areaLabel = areaLabelForKind(kind);
|
|
58
|
+
if (areaLabel) out.push(areaLabel);
|
|
59
|
+
return out;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* `severity:<blocker|major|minor>` from the entry's severity, or null
|
|
64
|
+
* if it is not one of the three (defensive; the enum is fixed).
|
|
65
|
+
*
|
|
66
|
+
* @param {string | undefined | null} severity
|
|
67
|
+
* @returns {string | null}
|
|
68
|
+
*/
|
|
69
|
+
export function severityLabel(severity) {
|
|
70
|
+
if (severity === 'blocker') return FEEDBACK_LABELS[1];
|
|
71
|
+
if (severity === 'major') return FEEDBACK_LABELS[2];
|
|
72
|
+
if (severity === 'minor') return FEEDBACK_LABELS[3];
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* `area:blueprint` or `area:core` from the entry's kind, or null on
|
|
78
|
+
* anything else.
|
|
79
|
+
*
|
|
80
|
+
* @param {string | undefined | null} kind
|
|
81
|
+
* @returns {string | null}
|
|
82
|
+
*/
|
|
83
|
+
export function areaLabelForKind(kind) {
|
|
84
|
+
if (kind === 'blueprint') return FEEDBACK_LABELS[4];
|
|
85
|
+
if (kind === 'core') return FEEDBACK_LABELS[5];
|
|
86
|
+
return null;
|
|
87
|
+
}
|