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,604 @@
|
|
|
1
|
+
// Feedback local store (TAC-4102). Slice 1 (FBS-180): the on-disk log
|
|
2
|
+
// under `.rcf/feedback/`. Append-only JSONL for entries, fold-by-id on
|
|
3
|
+
// read; a per-session state ledger at `state.json`; an outbox directory
|
|
4
|
+
// for bundle files (written in slice 4, referenced here so the store's
|
|
5
|
+
// path helpers are complete).
|
|
6
|
+
//
|
|
7
|
+
// The store is gitignored via the 0.6.0 managed-block aggregator
|
|
8
|
+
// (`src/setup/managed-gitignore.js`). This module OWNS the aggregator
|
|
9
|
+
// entry constant (`feedbackGitignoreEntry`), mirroring the pattern in
|
|
10
|
+
// `src/preflight/secrets.js:preflightEntry` and
|
|
11
|
+
// `src/setup/identity-seed.js:identityEntry`. Adding it to the
|
|
12
|
+
// aggregator is a one-import, one-array-line change.
|
|
13
|
+
//
|
|
14
|
+
// A pre-write refusal (`ensureGitignore`) is the belt to the aggregator's
|
|
15
|
+
// braces: on a project whose `.gitignore` does not effectively cover
|
|
16
|
+
// `.rcf/feedback/` the first `rcf feedback add` refuses instead of
|
|
17
|
+
// creating the log, protecting a pre-upgrade project against an
|
|
18
|
+
// accidental push of raw entries. `--force` overrides for the test
|
|
19
|
+
// path and for the operator who has audited their `.gitignore` by
|
|
20
|
+
// hand.
|
|
21
|
+
|
|
22
|
+
import {
|
|
23
|
+
appendFile, mkdir, readFile, stat, writeFile,
|
|
24
|
+
} from 'node:fs/promises';
|
|
25
|
+
import { dirname, join } from 'node:path';
|
|
26
|
+
import { spawn } from 'node:child_process';
|
|
27
|
+
|
|
28
|
+
/** Absolute path helpers under a project root. */
|
|
29
|
+
const FEEDBACK_DIR = '.rcf/feedback';
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Relative path (from project root) of the per-project feedback
|
|
33
|
+
* settings file. Committed to the repo; the hooks and the CLI treat
|
|
34
|
+
* this as the source of truth for `ask`, `quietMinutes` and the
|
|
35
|
+
* `redaction.allowHosts` extension list (design section 8).
|
|
36
|
+
*/
|
|
37
|
+
export const FEEDBACK_SETTINGS_PATH = 'rcf/feedback-settings.json';
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Default settings the hook and the ask-branch fall back to when
|
|
41
|
+
* `rcf/feedback-settings.json` is missing or empty. `ask: true` keeps
|
|
42
|
+
* the RULE 17 posture: silent capture, one ask per session at a
|
|
43
|
+
* pause, unless the operator has opted out for the project.
|
|
44
|
+
*/
|
|
45
|
+
export const DEFAULT_FEEDBACK_SETTINGS = Object.freeze({
|
|
46
|
+
settingsVersion: 1,
|
|
47
|
+
ask: true,
|
|
48
|
+
quietMinutes: 15,
|
|
49
|
+
redaction: Object.freeze({ allowHosts: [] }),
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Managed-gitignore aggregator entry (§4.1's 0.7.0-style extension:
|
|
54
|
+
* feature modules own their entry constant; the aggregator imports it).
|
|
55
|
+
* The trailing slash keeps the whole directory ignored (log, state,
|
|
56
|
+
* outbox and any future sibling files).
|
|
57
|
+
*/
|
|
58
|
+
export const feedbackGitignoreEntry = Object.freeze({
|
|
59
|
+
path: '.rcf/feedback/',
|
|
60
|
+
owner: 'rcf feedback: local feedback log and outbox (never committed)',
|
|
61
|
+
since: '0.28.0',
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* @param {string} projectRoot
|
|
66
|
+
* @returns {string}
|
|
67
|
+
*/
|
|
68
|
+
export function feedbackDir(projectRoot) {
|
|
69
|
+
return join(projectRoot, FEEDBACK_DIR);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* @param {string} projectRoot
|
|
74
|
+
* @returns {string}
|
|
75
|
+
*/
|
|
76
|
+
export function entriesPath(projectRoot) {
|
|
77
|
+
return join(projectRoot, FEEDBACK_DIR, 'entries.jsonl');
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* @param {string} projectRoot
|
|
82
|
+
* @returns {string}
|
|
83
|
+
*/
|
|
84
|
+
export function statePath(projectRoot) {
|
|
85
|
+
return join(projectRoot, FEEDBACK_DIR, 'state.json');
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* @param {string} projectRoot
|
|
90
|
+
* @returns {string}
|
|
91
|
+
*/
|
|
92
|
+
export function outboxDir(projectRoot) {
|
|
93
|
+
return join(projectRoot, FEEDBACK_DIR, 'outbox');
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* @typedef {object} FeedbackEntry
|
|
98
|
+
* @property {string} id fb-<yyyymmdd>-<4-hex>
|
|
99
|
+
* @property {string} recordedAt ISO timestamp
|
|
100
|
+
* @property {string} sessionId session id at capture time
|
|
101
|
+
* @property {'blueprint' | 'core'} kind
|
|
102
|
+
* @property {object} target see design §4.1
|
|
103
|
+
* @property {string | null} anchor AC/REQ/TAC/ADR id, or null
|
|
104
|
+
* @property {string} symptomClass closed enum (design §6)
|
|
105
|
+
* @property {'blocker' | 'major' | 'minor'} severity
|
|
106
|
+
* @property {string} title <= 120 chars
|
|
107
|
+
* @property {string} body <= 8 KB
|
|
108
|
+
* @property {Array<{ kind: string, value: string }>} evidence
|
|
109
|
+
* @property {object} environment harness / rcfLiteVersion / nodeVersion / platform
|
|
110
|
+
* @property {boolean} askNow
|
|
111
|
+
* @property {'pending' | 'submitted' | 'bundled' | 'discarded' | 'deferredUntilSession'} status
|
|
112
|
+
* @property {object} destination
|
|
113
|
+
*/
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* @typedef {object} StateTransition
|
|
117
|
+
* @property {string} id
|
|
118
|
+
* @property {string} at ISO timestamp
|
|
119
|
+
* @property {'pending' | 'submitted' | 'bundled' | 'deferredUntilSession' | 'discarded'} status
|
|
120
|
+
* @property {string} [issueUrl]
|
|
121
|
+
* @property {string} [outboxPath]
|
|
122
|
+
* @property {'new' | 'comment' | 'unchecked'} [dedupe]
|
|
123
|
+
* @property {string} [sessionId]
|
|
124
|
+
*/
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Read `entries.jsonl` and fold by id: for each id the LAST line wins.
|
|
128
|
+
* Returns an array of current-state entries in first-seen order, so
|
|
129
|
+
* `list` prints them by recording time by default.
|
|
130
|
+
*
|
|
131
|
+
* @param {string} projectRoot
|
|
132
|
+
* @returns {Promise<FeedbackEntry[]>}
|
|
133
|
+
*/
|
|
134
|
+
export async function readEntries(projectRoot) {
|
|
135
|
+
let text;
|
|
136
|
+
try {
|
|
137
|
+
text = await readFile(entriesPath(projectRoot), 'utf8');
|
|
138
|
+
} catch (err) {
|
|
139
|
+
if (/** @type {NodeJS.ErrnoException} */ (err).code === 'ENOENT') return [];
|
|
140
|
+
throw err;
|
|
141
|
+
}
|
|
142
|
+
const byId = new Map();
|
|
143
|
+
const order = [];
|
|
144
|
+
for (const raw of text.split('\n')) {
|
|
145
|
+
const line = raw.trim();
|
|
146
|
+
if (line === '') continue;
|
|
147
|
+
let obj;
|
|
148
|
+
try {
|
|
149
|
+
obj = JSON.parse(line);
|
|
150
|
+
} catch {
|
|
151
|
+
// A malformed line is not the store's failure surface; the writer
|
|
152
|
+
// never appends malformed lines. If one appears, skip and let the
|
|
153
|
+
// audit tools surface it.
|
|
154
|
+
continue;
|
|
155
|
+
}
|
|
156
|
+
if (typeof obj?.id !== 'string') continue;
|
|
157
|
+
if (!byId.has(obj.id)) {
|
|
158
|
+
order.push(obj.id);
|
|
159
|
+
byId.set(obj.id, obj);
|
|
160
|
+
} else {
|
|
161
|
+
byId.set(obj.id, { ...byId.get(obj.id), ...obj });
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
return order.map((id) => byId.get(id));
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Append one entry to the JSONL log. Ensures the parent directory
|
|
169
|
+
* exists (mkdir recursive) so the first call on a fresh project does
|
|
170
|
+
* not require a separate init step.
|
|
171
|
+
*
|
|
172
|
+
* @param {string} projectRoot
|
|
173
|
+
* @param {FeedbackEntry} entry
|
|
174
|
+
* @returns {Promise<void>}
|
|
175
|
+
*/
|
|
176
|
+
export async function appendEntry(projectRoot, entry) {
|
|
177
|
+
await mkdir(feedbackDir(projectRoot), { recursive: true });
|
|
178
|
+
const line = `${JSON.stringify(entry)}\n`;
|
|
179
|
+
await appendFile(entriesPath(projectRoot), line, 'utf8');
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Read the raw JSONL log and return the FIRST `discarded` transition
|
|
184
|
+
* timestamp per id. Used by the retention sweep so the 30-day clock
|
|
185
|
+
* runs from when the operator discarded the entry, not from when it
|
|
186
|
+
* was first recorded (F-slice-1-09 fix: an entry discarded today that
|
|
187
|
+
* was recorded 60 days ago must not prune on the next add).
|
|
188
|
+
*
|
|
189
|
+
* @param {string} projectRoot
|
|
190
|
+
* @returns {Promise<Map<string, string>>}
|
|
191
|
+
*/
|
|
192
|
+
export async function readDiscardTimestamps(projectRoot) {
|
|
193
|
+
const out = new Map();
|
|
194
|
+
let text;
|
|
195
|
+
try {
|
|
196
|
+
text = await readFile(entriesPath(projectRoot), 'utf8');
|
|
197
|
+
} catch (err) {
|
|
198
|
+
if (/** @type {NodeJS.ErrnoException} */ (err).code === 'ENOENT') return out;
|
|
199
|
+
throw err;
|
|
200
|
+
}
|
|
201
|
+
for (const raw of text.split('\n')) {
|
|
202
|
+
const line = raw.trim();
|
|
203
|
+
if (line === '') continue;
|
|
204
|
+
let obj;
|
|
205
|
+
try { obj = JSON.parse(line); } catch { continue; }
|
|
206
|
+
if (typeof obj?.id !== 'string') continue;
|
|
207
|
+
if (obj.status !== 'discarded') continue;
|
|
208
|
+
if (out.has(obj.id)) continue;
|
|
209
|
+
// A real state transition carries `at`; a seeded initial entry
|
|
210
|
+
// written with status:'discarded' from the start has only
|
|
211
|
+
// `recordedAt`. Both are legitimate first-discarded timestamps.
|
|
212
|
+
const ts = typeof obj.at === 'string'
|
|
213
|
+
? obj.at
|
|
214
|
+
: (typeof obj.recordedAt === 'string' ? obj.recordedAt : null);
|
|
215
|
+
if (ts) out.set(obj.id, ts);
|
|
216
|
+
}
|
|
217
|
+
return out;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* Append one state-transition line for an existing id. Callers pass a
|
|
222
|
+
* SHAPE that the reader's fold-by-id merges over the base entry; state
|
|
223
|
+
* transitions are additive, never destructive rewrites.
|
|
224
|
+
*
|
|
225
|
+
* @param {string} projectRoot
|
|
226
|
+
* @param {StateTransition} transition
|
|
227
|
+
* @returns {Promise<void>}
|
|
228
|
+
*/
|
|
229
|
+
export async function appendState(projectRoot, transition) {
|
|
230
|
+
await mkdir(feedbackDir(projectRoot), { recursive: true });
|
|
231
|
+
const line = `${JSON.stringify(transition)}\n`;
|
|
232
|
+
await appendFile(entriesPath(projectRoot), line, 'utf8');
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* Read the per-session ask ledger (`state.json`). Missing file returns
|
|
237
|
+
* the empty ledger. The shape is `{ asked: Array<{ sessionId, askedAt }>, queueStateAt: string | null }`;
|
|
238
|
+
* slice 5 fills it, slice 1 keeps the reader here so the whole store's
|
|
239
|
+
* shape lives in one file.
|
|
240
|
+
*
|
|
241
|
+
* @param {string} projectRoot
|
|
242
|
+
* @returns {Promise<{ asked: Array<{ sessionId: string, askedAt: string }>, queueStateAt: string | null }>}
|
|
243
|
+
*/
|
|
244
|
+
export async function readAskLedger(projectRoot) {
|
|
245
|
+
try {
|
|
246
|
+
const text = await readFile(statePath(projectRoot), 'utf8');
|
|
247
|
+
const parsed = JSON.parse(text);
|
|
248
|
+
return {
|
|
249
|
+
asked: Array.isArray(parsed?.asked) ? parsed.asked : [],
|
|
250
|
+
queueStateAt: typeof parsed?.queueStateAt === 'string' ? parsed.queueStateAt : null,
|
|
251
|
+
};
|
|
252
|
+
} catch (err) {
|
|
253
|
+
if (/** @type {NodeJS.ErrnoException} */ (err).code === 'ENOENT') {
|
|
254
|
+
return { asked: [], queueStateAt: null };
|
|
255
|
+
}
|
|
256
|
+
throw err;
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
/**
|
|
261
|
+
* Overwrite the ask ledger. Only slice 5 needs to write this; slice 1
|
|
262
|
+
* exports the writer so tests can seed a ledger without a private
|
|
263
|
+
* import path.
|
|
264
|
+
*
|
|
265
|
+
* @param {string} projectRoot
|
|
266
|
+
* @param {{ asked: Array<{ sessionId: string, askedAt: string }>, queueStateAt: string | null }} ledger
|
|
267
|
+
* @returns {Promise<void>}
|
|
268
|
+
*/
|
|
269
|
+
export async function writeAskLedger(projectRoot, ledger) {
|
|
270
|
+
await mkdir(feedbackDir(projectRoot), { recursive: true });
|
|
271
|
+
await writeFile(statePath(projectRoot), `${JSON.stringify(ledger, null, 2)}\n`, 'utf8');
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
/**
|
|
275
|
+
* Pre-write gitignore check. Returns `{ ok: true }` when git itself
|
|
276
|
+
* would ignore the feedback store path we are about to write; returns
|
|
277
|
+
* `{ ok: false, reason }` otherwise. Callers with `--force` bypass the
|
|
278
|
+
* check.
|
|
279
|
+
*
|
|
280
|
+
* F-slice-1-01 regression fix: the previous implementation walked
|
|
281
|
+
* `.gitignore` as a literal state machine and only recognised a small
|
|
282
|
+
* covers-set (`.rcf/feedback/`, `.rcf/`, ...) plus a hand-coded
|
|
283
|
+
* negation shortlist. That both missed valid wildcard shapes (`.rcf/*`
|
|
284
|
+
* covers the dir, but was rejected) and mis-judged the ignored-parent
|
|
285
|
+
* case (`.rcf/feedback/` + `!.rcf/feedback/*`: git cannot re-include a
|
|
286
|
+
* file whose parent is ignored, so the store is still safe, but the
|
|
287
|
+
* literal walker set `ignored=false` and refused). Delegating to
|
|
288
|
+
* `git check-ignore` means we judge the path the way git will judge it
|
|
289
|
+
* on the next `git add .`, which is the guarantee we actually need.
|
|
290
|
+
*
|
|
291
|
+
* When git is not installed or the project is not a git repo, we fall
|
|
292
|
+
* back to a conservative textual read of `.gitignore`: any line that
|
|
293
|
+
* folds one of `.rcf/feedback/`, `.rcf/feedback`, `.rcf/`, `.rcf`,
|
|
294
|
+
* `.rcf/*`, `.rcf/**`, or `.rcf/feedback/*` into the ignore set is
|
|
295
|
+
* enough. The fallback is deliberately generous because a machine
|
|
296
|
+
* without git cannot mis-publish through `git add`.
|
|
297
|
+
*
|
|
298
|
+
* @param {string} projectRoot
|
|
299
|
+
* @returns {Promise<{ ok: true } | { ok: false, reason: string }>}
|
|
300
|
+
*/
|
|
301
|
+
export async function ensureGitignore(projectRoot) {
|
|
302
|
+
const probeRelative = join('.rcf', 'feedback', 'entries.jsonl');
|
|
303
|
+
const git = await runGitCheckIgnore(projectRoot, probeRelative);
|
|
304
|
+
if (git.ok !== null) {
|
|
305
|
+
if (git.ok) return { ok: true };
|
|
306
|
+
return { ok: false, reason: `git check-ignore says ${probeRelative} would be committed by git add` };
|
|
307
|
+
}
|
|
308
|
+
// Fallback (no git, or not a repo): permissive textual scan.
|
|
309
|
+
let text;
|
|
310
|
+
try {
|
|
311
|
+
text = await readFile(join(projectRoot, '.gitignore'), 'utf8');
|
|
312
|
+
} catch (err) {
|
|
313
|
+
if (/** @type {NodeJS.ErrnoException} */ (err).code === 'ENOENT') {
|
|
314
|
+
return { ok: false, reason: 'no .gitignore in project root' };
|
|
315
|
+
}
|
|
316
|
+
throw err;
|
|
317
|
+
}
|
|
318
|
+
// Walk .gitignore in order; toggle the ignored state whenever a
|
|
319
|
+
// line (positive or `!` negation) covers the feedback store. The
|
|
320
|
+
// last-word wins, which mirrors git's own last-match-wins semantics
|
|
321
|
+
// for a file whose parent chain is not itself excluded through a
|
|
322
|
+
// pattern the negation cannot re-include (which we cannot judge
|
|
323
|
+
// without git; the check-ignore path above does).
|
|
324
|
+
//
|
|
325
|
+
// Round 3 (fallback-negation regression): a `!` line whose pattern
|
|
326
|
+
// is NOT in the coversFeedback vocabulary might still re-include
|
|
327
|
+
// entries.jsonl under real git (e.g. `.rcf/feedback/*` paired with
|
|
328
|
+
// `!*.jsonl`). The fallback cannot judge safely, so remember the
|
|
329
|
+
// unrecognised negation and refuse ok:true when one appears
|
|
330
|
+
// alongside a positive ignore. The known-vocabulary case still
|
|
331
|
+
// toggles as before, preserving the last-word-wins semantics that
|
|
332
|
+
// the round-2 tests pinned.
|
|
333
|
+
let ignored = false;
|
|
334
|
+
let unknownNegation = null;
|
|
335
|
+
for (const rawLine of text.split('\n')) {
|
|
336
|
+
const line = rawLine.trim();
|
|
337
|
+
if (line === '' || line.startsWith('#')) continue;
|
|
338
|
+
const isNeg = line.startsWith('!');
|
|
339
|
+
const pattern = (isNeg ? line.slice(1) : line).replace(/\/+$/, '').replace(/^\.\//, '');
|
|
340
|
+
const covers = coversFeedback(pattern);
|
|
341
|
+
if (covers) {
|
|
342
|
+
ignored = !isNeg;
|
|
343
|
+
} else if (isNeg) {
|
|
344
|
+
unknownNegation = line;
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
if (ignored && unknownNegation) {
|
|
348
|
+
return {
|
|
349
|
+
ok: false,
|
|
350
|
+
reason: `.gitignore contains a negation the fallback cannot evaluate ('${unknownNegation}') and git is not available for check-ignore; install git (or 'git init' the project) so the check can decide safely`,
|
|
351
|
+
};
|
|
352
|
+
}
|
|
353
|
+
if (ignored) return { ok: true };
|
|
354
|
+
return { ok: false, reason: 'no .gitignore rule covers .rcf/feedback/' };
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
/**
|
|
358
|
+
* Does a gitignore pattern (leading `!` already stripped, trailing
|
|
359
|
+
* slash normalised) cover the feedback store directory or a file
|
|
360
|
+
* inside it? Recognises the literal directory / file paths plus the
|
|
361
|
+
* common wildcard shapes callers write (`.rcf/*`, `.rcf/**`,
|
|
362
|
+
* `.rcf/feedback/*`, `.rcf/feedback/**`).
|
|
363
|
+
*
|
|
364
|
+
* @param {string} pattern
|
|
365
|
+
* @returns {boolean}
|
|
366
|
+
*/
|
|
367
|
+
function coversFeedback(pattern) {
|
|
368
|
+
const set = new Set([
|
|
369
|
+
'.rcf',
|
|
370
|
+
'.rcf/feedback',
|
|
371
|
+
'.rcf/feedback/entries.jsonl',
|
|
372
|
+
'.rcf/*',
|
|
373
|
+
'.rcf/**',
|
|
374
|
+
'.rcf/feedback/*',
|
|
375
|
+
'.rcf/feedback/**',
|
|
376
|
+
]);
|
|
377
|
+
return set.has(pattern);
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
/**
|
|
381
|
+
* Run `git check-ignore -q <path>` in `projectRoot`. Returns `ok`
|
|
382
|
+
* true when git says the path would be ignored (exit 0), false when
|
|
383
|
+
* git says it would be committed (exit 1), and null when git could
|
|
384
|
+
* not answer (no git, not a repo, or any other error) so the caller
|
|
385
|
+
* knows to fall back.
|
|
386
|
+
*
|
|
387
|
+
* @param {string} projectRoot
|
|
388
|
+
* @param {string} relativePath
|
|
389
|
+
* @returns {Promise<{ ok: true | false | null, reason: string | null }>}
|
|
390
|
+
*/
|
|
391
|
+
async function runGitCheckIgnore(projectRoot, relativePath) {
|
|
392
|
+
return new Promise((resolvePromise) => {
|
|
393
|
+
let child;
|
|
394
|
+
try {
|
|
395
|
+
child = spawn('git', ['check-ignore', '-q', relativePath], {
|
|
396
|
+
cwd: projectRoot,
|
|
397
|
+
env: process.env,
|
|
398
|
+
stdio: ['ignore', 'ignore', 'ignore'],
|
|
399
|
+
});
|
|
400
|
+
} catch {
|
|
401
|
+
resolvePromise({ ok: null, reason: 'git not spawnable' });
|
|
402
|
+
return;
|
|
403
|
+
}
|
|
404
|
+
let done = false;
|
|
405
|
+
const finish = (payload) => {
|
|
406
|
+
if (done) return;
|
|
407
|
+
done = true;
|
|
408
|
+
resolvePromise(payload);
|
|
409
|
+
};
|
|
410
|
+
child.on('error', () => finish({ ok: null, reason: 'git spawn error' }));
|
|
411
|
+
child.on('close', (code) => {
|
|
412
|
+
if (code === 0) finish({ ok: true, reason: null });
|
|
413
|
+
else if (code === 1) finish({ ok: false, reason: null });
|
|
414
|
+
else finish({ ok: null, reason: `git check-ignore exit ${code}` });
|
|
415
|
+
});
|
|
416
|
+
});
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
/**
|
|
420
|
+
* Generate a fresh entry id: `fb-<yyyymmdd>-<12-hex>`. Ruling R2
|
|
421
|
+
* (Dave 2026-09-16): 12-hex tail with a uniqueness probe on append
|
|
422
|
+
* so a busy day's 100+ findings do not collide (a 16-bit tail had a
|
|
423
|
+
* ~7.6% collision at 100 finds/day, which converted a distinct
|
|
424
|
+
* finding into a state transition on the old one via the fold-by-id
|
|
425
|
+
* reader). Callers should use `mintUniqueEntryId` when they can
|
|
426
|
+
* afford one read of the entries log; `newEntryId` remains the raw
|
|
427
|
+
* generator for tests that inject an rng.
|
|
428
|
+
*
|
|
429
|
+
* @param {Date} [now]
|
|
430
|
+
* @param {() => number} [rng] - 0..1; injectable for tests
|
|
431
|
+
* @returns {string}
|
|
432
|
+
*/
|
|
433
|
+
export function newEntryId(now = new Date(), rng = Math.random) {
|
|
434
|
+
const yyyy = now.getUTCFullYear().toString().padStart(4, '0');
|
|
435
|
+
const mm = (now.getUTCMonth() + 1).toString().padStart(2, '0');
|
|
436
|
+
const dd = now.getUTCDate().toString().padStart(2, '0');
|
|
437
|
+
// 48 bits split into three 16-bit words so we never rely on 32-bit
|
|
438
|
+
// integer coercion and every call has full 48-bit entropy.
|
|
439
|
+
const words = [];
|
|
440
|
+
for (let i = 0; i < 3; i += 1) {
|
|
441
|
+
words.push(Math.floor(rng() * 0x10000).toString(16).padStart(4, '0'));
|
|
442
|
+
}
|
|
443
|
+
return `fb-${yyyy}${mm}${dd}-${words.join('')}`;
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
/**
|
|
447
|
+
* Mint an entry id and re-generate on collision. F-slice-1-03 /
|
|
448
|
+
* ruling R2: append is preceded by a uniqueness probe over the read
|
|
449
|
+
* entries so no two rows share an id. The retry budget is 32; if
|
|
450
|
+
* every generated id still collides (astronomically unlikely with
|
|
451
|
+
* 48 bits of entropy) the last generated id is returned so the caller
|
|
452
|
+
* can decide how to escalate.
|
|
453
|
+
*
|
|
454
|
+
* @param {string} projectRoot
|
|
455
|
+
* @param {Date} [now]
|
|
456
|
+
* @param {() => number} [rng]
|
|
457
|
+
* @returns {Promise<string>}
|
|
458
|
+
*/
|
|
459
|
+
export async function mintUniqueEntryId(projectRoot, now = new Date(), rng = Math.random) {
|
|
460
|
+
const existing = new Set((await readEntries(projectRoot)).map((e) => e.id));
|
|
461
|
+
for (let i = 0; i < 32; i += 1) {
|
|
462
|
+
const id = newEntryId(now, rng);
|
|
463
|
+
if (!existing.has(id)) return id;
|
|
464
|
+
}
|
|
465
|
+
// F-slice-1-03 (fix round 2): fail closed rather than return a
|
|
466
|
+
// colliding id the caller would blindly append. R2's contract says
|
|
467
|
+
// "no two rows share an id"; returning the last colliding id would
|
|
468
|
+
// violate the shape even if the collision is astronomically
|
|
469
|
+
// unlikely (48 bits of entropy). handleAdd catches this and refuses
|
|
470
|
+
// the write with a usage-shaped error so the operator sees it.
|
|
471
|
+
const err = new Error(
|
|
472
|
+
'entry-id retry exhausted: 32 mint attempts all collided with existing ids. '
|
|
473
|
+
+ 'This is astronomically unlikely with 48 bits of entropy - suspect a corrupted '
|
|
474
|
+
+ '.rcf/feedback/entries.jsonl or a broken rng seed.',
|
|
475
|
+
);
|
|
476
|
+
/** @type {any} */ (err).code = 'FEEDBACK_ID_EXHAUSTED';
|
|
477
|
+
throw err;
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
/**
|
|
481
|
+
* Read `rcf/feedback-settings.json` and fold onto the defaults. A
|
|
482
|
+
* missing file returns the defaults verbatim (design section 8: a
|
|
483
|
+
* project without the file is still an opted-in project); an
|
|
484
|
+
* unparseable file returns `{ settings: defaults, parseError }` so
|
|
485
|
+
* the caller can surface the fault without crashing the hook.
|
|
486
|
+
*
|
|
487
|
+
* @param {string} projectRoot
|
|
488
|
+
* @returns {Promise<{ settings: { settingsVersion: number, ask: boolean, quietMinutes: number, redaction: { allowHosts: string[] } }, parseError: string | null, present: boolean }>}
|
|
489
|
+
*/
|
|
490
|
+
export async function readFeedbackSettings(projectRoot) {
|
|
491
|
+
const path = join(projectRoot, FEEDBACK_SETTINGS_PATH);
|
|
492
|
+
let text;
|
|
493
|
+
try {
|
|
494
|
+
text = await readFile(path, 'utf8');
|
|
495
|
+
} catch (err) {
|
|
496
|
+
if (/** @type {NodeJS.ErrnoException} */ (err).code === 'ENOENT') {
|
|
497
|
+
return {
|
|
498
|
+
settings: { ...DEFAULT_FEEDBACK_SETTINGS, redaction: { allowHosts: [] } },
|
|
499
|
+
parseError: null,
|
|
500
|
+
present: false,
|
|
501
|
+
};
|
|
502
|
+
}
|
|
503
|
+
throw err;
|
|
504
|
+
}
|
|
505
|
+
let parsed;
|
|
506
|
+
try {
|
|
507
|
+
parsed = JSON.parse(text);
|
|
508
|
+
} catch (err) {
|
|
509
|
+
return {
|
|
510
|
+
settings: { ...DEFAULT_FEEDBACK_SETTINGS, redaction: { allowHosts: [] } },
|
|
511
|
+
parseError: err.message,
|
|
512
|
+
present: true,
|
|
513
|
+
};
|
|
514
|
+
}
|
|
515
|
+
if (parsed === null || typeof parsed !== 'object' || Array.isArray(parsed)) {
|
|
516
|
+
return {
|
|
517
|
+
settings: { ...DEFAULT_FEEDBACK_SETTINGS, redaction: { allowHosts: [] } },
|
|
518
|
+
parseError: 'not a JSON object',
|
|
519
|
+
present: true,
|
|
520
|
+
};
|
|
521
|
+
}
|
|
522
|
+
const ask = typeof parsed.ask === 'boolean' ? parsed.ask : DEFAULT_FEEDBACK_SETTINGS.ask;
|
|
523
|
+
const quietMinutes = Number.isFinite(parsed.quietMinutes) && parsed.quietMinutes >= 0
|
|
524
|
+
? parsed.quietMinutes
|
|
525
|
+
: DEFAULT_FEEDBACK_SETTINGS.quietMinutes;
|
|
526
|
+
const settingsVersion = Number.isFinite(parsed.settingsVersion)
|
|
527
|
+
? parsed.settingsVersion
|
|
528
|
+
: DEFAULT_FEEDBACK_SETTINGS.settingsVersion;
|
|
529
|
+
const allowHosts = Array.isArray(parsed?.redaction?.allowHosts)
|
|
530
|
+
? parsed.redaction.allowHosts.filter((v) => typeof v === 'string')
|
|
531
|
+
: [];
|
|
532
|
+
return {
|
|
533
|
+
settings: { settingsVersion, ask, quietMinutes, redaction: { allowHosts } },
|
|
534
|
+
parseError: null,
|
|
535
|
+
present: true,
|
|
536
|
+
};
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
/**
|
|
540
|
+
* Overwrite `rcf/feedback-settings.json`, merging over the current
|
|
541
|
+
* on-disk file (or the defaults, if absent). Callers pass the delta
|
|
542
|
+
* they want applied; other fields survive verbatim.
|
|
543
|
+
*
|
|
544
|
+
* @param {string} projectRoot
|
|
545
|
+
* @param {Partial<{ settingsVersion: number, ask: boolean, quietMinutes: number, redaction: { allowHosts: string[] } }>} delta
|
|
546
|
+
* @returns {Promise<{ path: string, action: 'created' | 'updated' | 'noop', settings: object }>}
|
|
547
|
+
*/
|
|
548
|
+
export async function writeFeedbackSettings(projectRoot, delta) {
|
|
549
|
+
const path = join(projectRoot, FEEDBACK_SETTINGS_PATH);
|
|
550
|
+
let existed = true;
|
|
551
|
+
let currentText;
|
|
552
|
+
try {
|
|
553
|
+
currentText = await readFile(path, 'utf8');
|
|
554
|
+
} catch (err) {
|
|
555
|
+
if (/** @type {NodeJS.ErrnoException} */ (err).code === 'ENOENT') {
|
|
556
|
+
existed = false;
|
|
557
|
+
currentText = null;
|
|
558
|
+
} else {
|
|
559
|
+
throw err;
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
let base = { ...DEFAULT_FEEDBACK_SETTINGS, redaction: { allowHosts: [] } };
|
|
563
|
+
if (existed) {
|
|
564
|
+
try {
|
|
565
|
+
const parsed = JSON.parse(currentText);
|
|
566
|
+
if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {
|
|
567
|
+
base = { ...base, ...parsed };
|
|
568
|
+
if (parsed.redaction && typeof parsed.redaction === 'object' && !Array.isArray(parsed.redaction)) {
|
|
569
|
+
base.redaction = { allowHosts: Array.isArray(parsed.redaction.allowHosts) ? [...parsed.redaction.allowHosts] : [] };
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
} catch { /* fall through with defaults */ }
|
|
573
|
+
}
|
|
574
|
+
const next = {
|
|
575
|
+
...base,
|
|
576
|
+
...delta,
|
|
577
|
+
redaction: delta?.redaction ? { ...base.redaction, ...delta.redaction } : base.redaction,
|
|
578
|
+
};
|
|
579
|
+
const serialized = `${JSON.stringify(next, null, 2)}\n`;
|
|
580
|
+
if (existed && serialized === currentText) {
|
|
581
|
+
return { path, action: 'noop', settings: next };
|
|
582
|
+
}
|
|
583
|
+
await mkdir(dirname(path), { recursive: true });
|
|
584
|
+
await writeFile(path, serialized, 'utf8');
|
|
585
|
+
return { path, action: existed ? 'updated' : 'created', settings: next };
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
/**
|
|
589
|
+
* Existence probe used by `rcf feedback status` to decide whether the
|
|
590
|
+
* store has ever been written to. Not a truth-source for entries; use
|
|
591
|
+
* `readEntries` for that.
|
|
592
|
+
*
|
|
593
|
+
* @param {string} projectRoot
|
|
594
|
+
* @returns {Promise<boolean>}
|
|
595
|
+
*/
|
|
596
|
+
export async function storeExists(projectRoot) {
|
|
597
|
+
try {
|
|
598
|
+
await stat(entriesPath(projectRoot));
|
|
599
|
+
return true;
|
|
600
|
+
} catch (err) {
|
|
601
|
+
if (/** @type {NodeJS.ErrnoException} */ (err).code === 'ENOENT') return false;
|
|
602
|
+
throw err;
|
|
603
|
+
}
|
|
604
|
+
}
|
package/src/finalise/index.js
CHANGED
|
@@ -25,6 +25,10 @@ export {
|
|
|
25
25
|
// rcf-eval-node spec 2026-09-04 sections 5.2 + 8: EVAL-MISSING and
|
|
26
26
|
// EVAL-BELOW-THRESHOLD refusal on `rcf finalise`.
|
|
27
27
|
findEvalRefusalAcs, reportHasEvalRefusal,
|
|
28
|
+
// Referee-guarantee train (REQ-165, docs claims C-28 / C-29 / C-36):
|
|
29
|
+
// finalise refuses on UI-BASELINE-UNMET and BROWSER-VERIFICATION-MISSING.
|
|
30
|
+
findUiBaselineUnmetAcs, reportHasUiBaselineUnmet,
|
|
31
|
+
findBrowserVerificationMissingAcs, reportHasBrowserVerificationMissing,
|
|
28
32
|
} from './ingest.js';
|
|
29
33
|
export {
|
|
30
34
|
composeShipWithoutVerifiedRecord,
|
package/src/finalise/ingest.js
CHANGED
|
@@ -185,3 +185,64 @@ export function findEvalRefusalAcs(report) {
|
|
|
185
185
|
export function reportHasEvalRefusal(report) {
|
|
186
186
|
return findEvalRefusalAcs(report).length > 0;
|
|
187
187
|
}
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* Referee-guarantee train (REQ-165 / US-16501, docs claims C-28 / C-36).
|
|
191
|
+
* Extract per-AC verdicts in {UI-BASELINE-UNMET} from a verify report.
|
|
192
|
+
* The verdict is emitted by `uiPerAcVerdict` when a UI-bearing FBS has
|
|
193
|
+
* a bound `browserVerification[]` record whose `verdict` came back
|
|
194
|
+
* `block`; a block-severity probe-pack failure aggregates into the same
|
|
195
|
+
* verdict (docs claim C-36). Earlier reports carry no perAcVerdicts
|
|
196
|
+
* field; this returns an empty array in that case.
|
|
197
|
+
*
|
|
198
|
+
* @param {object} report
|
|
199
|
+
* @returns {Array<{ acId: string, verdict: string, reason?: string }>}
|
|
200
|
+
*/
|
|
201
|
+
export function findUiBaselineUnmetAcs(report) {
|
|
202
|
+
const perAc = Array.isArray(report?.perAcVerdicts) ? report.perAcVerdicts : [];
|
|
203
|
+
return perAc
|
|
204
|
+
.filter((e) => e && e.verdict === 'UI-BASELINE-UNMET')
|
|
205
|
+
.map((e) => ({ acId: e.acId, verdict: e.verdict, reason: e.reason }));
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* True when a verify report carries at least one UI-BASELINE-UNMET verdict.
|
|
210
|
+
* Consumed by the finalise gate to refuse promotion to `verified` on a
|
|
211
|
+
* failed UI baseline check (referee-guarantee C-28 / C-36).
|
|
212
|
+
*
|
|
213
|
+
* @param {object} report
|
|
214
|
+
* @returns {boolean}
|
|
215
|
+
*/
|
|
216
|
+
export function reportHasUiBaselineUnmet(report) {
|
|
217
|
+
return findUiBaselineUnmetAcs(report).length > 0;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* Referee-guarantee train (REQ-165 / US-16501, docs claim C-29).
|
|
222
|
+
* Extract per-AC verdicts in {BROWSER-VERIFICATION-MISSING} from a
|
|
223
|
+
* verify report. Emitted by `uiPerAcVerdict` when a UI-bearing FBS has
|
|
224
|
+
* no `browserVerification[]` record on the manifest (verify has nothing
|
|
225
|
+
* to read for the baseline check).
|
|
226
|
+
*
|
|
227
|
+
* @param {object} report
|
|
228
|
+
* @returns {Array<{ acId: string, verdict: string, reason?: string }>}
|
|
229
|
+
*/
|
|
230
|
+
export function findBrowserVerificationMissingAcs(report) {
|
|
231
|
+
const perAc = Array.isArray(report?.perAcVerdicts) ? report.perAcVerdicts : [];
|
|
232
|
+
return perAc
|
|
233
|
+
.filter((e) => e && e.verdict === 'BROWSER-VERIFICATION-MISSING')
|
|
234
|
+
.map((e) => ({ acId: e.acId, verdict: e.verdict, reason: e.reason }));
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
/**
|
|
238
|
+
* True when a verify report carries at least one
|
|
239
|
+
* BROWSER-VERIFICATION-MISSING verdict. Consumed by the finalise gate
|
|
240
|
+
* to refuse promotion to `verified` on a UI-bearing FBS whose bound
|
|
241
|
+
* browser-verification record is absent (referee-guarantee C-29).
|
|
242
|
+
*
|
|
243
|
+
* @param {object} report
|
|
244
|
+
* @returns {boolean}
|
|
245
|
+
*/
|
|
246
|
+
export function reportHasBrowserVerificationMissing(report) {
|
|
247
|
+
return findBrowserVerificationMissingAcs(report).length > 0;
|
|
248
|
+
}
|