rcf-lite 0.26.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 +43 -0
- package/README.md +10 -0
- package/bin/rcf.js +2 -0
- package/blueprints/application-account-settings/CHANGELOG.md +64 -2
- package/blueprints/application-account-settings/README.md +10 -10
- package/blueprints/application-account-settings/blueprint.json +26 -4
- package/blueprints/application-account-settings/contributions/adrs/adr-2601-application-account-settings-capability-vocabulary.json +1 -1
- package/blueprints/application-account-settings/contributions/adrs/adr-2602-application-account-settings-security-surface-shape.json +1 -1
- package/blueprints/application-account-settings/contributions/adrs/adr-2604-application-account-settings-reauth-window.json +5 -5
- 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-account-settings/contributions/requirements/application-account-settings-req-001.json +6 -2
- package/blueprints/application-account-settings/contributions/requirements/application-account-settings-req-002.json +4 -0
- package/blueprints/application-account-settings/contributions/requirements/application-account-settings-req-003.json +7 -3
- package/blueprints/application-account-settings/contributions/requirements/application-account-settings-req-004.json +4 -0
- package/blueprints/application-account-settings/contributions/requirements/application-account-settings-req-005.json +4 -0
- package/blueprints/application-account-settings/contributions/requirements/application-account-settings-req-006.json +6 -2
- package/blueprints/application-account-settings/contributions/requirements/application-account-settings-req-007.json +22 -0
- package/blueprints/application-account-settings/contributions/requirements/application-account-settings-req-009.json +21 -0
- package/blueprints/application-account-settings/contributions/tacs/tac-2601-application-account-settings-shell.json +8 -4
- package/blueprints/application-account-settings/contributions/tacs/tac-2602-application-account-settings-capability-discovery.json +3 -3
- package/blueprints/application-account-settings/contributions/tacs/tac-2604-application-account-settings-session-store.json +13 -7
- package/blueprints/application-account-settings/contributions/user-stories/application-account-settings-us-25101.json +19 -3
- package/blueprints/application-account-settings/contributions/user-stories/application-account-settings-us-25102.json +27 -2
- package/blueprints/application-account-settings/contributions/user-stories/application-account-settings-us-25103.json +13 -2
- package/blueprints/application-account-settings/contributions/user-stories/application-account-settings-us-25104.json +23 -2
- package/blueprints/application-account-settings/contributions/user-stories/application-account-settings-us-25105.json +51 -3
- package/blueprints/application-account-settings/contributions/user-stories/application-account-settings-us-25106.json +25 -6
- package/blueprints/application-account-settings/contributions/user-stories/application-account-settings-us-25107.json +13 -2
- package/blueprints/application-account-settings/contributions/user-stories/application-account-settings-us-25108.json +27 -2
- package/blueprints/application-account-settings/contributions/user-stories/application-account-settings-us-25109.json +4 -2
- package/blueprints/application-account-settings/contributions/user-stories/application-account-settings-us-25110.json +13 -2
- package/blueprints/application-account-settings/contributions/user-stories/application-account-settings-us-25111.json +71 -0
- package/blueprints/application-account-settings/contributions/user-stories/application-account-settings-us-25112.json +77 -0
- package/blueprints/application-account-settings/docs/topics.md +4 -4
- package/blueprints/application-account-settings/guide/application-account-settings.md +1 -1
- package/blueprints/application-account-settings/probe-packs/application-account-settings.pack.mjs +2 -2
- package/blueprints/application-admin-console/CHANGELOG.md +69 -7
- package/blueprints/application-admin-console/README.md +4 -4
- package/blueprints/application-admin-console/blueprint.json +34 -2
- package/blueprints/application-admin-console/contributions/adrs/adr-2201-application-admin-console-capability-vocabulary.json +2 -2
- package/blueprints/application-admin-console/contributions/adrs/adr-2203-application-admin-console-invite-transport.json +5 -5
- package/blueprints/application-admin-console/contributions/adrs/adr-2204-application-admin-console-audit-retention.json +7 -7
- package/blueprints/application-admin-console/contributions/adrs/adr-2214-application-admin-console-consume-zero-trust-gate.json +3 -3
- 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-admin-console/contributions/requirements/application-admin-console-req-001.json +4 -0
- package/blueprints/application-admin-console/contributions/requirements/application-admin-console-req-002.json +5 -1
- package/blueprints/application-admin-console/contributions/requirements/application-admin-console-req-003.json +4 -0
- package/blueprints/application-admin-console/contributions/requirements/application-admin-console-req-004.json +4 -0
- package/blueprints/application-admin-console/contributions/requirements/application-admin-console-req-005.json +6 -2
- package/blueprints/application-admin-console/contributions/requirements/application-admin-console-req-006.json +4 -0
- package/blueprints/application-admin-console/contributions/requirements/application-admin-console-req-007.json +22 -0
- package/blueprints/application-admin-console/contributions/requirements/application-admin-console-req-008.json +22 -0
- package/blueprints/application-admin-console/contributions/requirements/application-admin-console-req-009.json +21 -0
- package/blueprints/application-admin-console/contributions/requirements/application-admin-console-req-014.json +6 -2
- package/blueprints/application-admin-console/contributions/tacs/tac-2201-application-admin-console-shell.json +9 -7
- package/blueprints/application-admin-console/contributions/tacs/tac-2202-application-admin-console-capability-discovery.json +6 -6
- package/blueprints/application-admin-console/contributions/tacs/tac-2204-application-admin-console-audit-view.json +1 -1
- package/blueprints/application-admin-console/contributions/tacs/tac-2214-application-admin-console-access-gated-signin-surface.json +5 -5
- package/blueprints/application-admin-console/contributions/user-stories/application-admin-console-us-21101.json +4 -2
- package/blueprints/application-admin-console/contributions/user-stories/application-admin-console-us-21102.json +4 -2
- package/blueprints/application-admin-console/contributions/user-stories/application-admin-console-us-21103.json +10 -4
- package/blueprints/application-admin-console/contributions/user-stories/application-admin-console-us-21104.json +13 -2
- package/blueprints/application-admin-console/contributions/user-stories/application-admin-console-us-21105.json +15 -3
- package/blueprints/application-admin-console/contributions/user-stories/application-admin-console-us-21106.json +35 -2
- package/blueprints/application-admin-console/contributions/user-stories/application-admin-console-us-21107.json +22 -3
- package/blueprints/application-admin-console/contributions/user-stories/application-admin-console-us-21108.json +4 -2
- package/blueprints/application-admin-console/contributions/user-stories/application-admin-console-us-21109.json +4 -2
- package/blueprints/application-admin-console/contributions/user-stories/application-admin-console-us-21110.json +68 -0
- package/blueprints/application-admin-console/contributions/user-stories/application-admin-console-us-21111.json +76 -0
- package/blueprints/application-admin-console/contributions/user-stories/application-admin-console-us-21112.json +77 -0
- package/blueprints/application-admin-console/contributions/user-stories/application-admin-console-us-21815.json +21 -2
- package/blueprints/application-admin-console/contributions/user-stories/application-admin-console-us-21816.json +21 -2
- package/blueprints/application-admin-console/guide/application-admin-console.md +3 -3
- package/blueprints/application-admin-console/probe-packs/application-admin-console.pack.mjs +2 -2
- package/blueprints/application-api-rest/CHANGELOG.md +34 -0
- package/blueprints/application-api-rest/README.md +3 -3
- package/blueprints/application-api-rest/assets/samples/request-response-pairs.md +2 -0
- package/blueprints/application-api-rest/blueprint.json +3 -2
- package/blueprints/application-api-rest/contributions/adrs/adr-301-application-api-rest-error-envelope.json +1 -1
- package/blueprints/application-api-rest/contributions/adrs/adr-302-application-api-rest-auth-model.json +2 -2
- package/blueprints/application-api-rest/contributions/adrs/adr-303-application-api-rest-api-versioning.json +1 -1
- package/blueprints/application-api-rest/contributions/adrs/adr-304-application-api-rest-logging.json +1 -1
- package/blueprints/application-api-rest/contributions/adrs/adr-305-application-api-rest-pagination.json +1 -1
- package/blueprints/application-api-rest/contributions/adrs/adr-306-application-api-rest-idempotency.json +3 -3
- package/blueprints/application-api-rest/contributions/adrs/adr-307-application-api-rest-openapi-generation.json +1 -1
- package/blueprints/application-api-rest/contributions/adrs/adr-308-application-api-rest-rate-limiting.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/contributions/requirements/application-api-rest-req-001.json +6 -2
- package/blueprints/application-api-rest/contributions/requirements/application-api-rest-req-002.json +7 -3
- package/blueprints/application-api-rest/contributions/requirements/application-api-rest-req-003.json +6 -2
- package/blueprints/application-api-rest/contributions/requirements/application-api-rest-req-004.json +6 -2
- package/blueprints/application-api-rest/contributions/requirements/application-api-rest-req-005.json +6 -2
- package/blueprints/application-api-rest/contributions/requirements/application-api-rest-req-006.json +6 -2
- package/blueprints/application-api-rest/contributions/requirements/application-api-rest-req-007.json +6 -2
- package/blueprints/application-api-rest/contributions/requirements/application-api-rest-req-008.json +6 -2
- package/blueprints/application-api-rest/contributions/requirements/application-api-rest-req-009.json +6 -2
- package/blueprints/application-api-rest/contributions/requirements/application-api-rest-req-010.json +8 -4
- package/blueprints/application-api-rest/contributions/requirements/application-api-rest-req-011.json +6 -2
- package/blueprints/application-api-rest/contributions/requirements/application-api-rest-req-012.json +6 -2
- package/blueprints/application-api-rest/contributions/requirements/application-api-rest-req-013.json +7 -3
- package/blueprints/application-api-rest/contributions/requirements/application-api-rest-req-014.json +6 -2
- package/blueprints/application-api-rest/contributions/requirements/application-api-rest-req-015.json +6 -2
- package/blueprints/application-api-rest/contributions/requirements/application-api-rest-req-016.json +6 -2
- package/blueprints/application-api-rest/contributions/tacs/tac-301-application-api-rest-request-pipeline.json +1 -1
- package/blueprints/application-api-rest/contributions/tacs/tac-302-application-api-rest-auth-middleware.json +1 -1
- package/blueprints/application-api-rest/contributions/tacs/tac-303-application-api-rest-contract-surface.json +2 -2
- package/blueprints/application-api-rest/contributions/tacs/tac-304-application-api-rest-resource-layer.json +1 -1
- package/blueprints/application-api-rest/contributions/tacs/tac-305-application-api-rest-observability.json +1 -1
- package/blueprints/application-api-rest/contributions/tacs/tac-306-application-api-rest-operability.json +1 -1
- package/blueprints/application-api-rest/contributions/user-stories/application-api-rest-us-2101.json +13 -7
- package/blueprints/application-api-rest/contributions/user-stories/application-api-rest-us-2102.json +27 -13
- package/blueprints/application-api-rest/contributions/user-stories/application-api-rest-us-2103.json +18 -9
- package/blueprints/application-api-rest/contributions/user-stories/application-api-rest-us-2104.json +32 -10
- package/blueprints/application-api-rest/contributions/user-stories/application-api-rest-us-2105.json +19 -6
- package/blueprints/application-api-rest/contributions/user-stories/application-api-rest-us-2106.json +14 -8
- package/blueprints/application-api-rest/contributions/user-stories/application-api-rest-us-2107.json +20 -12
- package/blueprints/application-api-rest/contributions/user-stories/application-api-rest-us-2108.json +37 -15
- package/blueprints/application-api-rest/contributions/user-stories/application-api-rest-us-2109.json +15 -9
- package/blueprints/application-api-rest/contributions/user-stories/application-api-rest-us-2110.json +21 -11
- package/blueprints/application-api-rest/contributions/user-stories/application-api-rest-us-2111.json +42 -8
- package/blueprints/application-api-rest/contributions/user-stories/application-api-rest-us-2112.json +23 -13
- package/blueprints/application-api-rest/contributions/user-stories/application-api-rest-us-2113.json +17 -11
- package/blueprints/application-api-rest/contributions/user-stories/application-api-rest-us-2114.json +13 -8
- package/blueprints/application-api-rest/contributions/user-stories/application-api-rest-us-2115.json +13 -8
- package/blueprints/application-api-rest/contributions/user-stories/application-api-rest-us-2116.json +11 -6
- package/blueprints/application-api-rest/contributions/user-stories/application-api-rest-us-2117.json +19 -14
- package/blueprints/application-api-rest/contributions/user-stories/application-api-rest-us-2118.json +20 -10
- package/blueprints/application-api-rest/contributions/user-stories/application-api-rest-us-2119.json +20 -7
- package/blueprints/application-api-rest/contributions/user-stories/application-api-rest-us-2120.json +16 -10
- package/blueprints/application-api-rest/docs/topics.md +1 -1
- package/blueprints/application-charts/CHANGELOG.md +53 -6
- package/blueprints/application-charts/README.md +10 -10
- package/blueprints/application-charts/blueprint.json +115 -19
- package/blueprints/application-charts/contributions/adrs/adr-1901-application-charts-engine-choice.json +2 -2
- package/blueprints/application-charts/contributions/adrs/adr-1902-application-charts-accessible-palette.json +1 -1
- package/blueprints/application-charts/contributions/adrs/adr-1903-application-charts-motion.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 +11 -4
- package/blueprints/application-charts/contributions/requirements/application-charts-req-002.json +11 -4
- package/blueprints/application-charts/contributions/requirements/application-charts-req-003.json +10 -3
- package/blueprints/application-charts/contributions/requirements/application-charts-req-004.json +10 -3
- package/blueprints/application-charts/contributions/tacs/tac-1901-application-charts-render-shell.json +3 -2
- package/blueprints/application-charts/contributions/tacs/tac-1902-application-charts-keyboard-traversal.json +1 -1
- package/blueprints/application-charts/contributions/user-stories/application-charts-us-18101.json +52 -8
- package/blueprints/application-charts/contributions/user-stories/application-charts-us-18102.json +58 -6
- package/blueprints/application-charts/contributions/user-stories/application-charts-us-18103.json +54 -6
- package/blueprints/application-charts/contributions/user-stories/application-charts-us-18104.json +55 -6
- package/blueprints/application-charts/contributions/user-stories/application-charts-us-18105.json +64 -8
- package/blueprints/application-charts/contributions/user-stories/application-charts-us-18106.json +45 -7
- package/blueprints/application-charts/docs/topics.md +2 -2
- package/blueprints/application-charts/guide/application-charts.md +3 -3
- package/blueprints/application-charts/probe-packs/application-charts.pack.mjs +2 -2
- package/blueprints/application-dashboard/CHANGELOG.md +39 -8
- package/blueprints/application-dashboard/README.md +13 -13
- package/blueprints/application-dashboard/assets/guidance/dashboard-design.md +2 -2
- package/blueprints/application-dashboard/blueprint.json +149 -22
- package/blueprints/application-dashboard/contributions/adrs/adr-2001-application-dashboard-primary-kpi-enum.json +4 -4
- package/blueprints/application-dashboard/contributions/adrs/adr-2002-application-dashboard-timeframe-presets.json +2 -2
- package/blueprints/application-dashboard/contributions/adrs/adr-2003-application-dashboard-export-formats.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-001.json +10 -3
- package/blueprints/application-dashboard/contributions/requirements/application-dashboard-req-002.json +11 -4
- package/blueprints/application-dashboard/contributions/requirements/application-dashboard-req-003.json +11 -4
- package/blueprints/application-dashboard/contributions/requirements/application-dashboard-req-004.json +11 -4
- package/blueprints/application-dashboard/contributions/requirements/application-dashboard-req-005.json +11 -4
- package/blueprints/application-dashboard/contributions/tacs/tac-2001-application-dashboard-tile-grid.json +1 -1
- package/blueprints/application-dashboard/contributions/tacs/tac-2002-application-dashboard-filter-chrome.json +2 -2
- package/blueprints/application-dashboard/contributions/tacs/tac-2003-application-dashboard-export-handle.json +3 -3
- package/blueprints/application-dashboard/contributions/user-stories/application-dashboard-us-19101.json +55 -7
- package/blueprints/application-dashboard/contributions/user-stories/application-dashboard-us-19102.json +56 -8
- package/blueprints/application-dashboard/contributions/user-stories/application-dashboard-us-19103.json +59 -7
- package/blueprints/application-dashboard/contributions/user-stories/application-dashboard-us-19104.json +55 -7
- package/blueprints/application-dashboard/contributions/user-stories/application-dashboard-us-19105.json +55 -7
- package/blueprints/application-dashboard/contributions/user-stories/application-dashboard-us-19106.json +60 -8
- package/blueprints/application-dashboard/contributions/user-stories/application-dashboard-us-19107.json +57 -9
- package/blueprints/application-dashboard/docs/topics.md +3 -3
- package/blueprints/application-dashboard/guide/application-dashboard.md +5 -5
- package/blueprints/application-dashboard/probe-packs/application-dashboard.pack.mjs +4 -4
- package/blueprints/application-datatable/CHANGELOG.md +36 -5
- package/blueprints/application-datatable/README.md +4 -4
- package/blueprints/application-datatable/blueprint.json +169 -26
- package/blueprints/application-datatable/contributions/adrs/adr-1801-application-datatable-pattern-choice.json +1 -1
- package/blueprints/application-datatable/contributions/adrs/adr-1802-application-datatable-url-state.json +1 -1
- package/blueprints/application-datatable/contributions/adrs/adr-1803-application-datatable-page-size.json +1 -1
- package/blueprints/application-datatable/contributions/adrs/adr-1804-application-datatable-selection-persistence.json +1 -1
- 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-001.json +11 -4
- package/blueprints/application-datatable/contributions/requirements/application-datatable-req-002.json +11 -4
- package/blueprints/application-datatable/contributions/requirements/application-datatable-req-003.json +10 -3
- package/blueprints/application-datatable/contributions/requirements/application-datatable-req-004.json +11 -4
- package/blueprints/application-datatable/contributions/requirements/application-datatable-req-005.json +10 -3
- package/blueprints/application-datatable/contributions/requirements/application-datatable-req-006.json +11 -4
- package/blueprints/application-datatable/contributions/tacs/tac-1801-application-datatable-shell.json +1 -1
- package/blueprints/application-datatable/contributions/tacs/tac-1802-application-datatable-query-adapter.json +1 -1
- package/blueprints/application-datatable/contributions/tacs/tac-1803-application-datatable-selection-model.json +2 -2
- package/blueprints/application-datatable/contributions/user-stories/application-datatable-us-17101.json +29 -7
- package/blueprints/application-datatable/contributions/user-stories/application-datatable-us-17102.json +29 -7
- package/blueprints/application-datatable/contributions/user-stories/application-datatable-us-17103.json +28 -6
- package/blueprints/application-datatable/contributions/user-stories/application-datatable-us-17104.json +65 -7
- package/blueprints/application-datatable/contributions/user-stories/application-datatable-us-17105.json +32 -7
- package/blueprints/application-datatable/contributions/user-stories/application-datatable-us-17106.json +60 -7
- package/blueprints/application-datatable/contributions/user-stories/application-datatable-us-17107.json +72 -7
- package/blueprints/application-datatable/contributions/user-stories/application-datatable-us-17108.json +59 -9
- package/blueprints/application-datatable/contributions/user-stories/application-datatable-us-17109.json +58 -9
- package/blueprints/application-datatable/docs/topics.md +1 -1
- package/blueprints/application-datatable/guide/application-datatable.md +1 -1
- package/blueprints/application-empty-error-states/CHANGELOG.md +64 -4
- package/blueprints/application-empty-error-states/README.md +3 -3
- package/blueprints/application-empty-error-states/blueprint.json +38 -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-empty-error-states/contributions/requirements/application-empty-error-states-req-001.json +4 -0
- package/blueprints/application-empty-error-states/contributions/requirements/application-empty-error-states-req-002.json +7 -3
- package/blueprints/application-empty-error-states/contributions/requirements/application-empty-error-states-req-003.json +4 -0
- package/blueprints/application-empty-error-states/contributions/requirements/application-empty-error-states-req-004.json +6 -2
- package/blueprints/application-empty-error-states/contributions/requirements/application-empty-error-states-req-005.json +7 -3
- package/blueprints/application-empty-error-states/contributions/requirements/application-empty-error-states-req-006.json +21 -0
- package/blueprints/application-empty-error-states/contributions/requirements/application-empty-error-states-req-007.json +21 -0
- package/blueprints/application-empty-error-states/contributions/tacs/tac-2301-application-empty-error-states-state-machine.json +7 -4
- package/blueprints/application-empty-error-states/contributions/tacs/tac-2303-application-empty-error-states-offline-buffer.json +3 -2
- package/blueprints/application-empty-error-states/contributions/user-stories/application-empty-error-states-us-22101.json +17 -2
- package/blueprints/application-empty-error-states/contributions/user-stories/application-empty-error-states-us-22102.json +31 -2
- package/blueprints/application-empty-error-states/contributions/user-stories/application-empty-error-states-us-22103.json +27 -2
- package/blueprints/application-empty-error-states/contributions/user-stories/application-empty-error-states-us-22104.json +13 -2
- package/blueprints/application-empty-error-states/contributions/user-stories/application-empty-error-states-us-22105.json +33 -2
- package/blueprints/application-empty-error-states/contributions/user-stories/application-empty-error-states-us-22106.json +13 -2
- package/blueprints/application-empty-error-states/contributions/user-stories/application-empty-error-states-us-22107.json +23 -2
- package/blueprints/application-empty-error-states/contributions/user-stories/application-empty-error-states-us-22108.json +27 -2
- package/blueprints/application-empty-error-states/probe-packs/application-empty-error-states.pack.mjs +93 -9
- package/blueprints/application-error-handling/CHANGELOG.md +56 -0
- package/blueprints/application-error-handling/blueprint.json +106 -20
- package/blueprints/application-error-handling/contributions/adrs/adr-1701-application-error-handling-record-shape.json +1 -1
- package/blueprints/application-error-handling/contributions/adrs/adr-1702-application-error-handling-classification-vocabulary.json +1 -1
- package/blueprints/application-error-handling/contributions/adrs/adr-1703-application-error-handling-transport-mapping.json +1 -1
- 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-error-handling/contributions/requirements/application-error-handling-req-001.json +10 -3
- package/blueprints/application-error-handling/contributions/requirements/application-error-handling-req-002.json +10 -3
- package/blueprints/application-error-handling/contributions/requirements/application-error-handling-req-003.json +10 -3
- package/blueprints/application-error-handling/contributions/requirements/application-error-handling-req-004.json +10 -3
- package/blueprints/application-error-handling/contributions/tacs/tac-1701-application-error-handling-boundary.json +1 -1
- package/blueprints/application-error-handling/contributions/tacs/tac-1702-application-error-handling-record-factory.json +1 -1
- package/blueprints/application-error-handling/contributions/user-stories/application-error-handling-us-16101.json +63 -4
- package/blueprints/application-error-handling/contributions/user-stories/application-error-handling-us-16102.json +49 -4
- package/blueprints/application-error-handling/contributions/user-stories/application-error-handling-us-16103.json +51 -5
- package/blueprints/application-error-handling/contributions/user-stories/application-error-handling-us-16104.json +49 -4
- package/blueprints/application-error-handling/contributions/user-stories/application-error-handling-us-16105.json +49 -4
- package/blueprints/application-error-handling/contributions/user-stories/application-error-handling-us-16106.json +49 -4
- package/blueprints/application-error-handling/contributions/user-stories/application-error-handling-us-16107.json +53 -4
- package/blueprints/application-file-upload/CHANGELOG.md +60 -5
- package/blueprints/application-file-upload/README.md +1 -1
- package/blueprints/application-file-upload/blueprint.json +58 -2
- package/blueprints/application-file-upload/contributions/adrs/adr-2402-application-file-upload-accepted-set.json +3 -3
- 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 +5 -1
- package/blueprints/application-file-upload/contributions/requirements/application-file-upload-req-002.json +8 -4
- package/blueprints/application-file-upload/contributions/requirements/application-file-upload-req-003.json +7 -3
- package/blueprints/application-file-upload/contributions/requirements/application-file-upload-req-004.json +7 -3
- package/blueprints/application-file-upload/contributions/requirements/application-file-upload-req-005.json +5 -1
- package/blueprints/application-file-upload/contributions/requirements/application-file-upload-req-006.json +21 -0
- package/blueprints/application-file-upload/contributions/requirements/application-file-upload-req-007.json +21 -0
- package/blueprints/application-file-upload/contributions/tacs/tac-2401-application-file-upload-input.json +4 -2
- package/blueprints/application-file-upload/contributions/tacs/tac-2402-application-file-upload-transport.json +7 -2
- package/blueprints/application-file-upload/contributions/tacs/tac-2403-application-file-upload-progress-announcer.json +16 -6
- package/blueprints/application-file-upload/contributions/user-stories/application-file-upload-us-23101.json +23 -2
- package/blueprints/application-file-upload/contributions/user-stories/application-file-upload-us-23102.json +29 -4
- package/blueprints/application-file-upload/contributions/user-stories/application-file-upload-us-23103.json +13 -2
- package/blueprints/application-file-upload/contributions/user-stories/application-file-upload-us-23104.json +45 -2
- package/blueprints/application-file-upload/contributions/user-stories/application-file-upload-us-23105.json +37 -2
- package/blueprints/application-file-upload/contributions/user-stories/application-file-upload-us-23106.json +13 -2
- package/blueprints/application-file-upload/contributions/user-stories/application-file-upload-us-23107.json +17 -2
- package/blueprints/application-file-upload/probe-packs/application-file-upload.pack.mjs +14 -5
- package/blueprints/application-forms-wizard/CHANGELOG.md +50 -5
- package/blueprints/application-forms-wizard/README.md +3 -3
- package/blueprints/application-forms-wizard/blueprint.json +59 -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 +5 -1
- package/blueprints/application-forms-wizard/contributions/requirements/application-forms-wizard-req-002.json +7 -3
- package/blueprints/application-forms-wizard/contributions/requirements/application-forms-wizard-req-003.json +7 -3
- package/blueprints/application-forms-wizard/contributions/requirements/application-forms-wizard-req-004.json +7 -3
- package/blueprints/application-forms-wizard/contributions/requirements/application-forms-wizard-req-005.json +5 -1
- package/blueprints/application-forms-wizard/contributions/requirements/application-forms-wizard-req-006.json +21 -0
- package/blueprints/application-forms-wizard/contributions/tacs/tac-2501-application-forms-wizard-task-list.json +6 -4
- package/blueprints/application-forms-wizard/contributions/tacs/tac-2502-application-forms-wizard-error-summary.json +4 -3
- package/blueprints/application-forms-wizard/contributions/user-stories/application-forms-wizard-us-24101.json +35 -2
- package/blueprints/application-forms-wizard/contributions/user-stories/application-forms-wizard-us-24102.json +27 -2
- package/blueprints/application-forms-wizard/contributions/user-stories/application-forms-wizard-us-24103.json +21 -2
- package/blueprints/application-forms-wizard/contributions/user-stories/application-forms-wizard-us-24104.json +13 -2
- package/blueprints/application-forms-wizard/contributions/user-stories/application-forms-wizard-us-24105.json +33 -2
- package/blueprints/application-forms-wizard/contributions/user-stories/application-forms-wizard-us-24106.json +18 -3
- package/blueprints/application-forms-wizard/contributions/user-stories/application-forms-wizard-us-24107.json +23 -2
- package/blueprints/application-forms-wizard/contributions/user-stories/application-forms-wizard-us-24108.json +13 -2
- package/blueprints/application-forms-wizard/probe-packs/application-forms-wizard.pack.mjs +3 -3
- package/blueprints/application-notifications-in-app/CHANGELOG.md +70 -5
- package/blueprints/application-notifications-in-app/README.md +9 -9
- package/blueprints/application-notifications-in-app/blueprint.json +153 -23
- 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/requirements/application-notifications-in-app-req-001.json +11 -4
- package/blueprints/application-notifications-in-app/contributions/requirements/application-notifications-in-app-req-002.json +8 -1
- package/blueprints/application-notifications-in-app/contributions/requirements/application-notifications-in-app-req-003.json +10 -3
- package/blueprints/application-notifications-in-app/contributions/requirements/application-notifications-in-app-req-004.json +11 -4
- package/blueprints/application-notifications-in-app/contributions/requirements/application-notifications-in-app-req-005.json +12 -5
- package/blueprints/application-notifications-in-app/contributions/requirements/application-notifications-in-app-req-006.json +21 -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 +15 -9
- package/blueprints/application-notifications-in-app/contributions/tacs/tac-2103-application-notifications-in-app-preferences.json +2 -2
- package/blueprints/application-notifications-in-app/contributions/user-stories/application-notifications-in-app-us-20101.json +30 -6
- package/blueprints/application-notifications-in-app/contributions/user-stories/application-notifications-in-app-us-20102.json +44 -6
- package/blueprints/application-notifications-in-app/contributions/user-stories/application-notifications-in-app-us-20103.json +40 -6
- package/blueprints/application-notifications-in-app/contributions/user-stories/application-notifications-in-app-us-20104.json +31 -5
- package/blueprints/application-notifications-in-app/contributions/user-stories/application-notifications-in-app-us-20105.json +51 -9
- package/blueprints/application-notifications-in-app/contributions/user-stories/application-notifications-in-app-us-20106.json +19 -4
- package/blueprints/application-notifications-in-app/contributions/user-stories/application-notifications-in-app-us-20107.json +19 -4
- package/blueprints/application-notifications-in-app/contributions/user-stories/application-notifications-in-app-us-20108.json +19 -4
- package/blueprints/application-notifications-in-app/guide/application-notifications-in-app.md +4 -4
- package/blueprints/application-notifications-in-app/probe-packs/application-notifications-in-app.pack.mjs +4 -4
- package/blueprints/application-onboarding-tour/CHANGELOG.md +59 -2
- package/blueprints/application-onboarding-tour/README.md +3 -3
- package/blueprints/application-onboarding-tour/blueprint.json +24 -2
- package/blueprints/application-onboarding-tour/contributions/adrs/adr-2702-application-onboarding-tour-completion-store-shape.json +4 -4
- 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-onboarding-tour/contributions/requirements/application-onboarding-tour-req-001.json +6 -2
- package/blueprints/application-onboarding-tour/contributions/requirements/application-onboarding-tour-req-002.json +6 -2
- package/blueprints/application-onboarding-tour/contributions/requirements/application-onboarding-tour-req-003.json +4 -0
- package/blueprints/application-onboarding-tour/contributions/requirements/application-onboarding-tour-req-004.json +4 -0
- package/blueprints/application-onboarding-tour/contributions/requirements/application-onboarding-tour-req-005.json +22 -0
- package/blueprints/application-onboarding-tour/contributions/requirements/application-onboarding-tour-req-006.json +22 -0
- package/blueprints/application-onboarding-tour/contributions/tacs/tac-2702-application-onboarding-tour-checklist-slot.json +2 -1
- package/blueprints/application-onboarding-tour/contributions/tacs/tac-2703-application-onboarding-tour-completion-store.json +7 -7
- package/blueprints/application-onboarding-tour/contributions/user-stories/application-onboarding-tour-us-26101.json +67 -2
- package/blueprints/application-onboarding-tour/contributions/user-stories/application-onboarding-tour-us-26102.json +35 -2
- package/blueprints/application-onboarding-tour/contributions/user-stories/application-onboarding-tour-us-26103.json +13 -2
- package/blueprints/application-onboarding-tour/contributions/user-stories/application-onboarding-tour-us-26104.json +33 -2
- package/blueprints/application-onboarding-tour/contributions/user-stories/application-onboarding-tour-us-26105.json +13 -2
- package/blueprints/application-onboarding-tour/contributions/user-stories/application-onboarding-tour-us-26106.json +13 -2
- package/blueprints/application-onboarding-tour/contributions/user-stories/application-onboarding-tour-us-26107.json +17 -2
- package/blueprints/application-onboarding-tour/contributions/user-stories/application-onboarding-tour-us-26108.json +62 -0
- package/blueprints/application-onboarding-tour/contributions/user-stories/application-onboarding-tour-us-26109.json +72 -0
- package/blueprints/application-onboarding-tour/docs/topics.md +2 -2
- package/blueprints/application-onboarding-tour/guide/application-onboarding-tour.md +1 -1
- package/blueprints/application-onboarding-tour/probe-packs/application-onboarding-tour.pack.mjs +2 -2
- package/blueprints/application-spa/CHANGELOG.md +39 -0
- package/blueprints/application-spa/README.md +11 -12
- package/blueprints/application-spa/blueprint.json +3 -2
- package/blueprints/application-spa/contributions/adrs/adr-201-application-spa-routing.json +1 -1
- package/blueprints/application-spa/contributions/adrs/adr-202-application-spa-theming.json +2 -2
- package/blueprints/application-spa/contributions/adrs/adr-203-application-spa-client-state.json +1 -1
- package/blueprints/application-spa/contributions/adrs/adr-204-application-spa-error-envelope.json +1 -1
- package/blueprints/application-spa/contributions/adrs/adr-205-application-spa-auth-model.json +1 -1
- package/blueprints/application-spa/contributions/adrs/adr-206-application-spa-iconography.json +2 -2
- package/blueprints/application-spa/contributions/adrs/adr-207-application-spa-motion.json +1 -1
- package/blueprints/application-spa/contributions/adrs/adr-208-application-spa-i18n.json +1 -1
- package/blueprints/application-spa/contributions/adrs/adr-209-application-spa-telemetry-naming.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/requirements/application-spa-req-001.json +6 -2
- package/blueprints/application-spa/contributions/requirements/application-spa-req-002.json +6 -2
- package/blueprints/application-spa/contributions/requirements/application-spa-req-003.json +6 -2
- package/blueprints/application-spa/contributions/requirements/application-spa-req-004.json +6 -2
- package/blueprints/application-spa/contributions/requirements/application-spa-req-005.json +6 -2
- package/blueprints/application-spa/contributions/requirements/application-spa-req-006.json +6 -2
- package/blueprints/application-spa/contributions/requirements/application-spa-req-007.json +6 -2
- package/blueprints/application-spa/contributions/requirements/application-spa-req-008.json +6 -2
- package/blueprints/application-spa/contributions/requirements/application-spa-req-009.json +7 -3
- package/blueprints/application-spa/contributions/requirements/application-spa-req-010.json +6 -2
- package/blueprints/application-spa/contributions/requirements/application-spa-req-011.json +6 -2
- package/blueprints/application-spa/contributions/requirements/application-spa-req-012.json +6 -2
- package/blueprints/application-spa/contributions/requirements/application-spa-req-013.json +6 -2
- package/blueprints/application-spa/contributions/requirements/application-spa-req-014.json +6 -2
- package/blueprints/application-spa/contributions/requirements/application-spa-req-015.json +6 -2
- package/blueprints/application-spa/contributions/requirements/application-spa-req-016.json +6 -2
- package/blueprints/application-spa/contributions/requirements/application-spa-req-017.json +6 -2
- package/blueprints/application-spa/contributions/requirements/application-spa-req-018.json +7 -3
- package/blueprints/application-spa/contributions/requirements/application-spa-req-019.json +6 -2
- package/blueprints/application-spa/contributions/requirements/application-spa-req-020.json +6 -2
- package/blueprints/application-spa/contributions/requirements/application-spa-req-021.json +6 -2
- package/blueprints/application-spa/contributions/tacs/tac-201-application-spa-app-shell.json +4 -3
- package/blueprints/application-spa/contributions/tacs/tac-202-application-spa-theme-system.json +1 -1
- package/blueprints/application-spa/contributions/tacs/tac-203-application-spa-component-library.json +1 -1
- package/blueprints/application-spa/contributions/tacs/tac-204-application-spa-client-data-layer.json +1 -1
- package/blueprints/application-spa/contributions/tacs/tac-205-application-spa-forms-engine.json +1 -1
- package/blueprints/application-spa/contributions/tacs/tac-206-application-spa-telemetry.json +1 -1
- package/blueprints/application-spa/contributions/tacs/tac-207-application-spa-token-adherence-probe.json +2 -2
- package/blueprints/application-spa/contributions/tacs/tac-208-application-spa-icon-adherence-probe.json +3 -3
- package/blueprints/application-spa/contributions/tacs/tac-209-application-spa-csp-styled-adherence-probe.json +4 -4
- package/blueprints/application-spa/contributions/tacs/tac-210-application-spa-external-dependency-provisioning-probe.json +3 -3
- package/blueprints/application-spa/contributions/tacs/tac-211-application-spa-core-flow-e2e-probe.json +3 -3
- package/blueprints/application-spa/contributions/user-stories/application-spa-us-1101.json +22 -8
- package/blueprints/application-spa/contributions/user-stories/application-spa-us-1102.json +18 -9
- package/blueprints/application-spa/contributions/user-stories/application-spa-us-1103.json +13 -7
- package/blueprints/application-spa/contributions/user-stories/application-spa-us-1104.json +15 -10
- package/blueprints/application-spa/contributions/user-stories/application-spa-us-1105.json +13 -7
- package/blueprints/application-spa/contributions/user-stories/application-spa-us-1106.json +12 -7
- package/blueprints/application-spa/contributions/user-stories/application-spa-us-1107.json +25 -6
- package/blueprints/application-spa/contributions/user-stories/application-spa-us-1108.json +17 -9
- package/blueprints/application-spa/contributions/user-stories/application-spa-us-1109.json +17 -9
- package/blueprints/application-spa/contributions/user-stories/application-spa-us-1110.json +19 -10
- package/blueprints/application-spa/contributions/user-stories/application-spa-us-1111.json +19 -11
- package/blueprints/application-spa/contributions/user-stories/application-spa-us-1112.json +15 -8
- package/blueprints/application-spa/contributions/user-stories/application-spa-us-1113.json +15 -8
- package/blueprints/application-spa/contributions/user-stories/application-spa-us-1114.json +15 -10
- package/blueprints/application-spa/contributions/user-stories/application-spa-us-1115.json +13 -7
- package/blueprints/application-spa/contributions/user-stories/application-spa-us-1116.json +15 -9
- package/blueprints/application-spa/contributions/user-stories/application-spa-us-1117.json +20 -10
- package/blueprints/application-spa/contributions/user-stories/application-spa-us-1118.json +9 -5
- package/blueprints/application-spa/contributions/user-stories/application-spa-us-1119.json +11 -6
- package/blueprints/application-spa/contributions/user-stories/application-spa-us-1120.json +16 -10
- package/blueprints/application-spa/contributions/user-stories/application-spa-us-1121.json +13 -7
- package/blueprints/application-spa/contributions/user-stories/application-spa-us-1122.json +13 -7
- package/blueprints/application-spa/contributions/user-stories/application-spa-us-1123.json +28 -9
- package/blueprints/application-spa/contributions/user-stories/application-spa-us-1124.json +11 -6
- package/blueprints/application-spa/contributions/user-stories/application-spa-us-1125.json +14 -8
- package/blueprints/application-spa/contributions/user-stories/application-spa-us-1126.json +24 -9
- package/blueprints/application-spa/contributions/user-stories/application-spa-us-1127.json +11 -6
- package/blueprints/application-spa/contributions/user-stories/application-spa-us-1128.json +11 -7
- package/blueprints/application-spa/contributions/user-stories/application-spa-us-1129.json +25 -5
- package/blueprints/application-spa/contributions/user-stories/application-spa-us-1130.json +25 -5
- package/blueprints/application-spa/contributions/user-stories/application-spa-us-1131.json +19 -9
- package/blueprints/application-spa/contributions/user-stories/application-spa-us-1132.json +40 -10
- package/blueprints/application-spa/contributions/user-stories/application-spa-us-1133.json +35 -9
- package/blueprints/application-spa/contributions/user-stories/application-spa-us-1134.json +23 -3
- package/blueprints/application-spa/contributions/user-stories/application-spa-us-1135.json +19 -3
- package/blueprints/application-spa/docs/topics.md +1 -1
- package/blueprints/application-spa/guide/application-spa.md +2 -2
- package/blueprints/delivery-ci-workflows/CHANGELOG.md +40 -2
- package/blueprints/delivery-ci-workflows/README.md +4 -4
- package/blueprints/delivery-ci-workflows/blueprint.json +64 -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-001.json +4 -0
- package/blueprints/delivery-ci-workflows/contributions/requirements/delivery-ci-workflows-req-002.json +4 -0
- package/blueprints/delivery-ci-workflows/contributions/requirements/delivery-ci-workflows-req-003.json +4 -0
- package/blueprints/delivery-ci-workflows/contributions/requirements/delivery-ci-workflows-req-004.json +5 -1
- package/blueprints/delivery-ci-workflows/contributions/requirements/delivery-ci-workflows-req-005.json +4 -0
- package/blueprints/delivery-ci-workflows/contributions/requirements/delivery-ci-workflows-req-006.json +4 -0
- package/blueprints/delivery-ci-workflows/contributions/requirements/delivery-ci-workflows-req-007.json +4 -0
- package/blueprints/delivery-ci-workflows/contributions/requirements/delivery-ci-workflows-req-008.json +4 -0
- package/blueprints/delivery-ci-workflows/contributions/requirements/delivery-ci-workflows-req-009.json +4 -0
- package/blueprints/delivery-ci-workflows/contributions/requirements/delivery-ci-workflows-req-010.json +4 -0
- package/blueprints/delivery-ci-workflows/contributions/requirements/delivery-ci-workflows-req-011.json +6 -2
- package/blueprints/delivery-ci-workflows/contributions/requirements/delivery-ci-workflows-req-012.json +4 -0
- package/blueprints/delivery-ci-workflows/contributions/requirements/delivery-ci-workflows-req-013.json +4 -0
- package/blueprints/delivery-ci-workflows/contributions/requirements/delivery-ci-workflows-req-014.json +4 -0
- package/blueprints/delivery-ci-workflows/contributions/requirements/delivery-ci-workflows-req-015.json +4 -0
- package/blueprints/delivery-ci-workflows/contributions/requirements/delivery-ci-workflows-req-016.json +4 -0
- package/blueprints/delivery-ci-workflows/contributions/requirements/delivery-ci-workflows-req-017.json +4 -0
- package/blueprints/delivery-ci-workflows/contributions/requirements/delivery-ci-workflows-req-018.json +4 -0
- package/blueprints/delivery-ci-workflows/contributions/requirements/delivery-ci-workflows-req-019.json +4 -0
- package/blueprints/delivery-ci-workflows/contributions/requirements/delivery-ci-workflows-req-020.json +4 -0
- package/blueprints/delivery-ci-workflows/contributions/requirements/delivery-ci-workflows-req-021.json +4 -0
- package/blueprints/delivery-ci-workflows/contributions/requirements/delivery-ci-workflows-req-022.json +4 -0
- package/blueprints/delivery-ci-workflows/contributions/requirements/delivery-ci-workflows-req-023.json +4 -0
- package/blueprints/delivery-ci-workflows/contributions/user-stories/delivery-ci-workflows-us-6101.json +20 -4
- package/blueprints/delivery-ci-workflows/contributions/user-stories/delivery-ci-workflows-us-6102.json +19 -3
- package/blueprints/delivery-ci-workflows/contributions/user-stories/delivery-ci-workflows-us-6103.json +20 -4
- package/blueprints/delivery-ci-workflows/contributions/user-stories/delivery-ci-workflows-us-6104.json +20 -4
- package/blueprints/delivery-ci-workflows/contributions/user-stories/delivery-ci-workflows-us-6105.json +20 -4
- package/blueprints/delivery-ci-workflows/contributions/user-stories/delivery-ci-workflows-us-6106.json +20 -4
- package/blueprints/delivery-ci-workflows/contributions/user-stories/delivery-ci-workflows-us-6107.json +20 -4
- package/blueprints/delivery-ci-workflows/contributions/user-stories/delivery-ci-workflows-us-6108.json +20 -4
- package/blueprints/delivery-ci-workflows/contributions/user-stories/delivery-ci-workflows-us-6109.json +12 -5
- package/blueprints/delivery-ci-workflows/contributions/user-stories/delivery-ci-workflows-us-6110.json +21 -5
- package/blueprints/delivery-ci-workflows/contributions/user-stories/delivery-ci-workflows-us-6111.json +21 -5
- package/blueprints/delivery-ci-workflows/contributions/user-stories/delivery-ci-workflows-us-6112.json +35 -5
- package/blueprints/delivery-ci-workflows/contributions/user-stories/delivery-ci-workflows-us-6113.json +21 -5
- package/blueprints/delivery-ci-workflows/contributions/user-stories/delivery-ci-workflows-us-6114.json +8 -5
- package/blueprints/delivery-ci-workflows/contributions/user-stories/delivery-ci-workflows-us-6115.json +21 -5
- package/blueprints/delivery-ci-workflows/contributions/user-stories/delivery-ci-workflows-us-6116.json +19 -3
- package/blueprints/delivery-ci-workflows/contributions/user-stories/delivery-ci-workflows-us-6117.json +19 -3
- package/blueprints/delivery-ci-workflows/contributions/user-stories/delivery-ci-workflows-us-6118.json +21 -5
- package/blueprints/delivery-ci-workflows/contributions/user-stories/delivery-ci-workflows-us-6119.json +19 -3
- package/blueprints/delivery-ci-workflows/contributions/user-stories/delivery-ci-workflows-us-6120.json +19 -3
- package/blueprints/delivery-ci-workflows/contributions/user-stories/delivery-ci-workflows-us-6121.json +23 -6
- package/blueprints/delivery-ci-workflows/contributions/user-stories/delivery-ci-workflows-us-6122.json +24 -7
- package/blueprints/delivery-ci-workflows/contributions/user-stories/delivery-ci-workflows-us-6123.json +21 -5
- package/blueprints/delivery-ci-workflows/contributions/user-stories/delivery-ci-workflows-us-6124.json +19 -3
- package/blueprints/delivery-ci-workflows/docs/topics.md +2 -3
- package/blueprints/deploy-cloudflare-workers/CHANGELOG.md +19 -4
- package/blueprints/deploy-cloudflare-workers/README.md +5 -5
- package/blueprints/deploy-cloudflare-workers/blueprint.json +4 -4
- package/blueprints/deploy-cloudflare-workers/contributions/adrs/adr-1303-deploy-cloudflare-workers-preview-vs-production.json +1 -1
- package/blueprints/deploy-cloudflare-workers/contributions/adrs/adr-1306-deploy-cloudflare-workers-spa-shape.json +4 -4
- package/blueprints/deploy-cloudflare-workers/contributions/probes/assets-manifest-scan.mjs +25 -7
- package/blueprints/deploy-cloudflare-workers/contributions/requirements/deploy-cloudflare-workers-req-001.json +5 -1
- package/blueprints/deploy-cloudflare-workers/contributions/requirements/deploy-cloudflare-workers-req-002.json +6 -2
- package/blueprints/deploy-cloudflare-workers/contributions/requirements/deploy-cloudflare-workers-req-003.json +5 -1
- package/blueprints/deploy-cloudflare-workers/contributions/requirements/deploy-cloudflare-workers-req-004.json +5 -1
- package/blueprints/deploy-cloudflare-workers/contributions/requirements/deploy-cloudflare-workers-req-005.json +5 -1
- package/blueprints/deploy-cloudflare-workers/contributions/requirements/deploy-cloudflare-workers-req-006.json +5 -1
- package/blueprints/deploy-cloudflare-workers/contributions/requirements/deploy-cloudflare-workers-req-007.json +5 -1
- package/blueprints/deploy-cloudflare-workers/contributions/requirements/deploy-cloudflare-workers-req-008.json +5 -1
- package/blueprints/deploy-cloudflare-workers/contributions/requirements/deploy-cloudflare-workers-req-009.json +5 -1
- package/blueprints/deploy-cloudflare-workers/contributions/requirements/deploy-cloudflare-workers-req-010.json +5 -1
- package/blueprints/deploy-cloudflare-workers/contributions/requirements/deploy-cloudflare-workers-req-011.json +5 -1
- package/blueprints/deploy-cloudflare-workers/contributions/requirements/deploy-cloudflare-workers-req-012.json +5 -1
- package/blueprints/deploy-cloudflare-workers/contributions/requirements/deploy-cloudflare-workers-req-013.json +5 -1
- package/blueprints/deploy-cloudflare-workers/contributions/requirements/deploy-cloudflare-workers-req-014.json +7 -3
- package/blueprints/deploy-cloudflare-workers/contributions/tacs/tac-1301-deploy-cloudflare-workers-deploy-adapter.json +3 -2
- package/blueprints/deploy-cloudflare-workers/contributions/tacs/tac-1302-deploy-cloudflare-workers-wrangler-manifest.json +5 -2
- package/blueprints/deploy-cloudflare-workers/contributions/user-stories/deploy-cloudflare-workers-us-12101.json +21 -9
- package/blueprints/deploy-cloudflare-workers/contributions/user-stories/deploy-cloudflare-workers-us-12102.json +23 -4
- package/blueprints/deploy-cloudflare-workers/contributions/user-stories/deploy-cloudflare-workers-us-12103.json +7 -4
- package/blueprints/deploy-cloudflare-workers/contributions/user-stories/deploy-cloudflare-workers-us-12104.json +7 -4
- package/blueprints/deploy-cloudflare-workers/contributions/user-stories/deploy-cloudflare-workers-us-12105.json +11 -4
- package/blueprints/deploy-cloudflare-workers/contributions/user-stories/deploy-cloudflare-workers-us-12106.json +7 -4
- package/blueprints/deploy-cloudflare-workers/contributions/user-stories/deploy-cloudflare-workers-us-12107.json +7 -4
- package/blueprints/deploy-cloudflare-workers/contributions/user-stories/deploy-cloudflare-workers-us-12108.json +15 -4
- package/blueprints/deploy-cloudflare-workers/contributions/user-stories/deploy-cloudflare-workers-us-12109.json +11 -4
- package/blueprints/deploy-cloudflare-workers/contributions/user-stories/deploy-cloudflare-workers-us-12110.json +7 -4
- package/blueprints/deploy-cloudflare-workers/contributions/user-stories/deploy-cloudflare-workers-us-12111.json +11 -4
- package/blueprints/deploy-cloudflare-workers/contributions/user-stories/deploy-cloudflare-workers-us-12112.json +11 -4
- package/blueprints/deploy-cloudflare-workers/contributions/user-stories/deploy-cloudflare-workers-us-12113.json +41 -3
- package/blueprints/deploy-cloudflare-workers/contributions/user-stories/deploy-cloudflare-workers-us-12114.json +17 -2
- package/blueprints/deploy-cloudflare-workers/contributions/user-stories/deploy-cloudflare-workers-us-12115.json +18 -3
- package/blueprints/deploy-cloudflare-workers/docs/topics.md +2 -2
- package/blueprints/deploy-cloudflare-workers/guide/deploy-cloudflare-workers.md +7 -2
- package/blueprints/deploy-hetzner-server/CHANGELOG.md +115 -8
- package/blueprints/deploy-hetzner-server/README.md +12 -12
- package/blueprints/deploy-hetzner-server/blueprint.json +8 -7
- package/blueprints/deploy-hetzner-server/contributions/adrs/adr-3801-deploy-hetzner-server-cloud-host-contract.json +2 -2
- package/blueprints/deploy-hetzner-server/contributions/adrs/adr-3803-deploy-hetzner-server-provisioning-tool.json +2 -2
- 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/deploy-hetzner-server/contributions/requirements/deploy-hetzner-server-req-001.json +6 -2
- package/blueprints/deploy-hetzner-server/contributions/requirements/deploy-hetzner-server-req-002.json +6 -2
- package/blueprints/deploy-hetzner-server/contributions/requirements/deploy-hetzner-server-req-003.json +5 -1
- package/blueprints/deploy-hetzner-server/contributions/requirements/deploy-hetzner-server-req-004.json +5 -1
- package/blueprints/deploy-hetzner-server/contributions/requirements/deploy-hetzner-server-req-005.json +6 -2
- package/blueprints/deploy-hetzner-server/contributions/requirements/deploy-hetzner-server-req-006.json +5 -1
- package/blueprints/deploy-hetzner-server/contributions/schemas/hetzner-server.schema.json +1 -1
- package/blueprints/deploy-hetzner-server/contributions/templates/cloud-init.yaml.tmpl +1 -1
- package/blueprints/deploy-hetzner-server/contributions/user-stories/deploy-hetzner-server-us-37101.json +63 -2
- package/blueprints/deploy-hetzner-server/contributions/user-stories/deploy-hetzner-server-us-37102.json +35 -2
- package/blueprints/deploy-hetzner-server/contributions/user-stories/deploy-hetzner-server-us-37103.json +59 -2
- package/blueprints/deploy-hetzner-server/contributions/user-stories/deploy-hetzner-server-us-37104.json +31 -2
- package/blueprints/deploy-hetzner-server/contributions/user-stories/deploy-hetzner-server-us-37105.json +25 -2
- package/blueprints/deploy-hetzner-server/contributions/user-stories/deploy-hetzner-server-us-37106.json +35 -2
- package/blueprints/deploy-hetzner-server/contributions/user-stories/deploy-hetzner-server-us-37107.json +31 -2
- package/blueprints/deploy-hetzner-server/contributions/user-stories/deploy-hetzner-server-us-37108.json +43 -2
- package/blueprints/deploy-hetzner-server/contributions/user-stories/deploy-hetzner-server-us-37109.json +31 -2
- package/blueprints/deploy-hetzner-server/docs/topics.md +2 -2
- package/blueprints/deploy-hetzner-server/guide/deploy-hetzner-server.md +12 -11
- package/blueprints/edge-cloudflare-access/CHANGELOG.md +36 -3
- package/blueprints/edge-cloudflare-access/README.md +2 -2
- package/blueprints/edge-cloudflare-access/blueprint.json +12 -2
- package/blueprints/edge-cloudflare-access/contributions/probes/admin-console-gate-surface.mjs +9 -1
- package/blueprints/edge-cloudflare-access/contributions/probes/real-account-gated-url.mjs +10 -2
- package/blueprints/edge-cloudflare-access/contributions/probes/wrangler-seam.mjs +1 -1
- package/blueprints/edge-cloudflare-access/contributions/requirements/edge-cloudflare-access-req-001.json +5 -1
- package/blueprints/edge-cloudflare-access/contributions/requirements/edge-cloudflare-access-req-002.json +5 -1
- package/blueprints/edge-cloudflare-access/contributions/requirements/edge-cloudflare-access-req-003.json +5 -1
- package/blueprints/edge-cloudflare-access/contributions/requirements/edge-cloudflare-access-req-004.json +6 -2
- package/blueprints/edge-cloudflare-access/contributions/requirements/edge-cloudflare-access-req-005.json +5 -1
- package/blueprints/edge-cloudflare-access/contributions/requirements/edge-cloudflare-access-req-006.json +7 -3
- package/blueprints/edge-cloudflare-access/contributions/requirements/edge-cloudflare-access-req-007.json +22 -0
- package/blueprints/edge-cloudflare-access/contributions/user-stories/edge-cloudflare-access-us-34101.json +13 -3
- package/blueprints/edge-cloudflare-access/contributions/user-stories/edge-cloudflare-access-us-34102.json +63 -2
- package/blueprints/edge-cloudflare-access/contributions/user-stories/edge-cloudflare-access-us-34103.json +18 -3
- package/blueprints/edge-cloudflare-access/contributions/user-stories/edge-cloudflare-access-us-34104.json +36 -3
- package/blueprints/edge-cloudflare-access/contributions/user-stories/edge-cloudflare-access-us-34105.json +13 -3
- package/blueprints/edge-cloudflare-access/contributions/user-stories/edge-cloudflare-access-us-34106.json +9 -3
- package/blueprints/edge-cloudflare-access/contributions/user-stories/edge-cloudflare-access-us-34107.json +68 -3
- package/blueprints/edge-cloudflare-access/contributions/user-stories/edge-cloudflare-access-us-34108.json +5 -3
- package/blueprints/edge-cloudflare-access/contributions/user-stories/edge-cloudflare-access-us-34109.json +10 -4
- package/blueprints/edge-cloudflare-access/contributions/user-stories/edge-cloudflare-access-us-34110.json +33 -0
- package/blueprints/edge-cloudflare-access/docs/topics.md +2 -2
- package/blueprints/edge-cloudflare-rate-limiting/CHANGELOG.md +33 -2
- package/blueprints/edge-cloudflare-rate-limiting/README.md +3 -3
- package/blueprints/edge-cloudflare-rate-limiting/blueprint.json +1 -1
- package/blueprints/edge-cloudflare-rate-limiting/contributions/probes/real-account-burst-and-429.mjs +10 -2
- package/blueprints/edge-cloudflare-rate-limiting/contributions/requirements/edge-cloudflare-rate-limiting-req-001.json +6 -2
- package/blueprints/edge-cloudflare-rate-limiting/contributions/requirements/edge-cloudflare-rate-limiting-req-002.json +5 -1
- package/blueprints/edge-cloudflare-rate-limiting/contributions/requirements/edge-cloudflare-rate-limiting-req-003.json +5 -1
- package/blueprints/edge-cloudflare-rate-limiting/contributions/requirements/edge-cloudflare-rate-limiting-req-004.json +6 -2
- package/blueprints/edge-cloudflare-rate-limiting/contributions/requirements/edge-cloudflare-rate-limiting-req-005.json +5 -1
- package/blueprints/edge-cloudflare-rate-limiting/contributions/tacs/tac-3701-edge-cloudflare-rate-limiting-manifest-schema.json +2 -2
- package/blueprints/edge-cloudflare-rate-limiting/contributions/tacs/tac-3703-edge-cloudflare-rate-limiting-drift-audit-runner.json +2 -2
- package/blueprints/edge-cloudflare-rate-limiting/contributions/user-stories/edge-cloudflare-rate-limiting-us-36101.json +27 -3
- package/blueprints/edge-cloudflare-rate-limiting/contributions/user-stories/edge-cloudflare-rate-limiting-us-36102.json +9 -3
- package/blueprints/edge-cloudflare-rate-limiting/contributions/user-stories/edge-cloudflare-rate-limiting-us-36103.json +24 -5
- package/blueprints/edge-cloudflare-rate-limiting/contributions/user-stories/edge-cloudflare-rate-limiting-us-36104.json +88 -3
- package/blueprints/edge-cloudflare-rate-limiting/contributions/user-stories/edge-cloudflare-rate-limiting-us-36105.json +5 -3
- package/blueprints/edge-cloudflare-rate-limiting/contributions/user-stories/edge-cloudflare-rate-limiting-us-36106.json +22 -3
- package/blueprints/edge-cloudflare-rate-limiting/contributions/user-stories/edge-cloudflare-rate-limiting-us-36107.json +16 -5
- package/blueprints/edge-cloudflare-rate-limiting/contributions/user-stories/edge-cloudflare-rate-limiting-us-36108.json +14 -3
- package/blueprints/edge-cloudflare-rate-limiting/docs/topics.md +1 -1
- package/blueprints/edge-cloudflare-rate-limiting/guide/edge-cloudflare-rate-limiting.md +2 -2
- package/blueprints/edge-cloudflare-tunnel/CHANGELOG.md +40 -7
- package/blueprints/edge-cloudflare-tunnel/README.md +21 -23
- package/blueprints/edge-cloudflare-tunnel/blueprint.json +29 -4
- package/blueprints/edge-cloudflare-tunnel/contributions/adrs/adr-4001-edge-cloudflare-tunnel-ingress-bridge-contract.json +4 -4
- package/blueprints/edge-cloudflare-tunnel/contributions/adrs/adr-4002-edge-cloudflare-tunnel-connector-runtime.json +1 -1
- package/blueprints/edge-cloudflare-tunnel/contributions/probes/manifest-schema-validate.mjs +3 -3
- package/blueprints/edge-cloudflare-tunnel/contributions/probes/probe-utils.mjs +13 -2
- package/blueprints/edge-cloudflare-tunnel/contributions/probes/real-account-connector-healthy.mjs +8 -9
- package/blueprints/edge-cloudflare-tunnel/contributions/probes/real-account-tunnel-hostname-routes.mjs +2 -2
- package/blueprints/edge-cloudflare-tunnel/contributions/requirements/edge-cloudflare-tunnel-req-001.json +6 -2
- package/blueprints/edge-cloudflare-tunnel/contributions/requirements/edge-cloudflare-tunnel-req-002.json +5 -1
- package/blueprints/edge-cloudflare-tunnel/contributions/requirements/edge-cloudflare-tunnel-req-003.json +7 -3
- package/blueprints/edge-cloudflare-tunnel/contributions/requirements/edge-cloudflare-tunnel-req-004.json +5 -1
- package/blueprints/edge-cloudflare-tunnel/contributions/requirements/edge-cloudflare-tunnel-req-005.json +5 -1
- package/blueprints/edge-cloudflare-tunnel/contributions/requirements/edge-cloudflare-tunnel-req-006.json +22 -0
- package/blueprints/edge-cloudflare-tunnel/contributions/requirements/edge-cloudflare-tunnel-req-007.json +22 -0
- package/blueprints/edge-cloudflare-tunnel/contributions/tacs/tac-4001-edge-cloudflare-tunnel-connector-shape.json +1 -1
- package/blueprints/edge-cloudflare-tunnel/contributions/tacs/tac-4004-edge-cloudflare-tunnel-zone-and-hostname-apply.json +29 -0
- package/blueprints/edge-cloudflare-tunnel/contributions/user-stories/edge-cloudflare-tunnel-us-39101.json +39 -3
- package/blueprints/edge-cloudflare-tunnel/contributions/user-stories/edge-cloudflare-tunnel-us-39102.json +23 -4
- package/blueprints/edge-cloudflare-tunnel/contributions/user-stories/edge-cloudflare-tunnel-us-39103.json +53 -3
- package/blueprints/edge-cloudflare-tunnel/contributions/user-stories/edge-cloudflare-tunnel-us-39104.json +33 -3
- package/blueprints/edge-cloudflare-tunnel/contributions/user-stories/edge-cloudflare-tunnel-us-39105.json +25 -3
- package/blueprints/edge-cloudflare-tunnel/contributions/user-stories/edge-cloudflare-tunnel-us-39106.json +86 -2
- package/blueprints/edge-cloudflare-tunnel/contributions/user-stories/edge-cloudflare-tunnel-us-39107.json +25 -3
- package/blueprints/edge-cloudflare-tunnel/contributions/user-stories/edge-cloudflare-tunnel-us-39108.json +35 -2
- package/blueprints/edge-cloudflare-tunnel/contributions/user-stories/edge-cloudflare-tunnel-us-39109.json +74 -0
- package/blueprints/edge-cloudflare-tunnel/contributions/user-stories/edge-cloudflare-tunnel-us-39110.json +60 -0
- package/blueprints/edge-cloudflare-tunnel/docs/topics.md +2 -2
- package/blueprints/edge-cloudflare-tunnel/guide/edge-cloudflare-tunnel.md +60 -13
- package/blueprints/edge-cloudflare-turnstile/CHANGELOG.md +32 -1
- package/blueprints/edge-cloudflare-turnstile/README.md +2 -2
- package/blueprints/edge-cloudflare-turnstile/blueprint.json +1 -1
- package/blueprints/edge-cloudflare-turnstile/contributions/requirements/edge-cloudflare-turnstile-req-001.json +6 -2
- package/blueprints/edge-cloudflare-turnstile/contributions/requirements/edge-cloudflare-turnstile-req-002.json +5 -1
- package/blueprints/edge-cloudflare-turnstile/contributions/requirements/edge-cloudflare-turnstile-req-003.json +6 -2
- package/blueprints/edge-cloudflare-turnstile/contributions/requirements/edge-cloudflare-turnstile-req-004.json +5 -1
- package/blueprints/edge-cloudflare-turnstile/contributions/requirements/edge-cloudflare-turnstile-req-005.json +5 -1
- package/blueprints/edge-cloudflare-turnstile/contributions/tacs/tac-3601-edge-cloudflare-turnstile-widget-mount.json +2 -2
- package/blueprints/edge-cloudflare-turnstile/contributions/tacs/tac-3602-edge-cloudflare-turnstile-server-verifier.json +2 -2
- package/blueprints/edge-cloudflare-turnstile/contributions/user-stories/edge-cloudflare-turnstile-us-35101.json +46 -5
- package/blueprints/edge-cloudflare-turnstile/contributions/user-stories/edge-cloudflare-turnstile-us-35102.json +53 -2
- package/blueprints/edge-cloudflare-turnstile/contributions/user-stories/edge-cloudflare-turnstile-us-35103.json +81 -2
- package/blueprints/edge-cloudflare-turnstile/contributions/user-stories/edge-cloudflare-turnstile-us-35104.json +29 -6
- package/blueprints/edge-cloudflare-turnstile/contributions/user-stories/edge-cloudflare-turnstile-us-35105.json +14 -4
- package/blueprints/edge-cloudflare-turnstile/contributions/user-stories/edge-cloudflare-turnstile-us-35106.json +9 -3
- package/blueprints/edge-cloudflare-turnstile/contributions/user-stories/edge-cloudflare-turnstile-us-35107.json +5 -3
- package/blueprints/edge-cloudflare-turnstile/contributions/user-stories/edge-cloudflare-turnstile-us-35108.json +5 -3
- package/blueprints/edge-cloudflare-turnstile/docs/topics.md +1 -1
- package/blueprints/edge-cloudflare-turnstile/probe-packs/edge-cloudflare-turnstile.pack.mjs +27 -5
- package/blueprints/email-smtp-resend/CHANGELOG.md +40 -0
- package/blueprints/email-smtp-resend/README.md +4 -4
- package/blueprints/email-smtp-resend/assets/stub-adapter.md +2 -0
- package/blueprints/email-smtp-resend/blueprint.json +121 -18
- 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/contributions/requirements/email-smtp-resend-req-001.json +7 -3
- package/blueprints/email-smtp-resend/contributions/requirements/email-smtp-resend-req-002.json +4 -0
- package/blueprints/email-smtp-resend/contributions/requirements/email-smtp-resend-req-003.json +4 -0
- package/blueprints/email-smtp-resend/contributions/requirements/email-smtp-resend-req-004.json +4 -0
- package/blueprints/email-smtp-resend/contributions/requirements/email-smtp-resend-req-005.json +4 -0
- package/blueprints/email-smtp-resend/contributions/requirements/email-smtp-resend-req-006.json +4 -0
- package/blueprints/email-smtp-resend/contributions/tacs/tac-401-email-smtp-resend-send-adapter.json +3 -3
- package/blueprints/email-smtp-resend/contributions/tacs/tac-402-email-smtp-resend-webhook-verifier.json +7 -2
- package/blueprints/email-smtp-resend/contributions/user-stories/email-smtp-resend-us-4101.json +15 -8
- package/blueprints/email-smtp-resend/contributions/user-stories/email-smtp-resend-us-4102.json +27 -7
- package/blueprints/email-smtp-resend/contributions/user-stories/email-smtp-resend-us-4103.json +49 -4
- package/blueprints/email-smtp-resend/contributions/user-stories/email-smtp-resend-us-4104.json +6 -3
- package/blueprints/email-smtp-resend/contributions/user-stories/email-smtp-resend-us-4105.json +21 -5
- package/blueprints/email-smtp-resend/contributions/user-stories/email-smtp-resend-us-4106.json +27 -7
- package/blueprints/email-smtp-resend/docs/topics.md +2 -3
- package/blueprints/email-smtp-resend/guide/email-smtp-resend.md +2 -2
- package/blueprints/jobs-background/CHANGELOG.md +91 -6
- package/blueprints/jobs-background/README.md +8 -8
- package/blueprints/jobs-background/blueprint.json +57 -3
- package/blueprints/jobs-background/contributions/adrs/adr-3102-jobs-background-scheduler-mode.json +1 -1
- package/blueprints/jobs-background/contributions/adrs/adr-3103-jobs-background-requires-applied-capabilities.json +6 -6
- 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 +14 -6
- 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/contributions/requirements/jobs-background-req-001.json +7 -3
- package/blueprints/jobs-background/contributions/requirements/jobs-background-req-002.json +7 -3
- package/blueprints/jobs-background/contributions/requirements/jobs-background-req-003.json +5 -1
- package/blueprints/jobs-background/contributions/requirements/jobs-background-req-004.json +5 -1
- package/blueprints/jobs-background/contributions/requirements/jobs-background-req-005.json +5 -1
- package/blueprints/jobs-background/contributions/requirements/jobs-background-req-006.json +5 -1
- package/blueprints/jobs-background/contributions/tacs/tac-3101-jobs-background-job-definition.json +5 -5
- package/blueprints/jobs-background/contributions/user-stories/jobs-background-us-30101.json +20 -3
- package/blueprints/jobs-background/contributions/user-stories/jobs-background-us-30102.json +44 -9
- package/blueprints/jobs-background/contributions/user-stories/jobs-background-us-30103.json +48 -3
- package/blueprints/jobs-background/contributions/user-stories/jobs-background-us-30104.json +63 -3
- package/blueprints/jobs-background/contributions/user-stories/jobs-background-us-30105.json +20 -3
- package/blueprints/jobs-background/contributions/user-stories/jobs-background-us-30106.json +20 -3
- package/blueprints/jobs-background/contributions/user-stories/jobs-background-us-30107.json +20 -3
- package/blueprints/jobs-background/contributions/user-stories/jobs-background-us-30108.json +21 -3
- package/blueprints/jobs-background/contributions/user-stories/jobs-background-us-30109.json +23 -6
- package/blueprints/jobs-background/docs/topics.md +3 -3
- package/blueprints/jobs-background/guide/jobs-background.md +6 -6
- package/blueprints/messaging-queue-cloudflare/CHANGELOG.md +41 -19
- package/blueprints/messaging-queue-cloudflare/README.md +14 -14
- package/blueprints/messaging-queue-cloudflare/blueprint.json +127 -19
- package/blueprints/messaging-queue-cloudflare/contributions/adrs/adr-3001-messaging-queue-cloudflare-adapter.json +3 -3
- 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 +183 -15
- package/blueprints/messaging-queue-cloudflare/contributions/requirements/messaging-queue-cloudflare-req-001.json +6 -2
- package/blueprints/messaging-queue-cloudflare/contributions/requirements/messaging-queue-cloudflare-req-002.json +6 -2
- package/blueprints/messaging-queue-cloudflare/contributions/requirements/messaging-queue-cloudflare-req-003.json +5 -1
- package/blueprints/messaging-queue-cloudflare/contributions/requirements/messaging-queue-cloudflare-req-004.json +6 -2
- package/blueprints/messaging-queue-cloudflare/contributions/requirements/messaging-queue-cloudflare-req-005.json +6 -2
- package/blueprints/messaging-queue-cloudflare/contributions/requirements/messaging-queue-cloudflare-req-006.json +6 -2
- package/blueprints/messaging-queue-cloudflare/contributions/user-stories/messaging-queue-cloudflare-us-29101.json +22 -4
- package/blueprints/messaging-queue-cloudflare/contributions/user-stories/messaging-queue-cloudflare-us-29102.json +23 -4
- package/blueprints/messaging-queue-cloudflare/contributions/user-stories/messaging-queue-cloudflare-us-29103.json +20 -3
- package/blueprints/messaging-queue-cloudflare/contributions/user-stories/messaging-queue-cloudflare-us-29104.json +29 -7
- package/blueprints/messaging-queue-cloudflare/contributions/user-stories/messaging-queue-cloudflare-us-29105.json +20 -3
- package/blueprints/messaging-queue-cloudflare/contributions/user-stories/messaging-queue-cloudflare-us-29106.json +25 -4
- package/blueprints/messaging-queue-cloudflare/contributions/user-stories/messaging-queue-cloudflare-us-29107.json +25 -3
- package/blueprints/messaging-queue-cloudflare/contributions/user-stories/messaging-queue-cloudflare-us-29108.json +28 -6
- package/blueprints/messaging-queue-cloudflare/docs/topics.md +3 -3
- package/blueprints/messaging-queue-cloudflare/guide/messaging-queue-cloudflare.md +8 -6
- package/blueprints/object-storage-s3/CHANGELOG.md +94 -6
- package/blueprints/object-storage-s3/README.md +2 -2
- package/blueprints/object-storage-s3/blueprint.json +156 -24
- 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 +103 -19
- 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-001.json +6 -2
- package/blueprints/object-storage-s3/contributions/requirements/object-storage-s3-req-002.json +6 -2
- package/blueprints/object-storage-s3/contributions/requirements/object-storage-s3-req-003.json +5 -1
- package/blueprints/object-storage-s3/contributions/requirements/object-storage-s3-req-004.json +6 -2
- package/blueprints/object-storage-s3/contributions/requirements/object-storage-s3-req-005.json +6 -2
- package/blueprints/object-storage-s3/contributions/requirements/object-storage-s3-req-006.json +6 -2
- package/blueprints/object-storage-s3/contributions/requirements/object-storage-s3-req-101.json +5 -1
- package/blueprints/object-storage-s3/contributions/user-stories/object-storage-s3-us-28101.json +36 -4
- package/blueprints/object-storage-s3/contributions/user-stories/object-storage-s3-us-28102.json +32 -5
- package/blueprints/object-storage-s3/contributions/user-stories/object-storage-s3-us-28103.json +42 -3
- package/blueprints/object-storage-s3/contributions/user-stories/object-storage-s3-us-28104.json +22 -4
- package/blueprints/object-storage-s3/contributions/user-stories/object-storage-s3-us-28105.json +25 -4
- package/blueprints/object-storage-s3/contributions/user-stories/object-storage-s3-us-28106.json +13 -5
- package/blueprints/object-storage-s3/contributions/user-stories/object-storage-s3-us-28107.json +10 -4
- package/blueprints/object-storage-s3/contributions/user-stories/object-storage-s3-us-28108.json +12 -4
- package/blueprints/object-storage-s3/contributions/user-stories/object-storage-s3-us-28110.json +20 -3
- package/blueprints/object-storage-s3/docs/topics.md +1 -1
- package/blueprints/object-storage-s3/guide/object-storage-s3.md +3 -3
- package/blueprints/observability-essentials/CHANGELOG.md +37 -0
- package/blueprints/observability-essentials/README.md +3 -3
- package/blueprints/observability-essentials/assets/probe-samples/probe-response-baseline.v2.json +17 -0
- package/blueprints/observability-essentials/blueprint.json +34 -2
- package/blueprints/observability-essentials/contributions/adrs/adr-801-observability-essentials-health-probes.json +1 -1
- 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/contributions/requirements/observability-essentials-req-001.json +4 -0
- package/blueprints/observability-essentials/contributions/requirements/observability-essentials-req-002.json +4 -0
- package/blueprints/observability-essentials/contributions/requirements/observability-essentials-req-003.json +4 -0
- package/blueprints/observability-essentials/contributions/requirements/observability-essentials-req-004.json +4 -0
- package/blueprints/observability-essentials/contributions/requirements/observability-essentials-req-005.json +4 -0
- package/blueprints/observability-essentials/contributions/requirements/observability-essentials-req-006.json +6 -2
- package/blueprints/observability-essentials/contributions/requirements/observability-essentials-req-007.json +7 -3
- package/blueprints/observability-essentials/contributions/requirements/observability-essentials-req-008.json +4 -0
- package/blueprints/observability-essentials/contributions/requirements/observability-essentials-req-009.json +4 -0
- package/blueprints/observability-essentials/contributions/requirements/observability-essentials-req-010.json +4 -0
- package/blueprints/observability-essentials/contributions/tacs/tac-802-observability-essentials-readiness-probe.json +6 -1
- package/blueprints/observability-essentials/contributions/tacs/tac-803-observability-essentials-status-page.json +1 -1
- package/blueprints/observability-essentials/contributions/user-stories/observability-essentials-us-7101.json +25 -7
- package/blueprints/observability-essentials/contributions/user-stories/observability-essentials-us-7102.json +9 -5
- package/blueprints/observability-essentials/contributions/user-stories/observability-essentials-us-7103.json +51 -6
- package/blueprints/observability-essentials/contributions/user-stories/observability-essentials-us-7104.json +7 -4
- package/blueprints/observability-essentials/contributions/user-stories/observability-essentials-us-7105.json +6 -3
- package/blueprints/observability-essentials/contributions/user-stories/observability-essentials-us-7106.json +37 -6
- package/blueprints/observability-essentials/contributions/user-stories/observability-essentials-us-7107.json +18 -11
- package/blueprints/observability-essentials/contributions/user-stories/observability-essentials-us-7108.json +6 -3
- package/blueprints/observability-essentials/contributions/user-stories/observability-essentials-us-7109.json +7 -4
- package/blueprints/observability-essentials/contributions/user-stories/observability-essentials-us-7110.json +8 -5
- package/blueprints/observability-essentials/docs/topics.md +3 -4
- package/blueprints/observability-essentials/guide/observability-essentials.md +1 -1
- package/blueprints/observability-logging/CHANGELOG.md +44 -4
- package/blueprints/observability-logging/README.md +2 -2
- package/blueprints/observability-logging/blueprint.json +78 -29
- package/blueprints/observability-logging/contributions/adrs/adr-1605-observability-logging-serialisation-refusal.json +25 -0
- 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-logging/contributions/requirements/observability-logging-req-001.json +10 -3
- package/blueprints/observability-logging/contributions/requirements/observability-logging-req-002.json +8 -1
- package/blueprints/observability-logging/contributions/requirements/observability-logging-req-003.json +8 -1
- package/blueprints/observability-logging/contributions/requirements/observability-logging-req-004.json +8 -1
- package/blueprints/observability-logging/contributions/requirements/observability-logging-req-005.json +8 -1
- package/blueprints/observability-logging/contributions/requirements/observability-logging-req-006.json +16 -0
- package/blueprints/observability-logging/contributions/tacs/tac-1601-observability-logging-logger-factory.json +4 -4
- package/blueprints/observability-logging/contributions/user-stories/observability-logging-us-15101.json +62 -8
- package/blueprints/observability-logging/contributions/user-stories/observability-logging-us-15102.json +11 -6
- package/blueprints/observability-logging/contributions/user-stories/observability-logging-us-15103.json +37 -5
- package/blueprints/observability-logging/contributions/user-stories/observability-logging-us-15104.json +35 -4
- package/blueprints/observability-logging/contributions/user-stories/observability-logging-us-15105.json +24 -6
- package/blueprints/observability-logging/contributions/user-stories/observability-logging-us-15106.json +22 -4
- package/blueprints/observability-logging/contributions/user-stories/observability-logging-us-15107.json +34 -3
- package/blueprints/observability-logging/contributions/user-stories/observability-logging-us-15108.json +21 -3
- package/blueprints/observability-logging/contributions/user-stories/observability-logging-us-15109.json +71 -0
- package/blueprints/observability-probe-endpoints/CHANGELOG.md +32 -0
- package/blueprints/observability-probe-endpoints/README.md +4 -4
- package/blueprints/observability-probe-endpoints/blueprint.json +42 -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/contributions/requirements/observability-probe-endpoints-req-001.json +6 -2
- package/blueprints/observability-probe-endpoints/contributions/requirements/observability-probe-endpoints-req-002.json +4 -0
- package/blueprints/observability-probe-endpoints/contributions/requirements/observability-probe-endpoints-req-003.json +4 -0
- package/blueprints/observability-probe-endpoints/contributions/requirements/observability-probe-endpoints-req-004.json +4 -0
- package/blueprints/observability-probe-endpoints/contributions/requirements/observability-probe-endpoints-req-005.json +4 -0
- package/blueprints/observability-probe-endpoints/contributions/requirements/observability-probe-endpoints-req-006.json +4 -0
- package/blueprints/observability-probe-endpoints/contributions/requirements/observability-probe-endpoints-req-007.json +4 -0
- package/blueprints/observability-probe-endpoints/contributions/requirements/observability-probe-endpoints-req-008.json +4 -0
- package/blueprints/observability-probe-endpoints/contributions/user-stories/observability-probe-endpoints-us-14101.json +30 -9
- package/blueprints/observability-probe-endpoints/contributions/user-stories/observability-probe-endpoints-us-14102.json +24 -6
- package/blueprints/observability-probe-endpoints/contributions/user-stories/observability-probe-endpoints-us-14103.json +6 -3
- package/blueprints/observability-probe-endpoints/contributions/user-stories/observability-probe-endpoints-us-14104.json +9 -6
- package/blueprints/observability-probe-endpoints/contributions/user-stories/observability-probe-endpoints-us-14105.json +49 -4
- package/blueprints/observability-probe-endpoints/contributions/user-stories/observability-probe-endpoints-us-14106.json +9 -6
- package/blueprints/observability-probe-endpoints/contributions/user-stories/observability-probe-endpoints-us-14107.json +12 -8
- package/blueprints/observability-probe-endpoints/contributions/user-stories/observability-probe-endpoints-us-14108.json +6 -3
- package/blueprints/observability-probe-endpoints/docs/topics.md +2 -2
- package/blueprints/observability-probe-endpoints/guide/observability-probe-endpoints.md +3 -6
- package/blueprints/persistence-data-d1/CHANGELOG.md +32 -0
- package/blueprints/persistence-data-d1/README.md +3 -3
- package/blueprints/persistence-data-d1/assets/batch-usage/batch-atomicity-example.md +2 -0
- package/blueprints/persistence-data-d1/assets/facade-shape/facade-module-shape.md +2 -0
- package/blueprints/persistence-data-d1/blueprint.json +108 -23
- package/blueprints/persistence-data-d1/contributions/adrs/adr-1404-persistence-data-d1-store-boundary.json +4 -4
- 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/contributions/requirements/persistence-data-d1-req-001.json +5 -1
- package/blueprints/persistence-data-d1/contributions/requirements/persistence-data-d1-req-002.json +5 -1
- package/blueprints/persistence-data-d1/contributions/requirements/persistence-data-d1-req-003.json +5 -1
- package/blueprints/persistence-data-d1/contributions/requirements/persistence-data-d1-req-004.json +7 -3
- package/blueprints/persistence-data-d1/contributions/requirements/persistence-data-d1-req-005.json +5 -1
- package/blueprints/persistence-data-d1/contributions/requirements/persistence-data-d1-req-006.json +5 -1
- package/blueprints/persistence-data-d1/contributions/requirements/persistence-data-d1-req-007.json +5 -1
- package/blueprints/persistence-data-d1/contributions/user-stories/persistence-data-d1-us-13101.json +35 -4
- package/blueprints/persistence-data-d1/contributions/user-stories/persistence-data-d1-us-13102.json +25 -4
- package/blueprints/persistence-data-d1/contributions/user-stories/persistence-data-d1-us-13103.json +11 -4
- package/blueprints/persistence-data-d1/contributions/user-stories/persistence-data-d1-us-13104.json +13 -6
- package/blueprints/persistence-data-d1/contributions/user-stories/persistence-data-d1-us-13105.json +11 -4
- package/blueprints/persistence-data-d1/contributions/user-stories/persistence-data-d1-us-13106.json +7 -4
- package/blueprints/persistence-data-d1/contributions/user-stories/persistence-data-d1-us-13107.json +23 -3
- package/blueprints/persistence-data-d1/docs/topics.md +2 -3
- package/blueprints/persistence-data-postgres/CHANGELOG.md +99 -3
- package/blueprints/persistence-data-postgres/README.md +2 -2
- package/blueprints/persistence-data-postgres/blueprint.json +203 -24
- package/blueprints/persistence-data-postgres/contributions/adrs/adr-2801-persistence-data-postgres-driver.json +1 -1
- package/blueprints/persistence-data-postgres/contributions/adrs/adr-2805-persistence-data-postgres-connection-pool-posture.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-001.json +6 -2
- package/blueprints/persistence-data-postgres/contributions/requirements/persistence-data-postgres-req-002.json +6 -2
- package/blueprints/persistence-data-postgres/contributions/requirements/persistence-data-postgres-req-003.json +6 -2
- package/blueprints/persistence-data-postgres/contributions/requirements/persistence-data-postgres-req-004.json +7 -3
- package/blueprints/persistence-data-postgres/contributions/requirements/persistence-data-postgres-req-005.json +6 -2
- package/blueprints/persistence-data-postgres/contributions/requirements/persistence-data-postgres-req-006.json +6 -2
- package/blueprints/persistence-data-postgres/contributions/requirements/persistence-data-postgres-req-007.json +7 -3
- package/blueprints/persistence-data-postgres/contributions/tacs/tac-2802-persistence-data-postgres-migration-runner.json +2 -2
- package/blueprints/persistence-data-postgres/contributions/tacs/tac-2803-persistence-data-postgres-transaction-helper.json +5 -5
- package/blueprints/persistence-data-postgres/contributions/user-stories/persistence-data-postgres-us-27101.json +22 -4
- package/blueprints/persistence-data-postgres/contributions/user-stories/persistence-data-postgres-us-27102.json +118 -3
- package/blueprints/persistence-data-postgres/contributions/user-stories/persistence-data-postgres-us-27103.json +20 -3
- package/blueprints/persistence-data-postgres/contributions/user-stories/persistence-data-postgres-us-27104.json +26 -5
- package/blueprints/persistence-data-postgres/contributions/user-stories/persistence-data-postgres-us-27105.json +62 -3
- package/blueprints/persistence-data-postgres/contributions/user-stories/persistence-data-postgres-us-27106.json +20 -3
- package/blueprints/persistence-data-postgres/contributions/user-stories/persistence-data-postgres-us-27107.json +20 -3
- package/blueprints/persistence-data-postgres/contributions/user-stories/persistence-data-postgres-us-27108.json +20 -3
- package/blueprints/persistence-data-postgres/contributions/user-stories/persistence-data-postgres-us-27109.json +20 -3
- package/blueprints/persistence-data-postgres/contributions/user-stories/persistence-data-postgres-us-27110.json +48 -3
- package/blueprints/persistence-data-postgres/docs/topics.md +1 -1
- package/blueprints/persistence-data-sqlite/CHANGELOG.md +28 -0
- package/blueprints/persistence-data-sqlite/README.md +2 -2
- package/blueprints/persistence-data-sqlite/blueprint.json +148 -31
- 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/contributions/requirements/persistence-data-sqlite-req-001.json +5 -1
- package/blueprints/persistence-data-sqlite/contributions/requirements/persistence-data-sqlite-req-002.json +5 -1
- package/blueprints/persistence-data-sqlite/contributions/requirements/persistence-data-sqlite-req-003.json +5 -1
- package/blueprints/persistence-data-sqlite/contributions/requirements/persistence-data-sqlite-req-004.json +5 -1
- package/blueprints/persistence-data-sqlite/contributions/requirements/persistence-data-sqlite-req-005.json +5 -1
- package/blueprints/persistence-data-sqlite/contributions/requirements/persistence-data-sqlite-req-006.json +5 -1
- package/blueprints/persistence-data-sqlite/contributions/requirements/persistence-data-sqlite-req-007.json +5 -1
- package/blueprints/persistence-data-sqlite/contributions/requirements/persistence-data-sqlite-req-008.json +5 -1
- package/blueprints/persistence-data-sqlite/contributions/requirements/persistence-data-sqlite-req-009.json +5 -1
- package/blueprints/persistence-data-sqlite/contributions/requirements/persistence-data-sqlite-req-010.json +5 -1
- package/blueprints/persistence-data-sqlite/contributions/requirements/persistence-data-sqlite-req-011.json +5 -1
- package/blueprints/persistence-data-sqlite/contributions/user-stories/persistence-data-sqlite-us-5101.json +35 -4
- package/blueprints/persistence-data-sqlite/contributions/user-stories/persistence-data-sqlite-us-5102.json +7 -4
- package/blueprints/persistence-data-sqlite/contributions/user-stories/persistence-data-sqlite-us-5103.json +19 -3
- package/blueprints/persistence-data-sqlite/contributions/user-stories/persistence-data-sqlite-us-5104.json +21 -4
- package/blueprints/persistence-data-sqlite/contributions/user-stories/persistence-data-sqlite-us-5105.json +7 -4
- package/blueprints/persistence-data-sqlite/contributions/user-stories/persistence-data-sqlite-us-5106.json +11 -4
- package/blueprints/persistence-data-sqlite/contributions/user-stories/persistence-data-sqlite-us-5107.json +7 -4
- package/blueprints/persistence-data-sqlite/contributions/user-stories/persistence-data-sqlite-us-5108.json +7 -4
- package/blueprints/persistence-data-sqlite/contributions/user-stories/persistence-data-sqlite-us-5109.json +11 -8
- package/blueprints/persistence-data-sqlite/contributions/user-stories/persistence-data-sqlite-us-5110.json +23 -3
- package/blueprints/persistence-data-sqlite/contributions/user-stories/persistence-data-sqlite-us-5111.json +19 -3
- package/blueprints/persistence-data-sqlite/docs/topics.md +2 -3
- package/blueprints/persistence-data-sqlite/guide/persistence-data-sqlite.md +1 -1
- package/blueprints/platform-cloudflare-cron-triggers/CHANGELOG.md +40 -2
- package/blueprints/platform-cloudflare-cron-triggers/README.md +2 -3
- package/blueprints/platform-cloudflare-cron-triggers/blueprint.json +78 -17
- package/blueprints/platform-cloudflare-cron-triggers/contributions/adrs/adr-3301-platform-cloudflare-cron-triggers-scheduled-trigger-contract.json +2 -2
- package/blueprints/platform-cloudflare-cron-triggers/contributions/probes/real-account-scheduled-smoke.mjs +24 -3
- package/blueprints/platform-cloudflare-cron-triggers/contributions/probes/skew-tolerance.mjs +1 -1
- package/blueprints/platform-cloudflare-cron-triggers/contributions/requirements/platform-cloudflare-cron-triggers-req-001.json +6 -2
- package/blueprints/platform-cloudflare-cron-triggers/contributions/requirements/platform-cloudflare-cron-triggers-req-002.json +5 -1
- package/blueprints/platform-cloudflare-cron-triggers/contributions/requirements/platform-cloudflare-cron-triggers-req-003.json +5 -1
- package/blueprints/platform-cloudflare-cron-triggers/contributions/requirements/platform-cloudflare-cron-triggers-req-004.json +6 -2
- package/blueprints/platform-cloudflare-cron-triggers/contributions/tacs/tac-3301-platform-cloudflare-cron-triggers-scheduled-handler.json +1 -1
- package/blueprints/platform-cloudflare-cron-triggers/contributions/user-stories/platform-cloudflare-cron-triggers-us-32101.json +86 -5
- package/blueprints/platform-cloudflare-cron-triggers/contributions/user-stories/platform-cloudflare-cron-triggers-us-32102.json +69 -5
- package/blueprints/platform-cloudflare-cron-triggers/contributions/user-stories/platform-cloudflare-cron-triggers-us-32103.json +51 -4
- package/blueprints/platform-cloudflare-cron-triggers/contributions/user-stories/platform-cloudflare-cron-triggers-us-32104.json +65 -4
- package/blueprints/platform-cloudflare-cron-triggers/contributions/user-stories/platform-cloudflare-cron-triggers-us-32105.json +68 -5
- package/blueprints/platform-cloudflare-cron-triggers/contributions/user-stories/platform-cloudflare-cron-triggers-us-32106.json +62 -3
- package/blueprints/platform-cloudflare-cron-triggers/contributions/user-stories/platform-cloudflare-cron-triggers-us-32107.json +56 -3
- package/blueprints/platform-cloudflare-cron-triggers/docs/topics.md +4 -4
- package/blueprints/platform-cloudflare-durable-objects/CHANGELOG.md +40 -4
- package/blueprints/platform-cloudflare-durable-objects/README.md +6 -6
- package/blueprints/platform-cloudflare-durable-objects/blueprint.json +3 -2
- package/blueprints/platform-cloudflare-durable-objects/contributions/adrs/adr-3401-platform-cloudflare-durable-objects-single-cell-contract.json +1 -1
- package/blueprints/platform-cloudflare-durable-objects/contributions/adrs/adr-3402-platform-cloudflare-durable-objects-websocket-hub-contract.json +1 -1
- package/blueprints/platform-cloudflare-durable-objects/contributions/probes/probe-utils.mjs +2 -2
- package/blueprints/platform-cloudflare-durable-objects/contributions/probes/real-account-storage-smoke.mjs +41 -35
- package/blueprints/platform-cloudflare-durable-objects/contributions/probes/sole-reader-scan.mjs +1 -1
- package/blueprints/platform-cloudflare-durable-objects/contributions/probes/storage-round-trip.mjs +1 -1
- package/blueprints/platform-cloudflare-durable-objects/contributions/probes/websocket-hub-broadcast.mjs +1 -1
- package/blueprints/platform-cloudflare-durable-objects/contributions/probes/wrangler-seam.mjs +11 -5
- package/blueprints/platform-cloudflare-durable-objects/contributions/requirements/platform-cloudflare-durable-objects-req-001.json +5 -1
- package/blueprints/platform-cloudflare-durable-objects/contributions/requirements/platform-cloudflare-durable-objects-req-002.json +6 -2
- package/blueprints/platform-cloudflare-durable-objects/contributions/requirements/platform-cloudflare-durable-objects-req-003.json +5 -1
- package/blueprints/platform-cloudflare-durable-objects/contributions/requirements/platform-cloudflare-durable-objects-req-004.json +5 -1
- package/blueprints/platform-cloudflare-durable-objects/contributions/requirements/platform-cloudflare-durable-objects-req-005.json +6 -2
- package/blueprints/platform-cloudflare-durable-objects/contributions/requirements/platform-cloudflare-durable-objects-req-006.json +6 -2
- package/blueprints/platform-cloudflare-durable-objects/contributions/requirements/platform-cloudflare-durable-objects-req-007.json +5 -1
- package/blueprints/platform-cloudflare-durable-objects/contributions/requirements/platform-cloudflare-durable-objects-req-008.json +5 -1
- package/blueprints/platform-cloudflare-durable-objects/contributions/user-stories/platform-cloudflare-durable-objects-us-33101.json +73 -2
- package/blueprints/platform-cloudflare-durable-objects/contributions/user-stories/platform-cloudflare-durable-objects-us-33102.json +59 -2
- package/blueprints/platform-cloudflare-durable-objects/contributions/user-stories/platform-cloudflare-durable-objects-us-33103.json +77 -2
- package/blueprints/platform-cloudflare-durable-objects/contributions/user-stories/platform-cloudflare-durable-objects-us-33104.json +75 -6
- package/blueprints/platform-cloudflare-durable-objects/contributions/user-stories/platform-cloudflare-durable-objects-us-33105.json +73 -2
- package/blueprints/platform-cloudflare-durable-objects/contributions/user-stories/platform-cloudflare-durable-objects-us-33106.json +49 -2
- package/blueprints/platform-cloudflare-durable-objects/contributions/user-stories/platform-cloudflare-durable-objects-us-33107.json +45 -2
- package/blueprints/platform-cloudflare-durable-objects/contributions/user-stories/platform-cloudflare-durable-objects-us-33108.json +84 -3
- package/blueprints/platform-cloudflare-durable-objects/contributions/user-stories/platform-cloudflare-durable-objects-us-33109.json +45 -2
- package/blueprints/platform-cloudflare-durable-objects/contributions/user-stories/platform-cloudflare-durable-objects-us-33110.json +59 -2
- package/blueprints/platform-cloudflare-durable-objects/contributions/user-stories/platform-cloudflare-durable-objects-us-33111.json +45 -2
- package/blueprints/platform-cloudflare-durable-objects/contributions/user-stories/platform-cloudflare-durable-objects-us-33112.json +53 -2
- package/blueprints/platform-cloudflare-durable-objects/contributions/user-stories/platform-cloudflare-durable-objects-us-33113.json +68 -5
- package/blueprints/platform-cloudflare-durable-objects/docs/topics.md +2 -2
- package/blueprints/platform-cloudflare-durable-objects/guide/platform-cloudflare-durable-objects.md +9 -9
- package/blueprints/platform-cloudflare-kv/CHANGELOG.md +58 -12
- package/blueprints/platform-cloudflare-kv/README.md +7 -11
- package/blueprints/platform-cloudflare-kv/blueprint.json +115 -20
- package/blueprints/platform-cloudflare-kv/contributions/adrs/adr-3201-platform-cloudflare-kv-key-value-store-contract.json +3 -3
- package/blueprints/platform-cloudflare-kv/contributions/probes/cache-aside-hit-then-miss.mjs +1 -1
- package/blueprints/platform-cloudflare-kv/contributions/probes/event-secrecy.mjs +1 -1
- package/blueprints/platform-cloudflare-kv/contributions/probes/real-account-eventual-consistency-smoke.mjs +53 -18
- package/blueprints/platform-cloudflare-kv/contributions/requirements/platform-cloudflare-kv-req-001.json +6 -2
- package/blueprints/platform-cloudflare-kv/contributions/requirements/platform-cloudflare-kv-req-002.json +5 -1
- package/blueprints/platform-cloudflare-kv/contributions/requirements/platform-cloudflare-kv-req-003.json +5 -1
- package/blueprints/platform-cloudflare-kv/contributions/requirements/platform-cloudflare-kv-req-004.json +6 -2
- package/blueprints/platform-cloudflare-kv/contributions/requirements/platform-cloudflare-kv-req-005.json +7 -3
- package/blueprints/platform-cloudflare-kv/contributions/requirements/platform-cloudflare-kv-req-006.json +22 -0
- package/blueprints/platform-cloudflare-kv/contributions/requirements/platform-cloudflare-kv-req-007.json +22 -0
- package/blueprints/platform-cloudflare-kv/contributions/user-stories/platform-cloudflare-kv-us-31101.json +59 -2
- package/blueprints/platform-cloudflare-kv/contributions/user-stories/platform-cloudflare-kv-us-31102.json +45 -2
- package/blueprints/platform-cloudflare-kv/contributions/user-stories/platform-cloudflare-kv-us-31103.json +73 -3
- package/blueprints/platform-cloudflare-kv/contributions/user-stories/platform-cloudflare-kv-us-31104.json +67 -2
- package/blueprints/platform-cloudflare-kv/contributions/user-stories/platform-cloudflare-kv-us-31105.json +59 -2
- package/blueprints/platform-cloudflare-kv/contributions/user-stories/platform-cloudflare-kv-us-31106.json +45 -2
- package/blueprints/platform-cloudflare-kv/contributions/user-stories/platform-cloudflare-kv-us-31107.json +45 -2
- package/blueprints/platform-cloudflare-kv/contributions/user-stories/platform-cloudflare-kv-us-31108.json +45 -2
- package/blueprints/platform-cloudflare-kv/contributions/user-stories/platform-cloudflare-kv-us-31109.json +92 -0
- package/blueprints/platform-cloudflare-kv/contributions/user-stories/platform-cloudflare-kv-us-31110.json +88 -0
- package/blueprints/platform-cloudflare-kv/contributions/user-stories/platform-cloudflare-kv-us-31111.json +89 -0
- package/blueprints/platform-cloudflare-kv/docs/topics.md +2 -2
- package/blueprints/platform-cloudflare-kv/guide/platform-cloudflare-kv.md +2 -2
- package/blueprints/platform-docker-compose-host/CHANGELOG.md +124 -3
- package/blueprints/platform-docker-compose-host/README.md +7 -7
- package/blueprints/platform-docker-compose-host/blueprint.json +23 -6
- package/blueprints/platform-docker-compose-host/contributions/adrs/adr-3901-platform-docker-compose-host-contract.json +3 -3
- package/blueprints/platform-docker-compose-host/contributions/adrs/adr-3902-platform-docker-compose-host-reverse-proxy.json +4 -4
- package/blueprints/platform-docker-compose-host/contributions/adrs/adr-3903-platform-docker-compose-host-reject-coolify.json +2 -2
- package/blueprints/platform-docker-compose-host/contributions/adrs/adr-3904-platform-docker-compose-host-log-driver.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 -25
- 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/contributions/requirements/platform-docker-compose-host-req-001.json +6 -2
- package/blueprints/platform-docker-compose-host/contributions/requirements/platform-docker-compose-host-req-002.json +5 -1
- package/blueprints/platform-docker-compose-host/contributions/requirements/platform-docker-compose-host-req-003.json +6 -2
- package/blueprints/platform-docker-compose-host/contributions/requirements/platform-docker-compose-host-req-004.json +5 -1
- package/blueprints/platform-docker-compose-host/contributions/requirements/platform-docker-compose-host-req-005.json +6 -2
- package/blueprints/platform-docker-compose-host/contributions/requirements/platform-docker-compose-host-req-006.json +6 -2
- package/blueprints/platform-docker-compose-host/contributions/requirements/platform-docker-compose-host-req-007.json +22 -0
- package/blueprints/platform-docker-compose-host/contributions/user-stories/platform-docker-compose-host-us-38101.json +73 -2
- package/blueprints/platform-docker-compose-host/contributions/user-stories/platform-docker-compose-host-us-38102.json +67 -2
- package/blueprints/platform-docker-compose-host/contributions/user-stories/platform-docker-compose-host-us-38103.json +59 -2
- package/blueprints/platform-docker-compose-host/contributions/user-stories/platform-docker-compose-host-us-38104.json +75 -2
- package/blueprints/platform-docker-compose-host/contributions/user-stories/platform-docker-compose-host-us-38105.json +49 -2
- package/blueprints/platform-docker-compose-host/contributions/user-stories/platform-docker-compose-host-us-38106.json +45 -2
- package/blueprints/platform-docker-compose-host/contributions/user-stories/platform-docker-compose-host-us-38107.json +49 -2
- package/blueprints/platform-docker-compose-host/contributions/user-stories/platform-docker-compose-host-us-38108.json +49 -2
- package/blueprints/platform-docker-compose-host/contributions/user-stories/platform-docker-compose-host-us-38109.json +57 -2
- package/blueprints/platform-docker-compose-host/contributions/user-stories/platform-docker-compose-host-us-38110.json +92 -0
- package/blueprints/platform-docker-compose-host/docs/topics.md +4 -4
- package/blueprints/platform-docker-compose-host/guide/platform-docker-compose-host.md +6 -6
- package/blueprints/security-auth-clerk/CHANGELOG.md +36 -4
- package/blueprints/security-auth-clerk/README.md +4 -4
- package/blueprints/security-auth-clerk/assets/wiring/workers-wrangler-toml-shape.md +1 -1
- package/blueprints/security-auth-clerk/blueprint.json +23 -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/contributions/requirements/security-auth-clerk-req-001.json +6 -2
- package/blueprints/security-auth-clerk/contributions/requirements/security-auth-clerk-req-002.json +5 -1
- package/blueprints/security-auth-clerk/contributions/requirements/security-auth-clerk-req-003.json +6 -2
- package/blueprints/security-auth-clerk/contributions/requirements/security-auth-clerk-req-004.json +6 -2
- package/blueprints/security-auth-clerk/contributions/requirements/security-auth-clerk-req-005.json +5 -2
- package/blueprints/security-auth-clerk/contributions/requirements/security-auth-clerk-req-006.json +5 -1
- package/blueprints/security-auth-clerk/contributions/requirements/security-auth-clerk-req-007.json +4 -1
- package/blueprints/security-auth-clerk/contributions/requirements/security-auth-clerk-req-008.json +4 -1
- package/blueprints/security-auth-clerk/contributions/requirements/security-auth-clerk-req-009.json +4 -1
- package/blueprints/security-auth-clerk/contributions/requirements/security-auth-clerk-req-010.json +22 -0
- package/blueprints/security-auth-clerk/contributions/requirements/security-auth-clerk-req-011.json +22 -0
- package/blueprints/security-auth-clerk/contributions/tacs/tac-1001-security-auth-clerk-middleware.json +14 -4
- package/blueprints/security-auth-clerk/contributions/tacs/tac-1003-security-auth-clerk-session-verifier.json +7 -1
- package/blueprints/security-auth-clerk/contributions/user-stories/security-auth-clerk-us-9101.json +6 -3
- package/blueprints/security-auth-clerk/contributions/user-stories/security-auth-clerk-us-9102.json +19 -3
- package/blueprints/security-auth-clerk/contributions/user-stories/security-auth-clerk-us-9103.json +6 -3
- package/blueprints/security-auth-clerk/contributions/user-stories/security-auth-clerk-us-9104.json +6 -3
- package/blueprints/security-auth-clerk/contributions/user-stories/security-auth-clerk-us-9105.json +4 -2
- package/blueprints/security-auth-clerk/contributions/user-stories/security-auth-clerk-us-9106.json +4 -2
- package/blueprints/security-auth-clerk/contributions/user-stories/security-auth-clerk-us-9107.json +4 -2
- package/blueprints/security-auth-clerk/contributions/user-stories/security-auth-clerk-us-9108.json +13 -3
- package/blueprints/security-auth-clerk/contributions/user-stories/security-auth-clerk-us-9109.json +8 -2
- package/blueprints/security-auth-clerk/contributions/user-stories/security-auth-clerk-us-9110.json +4 -2
- package/blueprints/security-auth-clerk/contributions/user-stories/security-auth-clerk-us-9111.json +4 -2
- package/blueprints/security-auth-clerk/contributions/user-stories/security-auth-clerk-us-9112.json +102 -0
- package/blueprints/security-auth-clerk/contributions/user-stories/security-auth-clerk-us-9113.json +103 -0
- package/blueprints/security-auth-clerk/docs/topics.md +2 -3
- package/blueprints/security-auth-keycloak/CHANGELOG.md +34 -4
- package/blueprints/security-auth-keycloak/README.md +3 -3
- package/blueprints/security-auth-keycloak/blueprint.json +103 -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/contributions/requirements/security-auth-keycloak-req-001.json +5 -2
- package/blueprints/security-auth-keycloak/contributions/requirements/security-auth-keycloak-req-002.json +5 -1
- package/blueprints/security-auth-keycloak/contributions/requirements/security-auth-keycloak-req-003.json +5 -1
- package/blueprints/security-auth-keycloak/contributions/requirements/security-auth-keycloak-req-004.json +5 -1
- package/blueprints/security-auth-keycloak/contributions/requirements/security-auth-keycloak-req-005.json +6 -2
- package/blueprints/security-auth-keycloak/contributions/requirements/security-auth-keycloak-req-006.json +6 -2
- package/blueprints/security-auth-keycloak/contributions/requirements/security-auth-keycloak-req-007.json +4 -1
- package/blueprints/security-auth-keycloak/contributions/requirements/security-auth-keycloak-req-008.json +4 -1
- package/blueprints/security-auth-keycloak/contributions/requirements/security-auth-keycloak-req-009.json +4 -1
- package/blueprints/security-auth-keycloak/contributions/requirements/security-auth-keycloak-req-010.json +4 -1
- package/blueprints/security-auth-keycloak/contributions/requirements/security-auth-keycloak-req-011.json +5 -1
- package/blueprints/security-auth-keycloak/contributions/requirements/security-auth-keycloak-req-012.json +4 -1
- package/blueprints/security-auth-keycloak/contributions/requirements/security-auth-keycloak-req-013.json +22 -0
- package/blueprints/security-auth-keycloak/contributions/requirements/security-auth-keycloak-req-014.json +22 -0
- package/blueprints/security-auth-keycloak/contributions/requirements/security-auth-keycloak-req-015.json +22 -0
- package/blueprints/security-auth-keycloak/contributions/requirements/security-auth-keycloak-req-016.json +22 -0
- package/blueprints/security-auth-keycloak/contributions/requirements/security-auth-keycloak-req-017.json +22 -0
- package/blueprints/security-auth-keycloak/contributions/requirements/security-auth-keycloak-req-018.json +22 -0
- package/blueprints/security-auth-keycloak/contributions/requirements/security-auth-keycloak-req-019.json +22 -0
- package/blueprints/security-auth-keycloak/contributions/tacs/tac-1201-security-auth-keycloak-discovery-client.json +4 -2
- package/blueprints/security-auth-keycloak/contributions/tacs/tac-1202-security-auth-keycloak-jwt-verifier.json +8 -2
- package/blueprints/security-auth-keycloak/contributions/tacs/tac-1203-security-auth-keycloak-introspection-client.json +8 -2
- package/blueprints/security-auth-keycloak/contributions/tacs/tac-1204-security-auth-keycloak-provider-router.json +3 -1
- package/blueprints/security-auth-keycloak/contributions/tacs/tac-1205-security-auth-keycloak-role-adapter.json +2 -1
- package/blueprints/security-auth-keycloak/contributions/user-stories/security-auth-keycloak-us-11101.json +6 -3
- package/blueprints/security-auth-keycloak/contributions/user-stories/security-auth-keycloak-us-11102.json +10 -3
- package/blueprints/security-auth-keycloak/contributions/user-stories/security-auth-keycloak-us-11103.json +12 -2
- package/blueprints/security-auth-keycloak/contributions/user-stories/security-auth-keycloak-us-11104.json +8 -2
- package/blueprints/security-auth-keycloak/contributions/user-stories/security-auth-keycloak-us-11105.json +6 -3
- package/blueprints/security-auth-keycloak/contributions/user-stories/security-auth-keycloak-us-11106.json +18 -3
- package/blueprints/security-auth-keycloak/contributions/user-stories/security-auth-keycloak-us-11107.json +6 -3
- package/blueprints/security-auth-keycloak/contributions/user-stories/security-auth-keycloak-us-11108.json +6 -3
- package/blueprints/security-auth-keycloak/contributions/user-stories/security-auth-keycloak-us-11109.json +4 -2
- package/blueprints/security-auth-keycloak/contributions/user-stories/security-auth-keycloak-us-11110.json +6 -3
- package/blueprints/security-auth-keycloak/contributions/user-stories/security-auth-keycloak-us-11111.json +14 -3
- package/blueprints/security-auth-keycloak/contributions/user-stories/security-auth-keycloak-us-11112.json +4 -2
- package/blueprints/security-auth-keycloak/contributions/user-stories/security-auth-keycloak-us-11113.json +4 -2
- package/blueprints/security-auth-keycloak/contributions/user-stories/security-auth-keycloak-us-11114.json +72 -0
- package/blueprints/security-auth-keycloak/contributions/user-stories/security-auth-keycloak-us-11115.json +88 -0
- package/blueprints/security-auth-keycloak/contributions/user-stories/security-auth-keycloak-us-11116.json +117 -0
- package/blueprints/security-auth-keycloak/contributions/user-stories/security-auth-keycloak-us-11117.json +117 -0
- package/blueprints/security-auth-keycloak/contributions/user-stories/security-auth-keycloak-us-11118.json +117 -0
- package/blueprints/security-auth-keycloak/contributions/user-stories/security-auth-keycloak-us-11119.json +117 -0
- package/blueprints/security-auth-keycloak/contributions/user-stories/security-auth-keycloak-us-11120.json +103 -0
- package/blueprints/security-auth-keycloak/docs/topics.md +1 -2
- package/blueprints/security-auth-keycloak/guide/security-auth-keycloak.md +1 -1
- package/blueprints/security-auth-magic-link/CHANGELOG.md +30 -3
- package/blueprints/security-auth-magic-link/README.md +3 -3
- 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/contributions/requirements/security-auth-magic-link-req-001.json +4 -1
- package/blueprints/security-auth-magic-link/contributions/requirements/security-auth-magic-link-req-002.json +5 -1
- package/blueprints/security-auth-magic-link/contributions/requirements/security-auth-magic-link-req-003.json +6 -2
- package/blueprints/security-auth-magic-link/contributions/requirements/security-auth-magic-link-req-004.json +5 -1
- package/blueprints/security-auth-magic-link/contributions/requirements/security-auth-magic-link-req-005.json +5 -1
- package/blueprints/security-auth-magic-link/contributions/requirements/security-auth-magic-link-req-006.json +4 -1
- package/blueprints/security-auth-magic-link/contributions/requirements/security-auth-magic-link-req-007.json +4 -1
- package/blueprints/security-auth-magic-link/contributions/requirements/security-auth-magic-link-req-008.json +5 -1
- package/blueprints/security-auth-magic-link/contributions/requirements/security-auth-magic-link-req-009.json +5 -1
- package/blueprints/security-auth-magic-link/contributions/requirements/security-auth-magic-link-req-010.json +6 -2
- package/blueprints/security-auth-magic-link/contributions/requirements/security-auth-magic-link-req-011.json +6 -2
- package/blueprints/security-auth-magic-link/contributions/user-stories/security-auth-magic-link-us-3101.json +10 -5
- package/blueprints/security-auth-magic-link/contributions/user-stories/security-auth-magic-link-us-3102.json +8 -4
- package/blueprints/security-auth-magic-link/contributions/user-stories/security-auth-magic-link-us-3103.json +6 -3
- package/blueprints/security-auth-magic-link/contributions/user-stories/security-auth-magic-link-us-3104.json +8 -4
- package/blueprints/security-auth-magic-link/contributions/user-stories/security-auth-magic-link-us-3105.json +6 -3
- package/blueprints/security-auth-magic-link/contributions/user-stories/security-auth-magic-link-us-3106.json +6 -3
- package/blueprints/security-auth-magic-link/contributions/user-stories/security-auth-magic-link-us-3107.json +8 -4
- package/blueprints/security-auth-magic-link/contributions/user-stories/security-auth-magic-link-us-3108.json +6 -3
- package/blueprints/security-auth-magic-link/contributions/user-stories/security-auth-magic-link-us-3109.json +6 -3
- package/blueprints/security-auth-magic-link/contributions/user-stories/security-auth-magic-link-us-3110.json +6 -3
- package/blueprints/security-auth-magic-link/contributions/user-stories/security-auth-magic-link-us-3111.json +14 -3
- package/blueprints/security-auth-magic-link/docs/topics.md +1 -1
- package/blueprints/security-auth-magic-link/guide/security-auth-magic-link.md +1 -1
- package/blueprints/security-auth-oauth2/CHANGELOG.md +32 -4
- package/blueprints/security-auth-oauth2/README.md +3 -3
- package/blueprints/security-auth-oauth2/blueprint.json +35 -3
- 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/contributions/requirements/security-auth-oauth2-req-001.json +5 -2
- package/blueprints/security-auth-oauth2/contributions/requirements/security-auth-oauth2-req-002.json +5 -1
- package/blueprints/security-auth-oauth2/contributions/requirements/security-auth-oauth2-req-003.json +5 -1
- package/blueprints/security-auth-oauth2/contributions/requirements/security-auth-oauth2-req-004.json +4 -1
- package/blueprints/security-auth-oauth2/contributions/requirements/security-auth-oauth2-req-005.json +5 -1
- package/blueprints/security-auth-oauth2/contributions/requirements/security-auth-oauth2-req-006.json +6 -2
- package/blueprints/security-auth-oauth2/contributions/requirements/security-auth-oauth2-req-007.json +4 -1
- package/blueprints/security-auth-oauth2/contributions/requirements/security-auth-oauth2-req-008.json +6 -2
- package/blueprints/security-auth-oauth2/contributions/requirements/security-auth-oauth2-req-009.json +5 -1
- package/blueprints/security-auth-oauth2/contributions/requirements/security-auth-oauth2-req-010.json +4 -1
- package/blueprints/security-auth-oauth2/contributions/requirements/security-auth-oauth2-req-011.json +22 -0
- package/blueprints/security-auth-oauth2/contributions/requirements/security-auth-oauth2-req-012.json +22 -0
- package/blueprints/security-auth-oauth2/contributions/requirements/security-auth-oauth2-req-013.json +22 -0
- package/blueprints/security-auth-oauth2/contributions/tacs/tac-1102-security-auth-oauth2-provider-adapter.json +2 -1
- package/blueprints/security-auth-oauth2/contributions/tacs/tac-1103-security-auth-oauth2-session-bridge.json +9 -2
- package/blueprints/security-auth-oauth2/contributions/user-stories/security-auth-oauth2-us-10101.json +6 -3
- package/blueprints/security-auth-oauth2/contributions/user-stories/security-auth-oauth2-us-10102.json +6 -3
- package/blueprints/security-auth-oauth2/contributions/user-stories/security-auth-oauth2-us-10103.json +4 -2
- package/blueprints/security-auth-oauth2/contributions/user-stories/security-auth-oauth2-us-10104.json +4 -2
- package/blueprints/security-auth-oauth2/contributions/user-stories/security-auth-oauth2-us-10105.json +8 -4
- package/blueprints/security-auth-oauth2/contributions/user-stories/security-auth-oauth2-us-10106.json +6 -3
- package/blueprints/security-auth-oauth2/contributions/user-stories/security-auth-oauth2-us-10107.json +6 -3
- package/blueprints/security-auth-oauth2/contributions/user-stories/security-auth-oauth2-us-10108.json +6 -3
- package/blueprints/security-auth-oauth2/contributions/user-stories/security-auth-oauth2-us-10109.json +4 -2
- package/blueprints/security-auth-oauth2/contributions/user-stories/security-auth-oauth2-us-10110.json +4 -2
- package/blueprints/security-auth-oauth2/contributions/user-stories/security-auth-oauth2-us-10111.json +17 -2
- package/blueprints/security-auth-oauth2/contributions/user-stories/security-auth-oauth2-us-10112.json +82 -0
- package/blueprints/security-auth-oauth2/contributions/user-stories/security-auth-oauth2-us-10113.json +68 -0
- package/blueprints/security-auth-oauth2/contributions/user-stories/security-auth-oauth2-us-10114.json +88 -0
- package/blueprints/security-auth-oauth2/docs/topics.md +1 -2
- package/blueprints/security-secrets-management/CHANGELOG.md +26 -3
- package/blueprints/security-secrets-management/README.md +2 -2
- package/blueprints/security-secrets-management/blueprint.json +170 -32
- 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/contributions/requirements/security-secrets-management-req-001.json +5 -1
- package/blueprints/security-secrets-management/contributions/requirements/security-secrets-management-req-002.json +6 -2
- package/blueprints/security-secrets-management/contributions/requirements/security-secrets-management-req-003.json +6 -2
- package/blueprints/security-secrets-management/contributions/requirements/security-secrets-management-req-004.json +5 -1
- package/blueprints/security-secrets-management/contributions/requirements/security-secrets-management-req-005.json +6 -2
- package/blueprints/security-secrets-management/contributions/requirements/security-secrets-management-req-006.json +5 -1
- package/blueprints/security-secrets-management/contributions/requirements/security-secrets-management-req-007.json +5 -1
- package/blueprints/security-secrets-management/contributions/requirements/security-secrets-management-req-008.json +5 -1
- package/blueprints/security-secrets-management/contributions/requirements/security-secrets-management-req-009.json +5 -1
- package/blueprints/security-secrets-management/contributions/requirements/security-secrets-management-req-010.json +6 -3
- package/blueprints/security-secrets-management/contributions/user-stories/security-secrets-management-us-8101.json +6 -3
- package/blueprints/security-secrets-management/contributions/user-stories/security-secrets-management-us-8102.json +6 -3
- package/blueprints/security-secrets-management/contributions/user-stories/security-secrets-management-us-8103.json +4 -2
- package/blueprints/security-secrets-management/contributions/user-stories/security-secrets-management-us-8104.json +6 -3
- package/blueprints/security-secrets-management/contributions/user-stories/security-secrets-management-us-8105.json +8 -4
- package/blueprints/security-secrets-management/contributions/user-stories/security-secrets-management-us-8106.json +6 -3
- package/blueprints/security-secrets-management/contributions/user-stories/security-secrets-management-us-8107.json +6 -3
- package/blueprints/security-secrets-management/contributions/user-stories/security-secrets-management-us-8108.json +6 -3
- package/blueprints/security-secrets-management/contributions/user-stories/security-secrets-management-us-8109.json +6 -3
- package/blueprints/security-secrets-management/contributions/user-stories/security-secrets-management-us-8110.json +6 -3
- 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-050.json +1 -1
- package/rcf/test-suites/ts-052.json +1 -1
- package/rcf/test-suites/ts-053.json +2 -2
- package/rcf/test-suites/ts-054.json +2 -2
- package/rcf/test-suites/ts-055.json +2 -2
- package/rcf/test-suites/ts-056.json +4 -4
- package/rcf/test-suites/ts-057.json +2 -2
- 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/rcf/user-stories/us-7701.json +3 -3
- package/releases/releases.yaml +21 -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/cli/view.js +22 -11
- 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,2204 @@
|
|
|
1
|
+
// `rcf feedback` core verb (TAC-4101). Slice 2 (FBS-181) adds the
|
|
2
|
+
// `preview` sub-verb on top of slice 1's capture and store:
|
|
3
|
+
// add record one finding (silent, local; no network)
|
|
4
|
+
// list print pending entries (--all includes every state; --json)
|
|
5
|
+
// status counts + gh availability (gh probing lands in slice 4;
|
|
6
|
+
// slice 2 still reports the local-only summary)
|
|
7
|
+
// defer mark all pending entries deferredUntilSession
|
|
8
|
+
// discard mark named (or --all) entries discarded
|
|
9
|
+
// preview render the exact issue title, body and redaction ledger
|
|
10
|
+
// for every pending entry; read-only, no network
|
|
11
|
+
//
|
|
12
|
+
// Sub-verbs from later slices are registered here as "not yet available"
|
|
13
|
+
// stubs so `rcf feedback submit|opt-in|opt-out|hook` return the
|
|
14
|
+
// documented usage-plus-outcome exit code (3) with a one-line note
|
|
15
|
+
// naming the slice that ships them. This keeps the RULE 17 block
|
|
16
|
+
// referable at slice-2 time without inventing verb behaviour ahead of
|
|
17
|
+
// the ACs. Sub-verb argv parsing lives in each handler so each verb's
|
|
18
|
+
// flag surface is local.
|
|
19
|
+
//
|
|
20
|
+
// The verb is CORE (not grouped), because it spans discover-to-audit
|
|
21
|
+
// scope and is invoked from harness hooks (design §3.1). See
|
|
22
|
+
// `bin/rcf.js:CORE`.
|
|
23
|
+
|
|
24
|
+
import { readFile, realpath } from 'node:fs/promises';
|
|
25
|
+
import { dirname, resolve } from 'node:path';
|
|
26
|
+
import { platform as osPlatform } from 'node:os';
|
|
27
|
+
import { fileURLToPath } from 'node:url';
|
|
28
|
+
import { parseArgs } from 'node:util';
|
|
29
|
+
import { execFile } from 'node:child_process';
|
|
30
|
+
import { promisify } from 'node:util';
|
|
31
|
+
import process from 'node:process';
|
|
32
|
+
|
|
33
|
+
const execFileP = promisify(execFile);
|
|
34
|
+
|
|
35
|
+
import { findProjectRoot } from '../view/index.js';
|
|
36
|
+
import {
|
|
37
|
+
appendEntry,
|
|
38
|
+
appendState,
|
|
39
|
+
ensureGitignore,
|
|
40
|
+
mintUniqueEntryId,
|
|
41
|
+
newEntryId,
|
|
42
|
+
readAskLedger,
|
|
43
|
+
readDiscardTimestamps,
|
|
44
|
+
readEntries,
|
|
45
|
+
readFeedbackSettings,
|
|
46
|
+
storeExists,
|
|
47
|
+
writeAskLedger,
|
|
48
|
+
writeFeedbackSettings,
|
|
49
|
+
} from '../feedback/store.js';
|
|
50
|
+
import {
|
|
51
|
+
buildAskReason,
|
|
52
|
+
buildCarryOverLine,
|
|
53
|
+
emit as emitHook,
|
|
54
|
+
emitSessionStart,
|
|
55
|
+
shouldAsk,
|
|
56
|
+
} from '../feedback/hook.js';
|
|
57
|
+
import { redact, allowedHosts, findResidualSecrets } from '../feedback/redact.js';
|
|
58
|
+
import { fingerprint } from '../feedback/fingerprint.js';
|
|
59
|
+
import { renderIssue, renderComment, renderBundle } from '../feedback/render.js';
|
|
60
|
+
import { resolve as resolveDestination, listUnresolvedLibraries, findBlueprintRecord } from '../feedback/destination.js';
|
|
61
|
+
import { readLibraryRegistry } from '../blueprint/library-registry.js';
|
|
62
|
+
import { loadGhAdapter } from '../feedback/gh.js';
|
|
63
|
+
import { labelsForEntry } from '../feedback/labels.js';
|
|
64
|
+
import { outboxDir } from '../feedback/store.js';
|
|
65
|
+
import { mkdir, readdir, writeFile } from 'node:fs/promises';
|
|
66
|
+
|
|
67
|
+
const here = dirname(fileURLToPath(import.meta.url));
|
|
68
|
+
const PACKAGE_ROOT = resolve(here, '..', '..');
|
|
69
|
+
|
|
70
|
+
/** Closed enum from design §6. Any other value on --class exits 2. */
|
|
71
|
+
export const SYMPTOM_CLASSES = Object.freeze([
|
|
72
|
+
'docs-mismatch',
|
|
73
|
+
'validate-fails',
|
|
74
|
+
'apply-fails',
|
|
75
|
+
'internal-contradiction',
|
|
76
|
+
'stale-citation',
|
|
77
|
+
'missing-scenario',
|
|
78
|
+
'verb-error',
|
|
79
|
+
'verb-hang',
|
|
80
|
+
'wrong-output',
|
|
81
|
+
'other',
|
|
82
|
+
]);
|
|
83
|
+
|
|
84
|
+
/** Severity enum (design §3.1). */
|
|
85
|
+
export const SEVERITIES = Object.freeze(['blocker', 'major', 'minor']);
|
|
86
|
+
|
|
87
|
+
/** Kind enum. */
|
|
88
|
+
export const KINDS = Object.freeze(['blueprint', 'core']);
|
|
89
|
+
|
|
90
|
+
/** Body size cap (bytes, design §5 rule 7). */
|
|
91
|
+
export const BODY_CAP_BYTES = 8 * 1024;
|
|
92
|
+
|
|
93
|
+
/** Title char cap (design §3.1). */
|
|
94
|
+
export const TITLE_CAP_CHARS = 120;
|
|
95
|
+
|
|
96
|
+
export const HELP = `Usage: rcf feedback <sub-verb> [options]
|
|
97
|
+
|
|
98
|
+
Sub-verbs (available):
|
|
99
|
+
add Record one finding to the local log (no network, no ask).
|
|
100
|
+
list Print pending entries (--all includes every state, --json).
|
|
101
|
+
status Counts, opt-out state, gh availability summary.
|
|
102
|
+
defer Mark all pending entries deferred for the current session.
|
|
103
|
+
discard Mark named entries discarded (or --all).
|
|
104
|
+
preview Render the exact issue text and redaction ledger for each
|
|
105
|
+
pending entry; read-only, no network.
|
|
106
|
+
submit File each pending entry under the reporter's ambient gh
|
|
107
|
+
login; --yes is required. Runs preflight (gh, auth, repo
|
|
108
|
+
access, issues-enabled), a fingerprint dedupe search, then
|
|
109
|
+
either creates the issue, comments on a match, or writes
|
|
110
|
+
a bundle to .rcf/feedback/outbox/ and prints the paste
|
|
111
|
+
URL. See docs/feedback.md for the full walk.
|
|
112
|
+
opt-out Silence the per-session ask for this project by writing
|
|
113
|
+
rcf/feedback-settings.json:ask false. add / preview /
|
|
114
|
+
submit keep working (hand-driven flow).
|
|
115
|
+
opt-in Restore the ask (writes rcf/feedback-settings.json:ask true).
|
|
116
|
+
hook Harness hook handler (Stop / SessionEnd / SessionStart).
|
|
117
|
+
Reads harness JSON from stdin; applies the quiet rule
|
|
118
|
+
(design 3.5); on Claude Code, Stop exits 2 with the ask
|
|
119
|
+
on stderr; on Codex, stdout carries the block JSON.
|
|
120
|
+
Sub-shape: rcf feedback hook <stop|session-end|session-start>
|
|
121
|
+
[--harness claude-code|codex].
|
|
122
|
+
|
|
123
|
+
Common options:
|
|
124
|
+
--help Print this help.
|
|
125
|
+
--json Machine-readable output (list, status).
|
|
126
|
+
|
|
127
|
+
'rcf feedback add' options (all required unless noted):
|
|
128
|
+
--kind blueprint|core What the finding is about.
|
|
129
|
+
--target <ref> Blueprint slug, prefix:slug or verb path.
|
|
130
|
+
--anchor <id> AC / REQ / TAC / ADR id, or verb name.
|
|
131
|
+
Optional but strongly recommended for
|
|
132
|
+
dedupe folding.
|
|
133
|
+
--class <symptom-class> One of ${SYMPTOM_CLASSES.join(', ')}.
|
|
134
|
+
--severity blocker|major|minor
|
|
135
|
+
--title <text> <= ${TITLE_CAP_CHARS} chars.
|
|
136
|
+
--body <text> | --body-file <path>
|
|
137
|
+
Body markdown, <= ${BODY_CAP_BYTES / 1024} KB
|
|
138
|
+
after UTF-8 encoding.
|
|
139
|
+
--evidence <pointer> Repeatable: a command, a path:line
|
|
140
|
+
inside the project, or an id.
|
|
141
|
+
--harness claude-code|codex|other
|
|
142
|
+
Optional; inferred from env when absent.
|
|
143
|
+
--ask-now Blocker shortcut; flags the batch so the
|
|
144
|
+
next Stop hook asks regardless of the
|
|
145
|
+
15-minute quiet rule (slice 5).
|
|
146
|
+
--force Bypass the .gitignore pre-write refusal.
|
|
147
|
+
|
|
148
|
+
Exit codes:
|
|
149
|
+
0 success
|
|
150
|
+
2 usage error (bad flags, unknown enum, oversize body, no ignore
|
|
151
|
+
coverage without --force)
|
|
152
|
+
3 add: --kind blueprint AND the target is absent from
|
|
153
|
+
rcf/manifest.json:blueprints[] (unknown target). A known target
|
|
154
|
+
whose registered library has no resolvable feedback destination
|
|
155
|
+
is exit 0 with the entry stamped destination:unresolved; submit
|
|
156
|
+
writes a bundle at that entry's slot.
|
|
157
|
+
submit / preview: at least one entry stayed pending because of a
|
|
158
|
+
residual-secret refusal after redaction.
|
|
159
|
+
`;
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Core-verb entry point. Signature matches the other CORE handlers
|
|
163
|
+
* dispatched from `bin/rcf.js:CORE`.
|
|
164
|
+
*
|
|
165
|
+
* @param {string[]} argv - argv slice after `feedback`
|
|
166
|
+
* @param {object} [deps]
|
|
167
|
+
* @param {NodeJS.WritableStream} [deps.stdout]
|
|
168
|
+
* @param {NodeJS.WritableStream} [deps.stderr]
|
|
169
|
+
* @param {string} [deps.cwd]
|
|
170
|
+
* @param {NodeJS.ProcessEnv} [deps.env]
|
|
171
|
+
* @param {() => Date} [deps.now]
|
|
172
|
+
* @param {() => number} [deps.rng]
|
|
173
|
+
* @param {string} [deps.sessionId]
|
|
174
|
+
* @returns {Promise<number>}
|
|
175
|
+
*/
|
|
176
|
+
export async function main(argv, deps = {}) {
|
|
177
|
+
const stdout = deps.stdout ?? process.stdout;
|
|
178
|
+
const stderr = deps.stderr ?? process.stderr;
|
|
179
|
+
const cwd = deps.cwd ?? process.cwd();
|
|
180
|
+
const env = deps.env ?? process.env;
|
|
181
|
+
const now = deps.now ?? (() => new Date());
|
|
182
|
+
const rng = deps.rng ?? Math.random;
|
|
183
|
+
const sessionId = deps.sessionId ?? env.RCF_FEEDBACK_SESSION_ID ?? 'unknown';
|
|
184
|
+
|
|
185
|
+
if (argv.length === 0 || argv[0] === '--help' || argv[0] === '-h') {
|
|
186
|
+
stdout.write(HELP);
|
|
187
|
+
return argv.length === 0 ? 2 : 0;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
const sub = argv[0];
|
|
191
|
+
const rest = argv.slice(1);
|
|
192
|
+
const ctx = { stdout, stderr, cwd, env, now, rng, sessionId };
|
|
193
|
+
switch (sub) {
|
|
194
|
+
case 'add': return handleAdd(rest, ctx);
|
|
195
|
+
case 'list': return handleList(rest, ctx);
|
|
196
|
+
case 'status': return handleStatus(rest, ctx);
|
|
197
|
+
case 'defer': return handleDefer(rest, ctx);
|
|
198
|
+
case 'discard': return handleDiscard(rest, ctx);
|
|
199
|
+
case 'preview': return handlePreview(rest, ctx);
|
|
200
|
+
case 'submit': return handleSubmit(rest, ctx);
|
|
201
|
+
case 'opt-in': return handleOptToggle('opt-in', rest, ctx);
|
|
202
|
+
case 'opt-out': return handleOptToggle('opt-out', rest, ctx);
|
|
203
|
+
case 'hook': return handleHook(rest, ctx);
|
|
204
|
+
default:
|
|
205
|
+
stderr.write(`[error] usage unknown feedback sub-verb '${sub}'\n`);
|
|
206
|
+
stdout.write(HELP);
|
|
207
|
+
return 2;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// -- add -------------------------------------------------------------------
|
|
212
|
+
|
|
213
|
+
const ADD_OPTIONS = /** @type {const} */ ({
|
|
214
|
+
kind: { type: 'string' },
|
|
215
|
+
target: { type: 'string' },
|
|
216
|
+
anchor: { type: 'string' },
|
|
217
|
+
class: { type: 'string' },
|
|
218
|
+
severity: { type: 'string' },
|
|
219
|
+
title: { type: 'string' },
|
|
220
|
+
body: { type: 'string' },
|
|
221
|
+
'body-file': { type: 'string' },
|
|
222
|
+
evidence: { type: 'string', multiple: true },
|
|
223
|
+
harness: { type: 'string' },
|
|
224
|
+
'ask-now': { type: 'boolean' },
|
|
225
|
+
force: { type: 'boolean' },
|
|
226
|
+
help: { type: 'boolean' },
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
async function handleAdd(argv, ctx) {
|
|
230
|
+
const { stdout, stderr, cwd, env } = ctx;
|
|
231
|
+
// F-slice-1-02: RCF_FEEDBACK_DISABLE=1 makes `add` a no-op that
|
|
232
|
+
// prints the design-8 line and exits 0 without touching the tree.
|
|
233
|
+
// Locked-down environments where even a local log is unwanted rely
|
|
234
|
+
// on this; the previous build honoured only the opt-out semantics
|
|
235
|
+
// in `status`, so `add` would still persist raw entries.
|
|
236
|
+
if (env.RCF_FEEDBACK_DISABLE === '1') {
|
|
237
|
+
stdout.write('feedback disabled by env\n');
|
|
238
|
+
return 0;
|
|
239
|
+
}
|
|
240
|
+
let parsed;
|
|
241
|
+
try {
|
|
242
|
+
parsed = parseArgs({ args: argv, options: ADD_OPTIONS, allowPositionals: false, strict: true });
|
|
243
|
+
} catch (err) {
|
|
244
|
+
stderr.write(`[error] usage ${err.message}\n`);
|
|
245
|
+
return 2;
|
|
246
|
+
}
|
|
247
|
+
const flags = parsed.values;
|
|
248
|
+
if (flags.help) { stdout.write(HELP); return 0; }
|
|
249
|
+
|
|
250
|
+
// Enum + presence checks BEFORE any project-root probing so a usage
|
|
251
|
+
// error never touches the tree.
|
|
252
|
+
const kind = flags.kind;
|
|
253
|
+
if (!kind || !KINDS.includes(kind)) {
|
|
254
|
+
stderr.write(`[error] usage --kind must be one of ${KINDS.join(', ')}\n`);
|
|
255
|
+
return 2;
|
|
256
|
+
}
|
|
257
|
+
const symptomClass = flags.class;
|
|
258
|
+
if (!symptomClass || !SYMPTOM_CLASSES.includes(symptomClass)) {
|
|
259
|
+
stderr.write(`[error] usage --class must be one of ${SYMPTOM_CLASSES.join(', ')}\n`);
|
|
260
|
+
return 2;
|
|
261
|
+
}
|
|
262
|
+
const severity = flags.severity;
|
|
263
|
+
if (!severity || !SEVERITIES.includes(severity)) {
|
|
264
|
+
stderr.write(`[error] usage --severity must be one of ${SEVERITIES.join(', ')}\n`);
|
|
265
|
+
return 2;
|
|
266
|
+
}
|
|
267
|
+
const target = flags.target;
|
|
268
|
+
if (!target) { stderr.write('[error] usage --target is required\n'); return 2; }
|
|
269
|
+
const title = flags.title;
|
|
270
|
+
if (!title) { stderr.write('[error] usage --title is required\n'); return 2; }
|
|
271
|
+
if (title.length > TITLE_CAP_CHARS) {
|
|
272
|
+
stderr.write(`[error] usage --title exceeds ${TITLE_CAP_CHARS} character cap (got ${title.length})\n`);
|
|
273
|
+
return 2;
|
|
274
|
+
}
|
|
275
|
+
const evidence = flags.evidence ?? [];
|
|
276
|
+
if (evidence.length === 0) {
|
|
277
|
+
stderr.write('[error] usage --evidence is required (repeatable)\n');
|
|
278
|
+
return 2;
|
|
279
|
+
}
|
|
280
|
+
const harness = flags.harness ?? inferHarness(ctx.env);
|
|
281
|
+
if (flags.harness && !['claude-code', 'codex', 'other'].includes(flags.harness)) {
|
|
282
|
+
stderr.write('[error] usage --harness must be one of claude-code, codex, other\n');
|
|
283
|
+
return 2;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
// Body: either --body or --body-file, exactly one, capped at 8 KB.
|
|
287
|
+
if (flags.body != null && flags['body-file'] != null) {
|
|
288
|
+
stderr.write('[error] usage pass either --body or --body-file, not both\n');
|
|
289
|
+
return 2;
|
|
290
|
+
}
|
|
291
|
+
let body;
|
|
292
|
+
if (flags.body != null) {
|
|
293
|
+
body = flags.body;
|
|
294
|
+
} else if (flags['body-file'] != null) {
|
|
295
|
+
try {
|
|
296
|
+
body = await readFile(resolve(cwd, flags['body-file']), 'utf8');
|
|
297
|
+
} catch (err) {
|
|
298
|
+
stderr.write(`[error] usage --body-file: ${err.message}\n`);
|
|
299
|
+
return 2;
|
|
300
|
+
}
|
|
301
|
+
} else {
|
|
302
|
+
stderr.write('[error] usage one of --body or --body-file is required\n');
|
|
303
|
+
return 2;
|
|
304
|
+
}
|
|
305
|
+
const bodyBytes = Buffer.byteLength(body, 'utf8');
|
|
306
|
+
if (bodyBytes > BODY_CAP_BYTES) {
|
|
307
|
+
stderr.write(`[error] usage --body exceeds ${BODY_CAP_BYTES} byte cap (got ${bodyBytes})\n`);
|
|
308
|
+
return 2;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
// Find the project root; without a manifest we cannot honour the
|
|
312
|
+
// gitignore refusal or the destination resolution.
|
|
313
|
+
const projectRoot = await findProjectRoot(cwd);
|
|
314
|
+
if (!projectRoot) {
|
|
315
|
+
stderr.write('[error] usage no project root found (no rcf/manifest.json in this directory or any ancestor). Run `npx rcf init` to scaffold and wire a project.\n');
|
|
316
|
+
return 2;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
// Gitignore pre-write refusal. --force bypasses.
|
|
320
|
+
if (!flags.force) {
|
|
321
|
+
const check = await ensureGitignore(projectRoot);
|
|
322
|
+
if (!check.ok) {
|
|
323
|
+
stderr.write(`[error] usage ${check.reason}. Run \`rcf doctor --fix\` to add the managed .gitignore entry (or pass --force to write anyway).\n`);
|
|
324
|
+
return 2;
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
// Destination resolution (design 3.3, slice 3 landed the resolver).
|
|
329
|
+
// Runs at add-time so the entry carries its declared destination
|
|
330
|
+
// through preview and submit; preview re-resolves defensively so a
|
|
331
|
+
// library that later declared an issues field lifts a previously
|
|
332
|
+
// stamped `unresolved` entry to a real destination.
|
|
333
|
+
const resolverInputs = await loadResolverInputs(projectRoot);
|
|
334
|
+
const record = kind === 'blueprint'
|
|
335
|
+
? await lookupBlueprintRecord(projectRoot, target)
|
|
336
|
+
: null;
|
|
337
|
+
// Build a resolver-shaped entry for the pre-write resolve call: the
|
|
338
|
+
// real feedback entry does not exist yet, but the resolver only reads
|
|
339
|
+
// { kind, target.ref } and the manifest for lookup.
|
|
340
|
+
const preResolveEntry = { kind, target: { ref: target } };
|
|
341
|
+
const resolvedDestination = await resolveDestination(preResolveEntry, resolverInputs);
|
|
342
|
+
// Design 3.1 exit-3 branch: the blueprint TARGET could not be found
|
|
343
|
+
// on the manifest at all (unknown-target). A library whose registry
|
|
344
|
+
// entry lacks an issuesRepo (or whose sourceRef is not a github URL)
|
|
345
|
+
// stamps the entry as unresolved but stays exit 0 (design 7 case 5:
|
|
346
|
+
// slice 4 writes the bundle at submit time).
|
|
347
|
+
const destinationUnresolved = resolvedDestination.visibility === 'unresolved';
|
|
348
|
+
const targetUnknown = destinationUnresolved && resolvedDestination.reason === 'unknown-target';
|
|
349
|
+
|
|
350
|
+
// Environment stamp (design §3.6, F-2 extended).
|
|
351
|
+
const environment = {
|
|
352
|
+
harness,
|
|
353
|
+
rcfLiteVersion: await readOwnVersion(),
|
|
354
|
+
nodeVersion: process.versions.node,
|
|
355
|
+
platform: osPlatform(),
|
|
356
|
+
};
|
|
357
|
+
|
|
358
|
+
// Blueprint-specific stamps (AC-15501-5, F-slice-1-07: also merge
|
|
359
|
+
// registry-sourced libraryRef and pin.tarballSha256 which live on
|
|
360
|
+
// rcf/blueprint-libraries.json, not on the manifest record).
|
|
361
|
+
let blueprintStamp = {};
|
|
362
|
+
if (kind === 'blueprint' && record) {
|
|
363
|
+
const registryEntry = record.libraryPrefix && resolverInputs.registry
|
|
364
|
+
? (Array.isArray(resolverInputs.registry.libraries)
|
|
365
|
+
? resolverInputs.registry.libraries.find((l) => l?.libraryPrefix === record.libraryPrefix)
|
|
366
|
+
: null)
|
|
367
|
+
: null;
|
|
368
|
+
const libraryRef = record.libraryRef ?? registryEntry?.libraryRef ?? null;
|
|
369
|
+
const resolvedSha = record.pin?.resolvedSha ?? registryEntry?.resolvedSha ?? null;
|
|
370
|
+
const tarballSha256 = record.pin?.tarballSha256 ?? registryEntry?.provenance?.tarballSha256 ?? null;
|
|
371
|
+
blueprintStamp = {
|
|
372
|
+
blueprintVersion: record.version ?? null,
|
|
373
|
+
libraryPrefix: record.libraryPrefix ?? null,
|
|
374
|
+
libraryRef,
|
|
375
|
+
...(resolvedSha ? { resolvedSha } : {}),
|
|
376
|
+
...(tarballSha256 ? { tarballSha256 } : {}),
|
|
377
|
+
};
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
const recordedAt = ctx.now().toISOString().replace(/\.\d{3}Z$/, 'Z');
|
|
381
|
+
// F-slice-1-03 / ruling R2: 12-hex id with a uniqueness probe on
|
|
382
|
+
// the append. mintUniqueEntryId THROWS FEEDBACK_ID_EXHAUSTED if
|
|
383
|
+
// every attempt collides (fail-closed, fix round 2): a colliding
|
|
384
|
+
// id would violate R2's "no two rows share an id" shape, so we
|
|
385
|
+
// refuse the write and surface the fault instead of appending a
|
|
386
|
+
// duplicate row the reader would fold into a state transition.
|
|
387
|
+
let id;
|
|
388
|
+
try {
|
|
389
|
+
id = await mintUniqueEntryId(projectRoot, ctx.now(), ctx.rng);
|
|
390
|
+
} catch (err) {
|
|
391
|
+
if (err && err.code === 'FEEDBACK_ID_EXHAUSTED') {
|
|
392
|
+
stderr.write(`[error] usage ${err.message}\n`);
|
|
393
|
+
return 2;
|
|
394
|
+
}
|
|
395
|
+
throw err;
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
const entryPreFingerprint = {
|
|
399
|
+
id,
|
|
400
|
+
recordedAt,
|
|
401
|
+
sessionId: ctx.sessionId,
|
|
402
|
+
kind,
|
|
403
|
+
target: {
|
|
404
|
+
ref: target,
|
|
405
|
+
...(kind === 'blueprint' ? {
|
|
406
|
+
effectiveSlug: record?.slug ?? target,
|
|
407
|
+
...blueprintStamp,
|
|
408
|
+
} : {}),
|
|
409
|
+
},
|
|
410
|
+
anchor: flags.anchor ?? null,
|
|
411
|
+
symptomClass,
|
|
412
|
+
severity,
|
|
413
|
+
title,
|
|
414
|
+
body,
|
|
415
|
+
evidence: evidence.map((v) => classifyEvidence(v)),
|
|
416
|
+
environment,
|
|
417
|
+
askNow: Boolean(flags['ask-now']),
|
|
418
|
+
};
|
|
419
|
+
// F-slice-1-12: persist the fingerprint so `list --json`, `status`
|
|
420
|
+
// and any triage-side tooling can key off it without re-computing.
|
|
421
|
+
// The persisted value MUST equal what preview and submit compute
|
|
422
|
+
// from the same entry.
|
|
423
|
+
const fp = fingerprint(entryPreFingerprint);
|
|
424
|
+
const entry = {
|
|
425
|
+
...entryPreFingerprint,
|
|
426
|
+
fingerprint: fp,
|
|
427
|
+
status: 'pending',
|
|
428
|
+
destination: destinationUnresolved
|
|
429
|
+
// Preserve the slice-1 shape ({ reason: 'unresolved' }) that
|
|
430
|
+
// existing tests and the preview-time re-resolve rely on; the
|
|
431
|
+
// resolver's granular reason (unknown-target vs no-issues-field
|
|
432
|
+
// vs no-github-source vs no-libraryprefix-record) is recomputed
|
|
433
|
+
// at preview and submit time.
|
|
434
|
+
? { reason: 'unresolved', resolverReason: resolvedDestination.reason ?? 'unresolved' }
|
|
435
|
+
: {
|
|
436
|
+
repo: resolvedDestination.repo,
|
|
437
|
+
visibility: resolvedDestination.visibility,
|
|
438
|
+
kind: resolvedDestination.kind,
|
|
439
|
+
derived: resolvedDestination.derived,
|
|
440
|
+
...(resolvedDestination.source ? { source: resolvedDestination.source } : {}),
|
|
441
|
+
...(resolvedDestination.publisherContact ? { publisherContact: resolvedDestination.publisherContact } : {}),
|
|
442
|
+
},
|
|
443
|
+
};
|
|
444
|
+
|
|
445
|
+
await appendEntry(projectRoot, entry);
|
|
446
|
+
|
|
447
|
+
// F-slice-1-09: prune discarded entries older than 30 days so the
|
|
448
|
+
// log does not grow unbounded (design 3.1 L137). The prune is a
|
|
449
|
+
// set of state transitions, not a rewrite of the JSONL; a discarded
|
|
450
|
+
// entry older than the window gains a new `pruned` state line so
|
|
451
|
+
// the reader's fold-by-id drops it from `list --all` counts too.
|
|
452
|
+
await pruneOldDiscarded(projectRoot, ctx.now());
|
|
453
|
+
|
|
454
|
+
// Count of pending entries after this write (fold-by-id read).
|
|
455
|
+
const all = await readEntries(projectRoot);
|
|
456
|
+
const pending = all.filter((e) => e.status === 'pending').length;
|
|
457
|
+
|
|
458
|
+
stdout.write(`recorded ${id} (${pending} pending). Nothing sent.\n`);
|
|
459
|
+
|
|
460
|
+
if (targetUnknown) {
|
|
461
|
+
// Design 3.1 exit-3: --kind blueprint but the target does not
|
|
462
|
+
// appear on rcf/manifest.json:blueprints[]. The entry is still
|
|
463
|
+
// recorded so the operator can rewrite the target and re-preview.
|
|
464
|
+
stderr.write(`destination unresolved: ${target}\n`);
|
|
465
|
+
return 3;
|
|
466
|
+
}
|
|
467
|
+
if (destinationUnresolved) {
|
|
468
|
+
// Design 7 case 5: the target resolved to a library whose registry
|
|
469
|
+
// entry has no issuesRepo and no derivable github source. Entry is
|
|
470
|
+
// stamped unresolved and stays pending; slice 4 writes the bundle
|
|
471
|
+
// at submit time and prints the publisher contact.
|
|
472
|
+
stderr.write(`destination unresolved for library '${record?.libraryPrefix ?? '<unknown>'}': ${resolvedDestination.reason ?? 'unresolved'}. The entry is kept; \`rcf feedback submit\` will write a bundle instead of filing an issue.\n`);
|
|
473
|
+
}
|
|
474
|
+
return 0;
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
/**
|
|
478
|
+
* Classify an evidence pointer into `{ kind, value }`. A colon-separated
|
|
479
|
+
* `path:line` pattern is 'file'; a bare identifier that looks like an
|
|
480
|
+
* upper-cased id is 'id'; anything else is 'command'. The classification
|
|
481
|
+
* is best-effort and does not gate the write.
|
|
482
|
+
*
|
|
483
|
+
* @param {string} value
|
|
484
|
+
* @returns {{ kind: 'file' | 'id' | 'command', value: string }}
|
|
485
|
+
*/
|
|
486
|
+
export function classifyEvidence(value) {
|
|
487
|
+
if (/^[A-Z]+-\d[\w-]*$/.test(value)) return { kind: 'id', value };
|
|
488
|
+
if (/^[^\s].*:\d+$/.test(value)) return { kind: 'file', value };
|
|
489
|
+
return { kind: 'command', value };
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
// -- list ------------------------------------------------------------------
|
|
493
|
+
|
|
494
|
+
const LIST_OPTIONS = /** @type {const} */ ({
|
|
495
|
+
all: { type: 'boolean' },
|
|
496
|
+
json: { type: 'boolean' },
|
|
497
|
+
help: { type: 'boolean' },
|
|
498
|
+
});
|
|
499
|
+
|
|
500
|
+
async function handleList(argv, ctx) {
|
|
501
|
+
const { stdout, stderr, cwd } = ctx;
|
|
502
|
+
let parsed;
|
|
503
|
+
try {
|
|
504
|
+
parsed = parseArgs({ args: argv, options: LIST_OPTIONS, allowPositionals: false, strict: true });
|
|
505
|
+
} catch (err) {
|
|
506
|
+
stderr.write(`[error] usage ${err.message}\n`);
|
|
507
|
+
return 2;
|
|
508
|
+
}
|
|
509
|
+
const flags = parsed.values;
|
|
510
|
+
if (flags.help) { stdout.write(HELP); return 0; }
|
|
511
|
+
|
|
512
|
+
const projectRoot = await findProjectRoot(cwd);
|
|
513
|
+
if (!projectRoot) {
|
|
514
|
+
stderr.write('[error] usage no project root found (no rcf/manifest.json in this directory or any ancestor).\n');
|
|
515
|
+
return 2;
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
const all = await readEntries(projectRoot);
|
|
519
|
+
const shown = flags.all ? all : all.filter((e) => e.status === 'pending');
|
|
520
|
+
// Round 3 (F-slice-1-09 regression): a pruned entry's body and
|
|
521
|
+
// title stayed visible through `list --all --json` because the
|
|
522
|
+
// fold-by-id spread merged the pruned state row over the original
|
|
523
|
+
// entry without clearing the free-form content. The prune sweep's
|
|
524
|
+
// point is to age content out; scrub it here so `list` on either
|
|
525
|
+
// surface never re-exposes a pruned body.
|
|
526
|
+
const sanitised = shown.map((e) => (e.status === 'pruned'
|
|
527
|
+
? { ...e, title: null, body: null, evidence: [] }
|
|
528
|
+
: e));
|
|
529
|
+
|
|
530
|
+
if (flags.json) {
|
|
531
|
+
stdout.write(`${JSON.stringify(sanitised, null, 2)}\n`);
|
|
532
|
+
return 0;
|
|
533
|
+
}
|
|
534
|
+
if (sanitised.length === 0) {
|
|
535
|
+
stdout.write(flags.all
|
|
536
|
+
? 'no feedback entries.\n'
|
|
537
|
+
: 'no pending feedback entries.\n');
|
|
538
|
+
return 0;
|
|
539
|
+
}
|
|
540
|
+
const rows = sanitised.slice().sort((a, b) => (a.recordedAt ?? '').localeCompare(b.recordedAt ?? ''));
|
|
541
|
+
for (const e of rows) {
|
|
542
|
+
const statusCol = flags.all ? `[${e.status}] ` : '';
|
|
543
|
+
const titleText = e.status === 'pruned' ? '(pruned; body scrubbed)' : e.title;
|
|
544
|
+
stdout.write(`${statusCol}${e.id} ${e.target?.ref ?? '?'} ${e.symptomClass} ${e.severity} ${titleText}\n`);
|
|
545
|
+
}
|
|
546
|
+
return 0;
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
// -- status ----------------------------------------------------------------
|
|
550
|
+
|
|
551
|
+
const STATUS_OPTIONS = /** @type {const} */ ({
|
|
552
|
+
json: { type: 'boolean' },
|
|
553
|
+
help: { type: 'boolean' },
|
|
554
|
+
});
|
|
555
|
+
|
|
556
|
+
async function handleStatus(argv, ctx) {
|
|
557
|
+
const { stdout, stderr, cwd, env } = ctx;
|
|
558
|
+
let parsed;
|
|
559
|
+
try {
|
|
560
|
+
parsed = parseArgs({ args: argv, options: STATUS_OPTIONS, allowPositionals: false, strict: true });
|
|
561
|
+
} catch (err) {
|
|
562
|
+
stderr.write(`[error] usage ${err.message}\n`);
|
|
563
|
+
return 2;
|
|
564
|
+
}
|
|
565
|
+
const flags = parsed.values;
|
|
566
|
+
if (flags.help) { stdout.write(HELP); return 0; }
|
|
567
|
+
|
|
568
|
+
const projectRoot = await findProjectRoot(cwd);
|
|
569
|
+
if (!projectRoot) {
|
|
570
|
+
stderr.write('[error] usage no project root found (no rcf/manifest.json in this directory or any ancestor).\n');
|
|
571
|
+
return 2;
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
const exists = await storeExists(projectRoot);
|
|
575
|
+
const all = exists ? await readEntries(projectRoot) : [];
|
|
576
|
+
const counts = countByStatus(all);
|
|
577
|
+
// Precedence (design section 8): env DISABLE > env ASK=0 > file
|
|
578
|
+
// ask false > file ask true (the default). The status view names
|
|
579
|
+
// the resolved source so the operator can tell whether an ask
|
|
580
|
+
// will fire without inspecting the file.
|
|
581
|
+
const settingsRead = await readFeedbackSettings(projectRoot);
|
|
582
|
+
const fileAskOff = settingsRead.settings.ask === false;
|
|
583
|
+
const optOut = env.RCF_FEEDBACK_DISABLE === '1'
|
|
584
|
+
|| env.RCF_FEEDBACK_ASK === '0'
|
|
585
|
+
|| fileAskOff;
|
|
586
|
+
// Destination coverage across the library registry (design 3.1;
|
|
587
|
+
// slice 3 landed the resolver). A parseable-but-empty registry means
|
|
588
|
+
// no libraries are declared, so nothing to warn about. A broken
|
|
589
|
+
// registry is treated as "no libraries" here; the doctor
|
|
590
|
+
// feedback-destinations check surfaces the parse failure instead.
|
|
591
|
+
const registryRead = await readLibraryRegistry(projectRoot);
|
|
592
|
+
const registry = (registryRead && typeof registryRead === 'object' && 'kind' in registryRead)
|
|
593
|
+
? { libraries: [] }
|
|
594
|
+
: registryRead;
|
|
595
|
+
const unresolvedLibraries = listUnresolvedLibraries(registry);
|
|
596
|
+
// Slice 4 (FBS-183): probe gh availability once so `rcf feedback
|
|
597
|
+
// status` warns the operator when submit would fall through to a
|
|
598
|
+
// bundle. A failed probe never fails status; the summary just
|
|
599
|
+
// records what the probe saw.
|
|
600
|
+
const ghSummary = await probeGhSummary(env);
|
|
601
|
+
// Per-blueprint destination table (design 3.1 L140): for every
|
|
602
|
+
// applied blueprint on the manifest, show the destination the
|
|
603
|
+
// resolver would return today. Read-only, no network. Collected
|
|
604
|
+
// BEFORE the JSON early-return so --json carries the same table
|
|
605
|
+
// the text path prints (F-slice-1-10 fix round 2).
|
|
606
|
+
const resolverInputsStatus = await loadResolverInputs(projectRoot);
|
|
607
|
+
const appliedBlueprints = Array.isArray(resolverInputsStatus.manifest?.blueprints)
|
|
608
|
+
? resolverInputsStatus.manifest.blueprints
|
|
609
|
+
: [];
|
|
610
|
+
const destinationTable = [];
|
|
611
|
+
for (const r of appliedBlueprints) {
|
|
612
|
+
const ref = r.libraryPrefix
|
|
613
|
+
? `${r.libraryPrefix}:${r.slug}`
|
|
614
|
+
: (r.slug ?? r.name ?? '(unnamed)');
|
|
615
|
+
const dest = await resolveDestination(
|
|
616
|
+
{ kind: 'blueprint', target: { ref } },
|
|
617
|
+
resolverInputsStatus,
|
|
618
|
+
);
|
|
619
|
+
destinationTable.push({
|
|
620
|
+
ref,
|
|
621
|
+
repo: dest.repo ?? null,
|
|
622
|
+
visibility: dest.visibility ?? 'unresolved',
|
|
623
|
+
derived: !!dest.derived,
|
|
624
|
+
reason: dest.reason ?? null,
|
|
625
|
+
});
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
const summary = {
|
|
629
|
+
counts,
|
|
630
|
+
optOut,
|
|
631
|
+
optOutSource: optOut
|
|
632
|
+
? (env.RCF_FEEDBACK_DISABLE === '1'
|
|
633
|
+
? 'env:RCF_FEEDBACK_DISABLE'
|
|
634
|
+
: (env.RCF_FEEDBACK_ASK === '0'
|
|
635
|
+
? 'env:RCF_FEEDBACK_ASK=0'
|
|
636
|
+
: 'file:rcf/feedback-settings.json'))
|
|
637
|
+
: null,
|
|
638
|
+
quietMinutes: settingsRead.settings.quietMinutes,
|
|
639
|
+
storePath: '.rcf/feedback/entries.jsonl',
|
|
640
|
+
gh: ghSummary,
|
|
641
|
+
destinations: {
|
|
642
|
+
registeredLibraries: Array.isArray(registry?.libraries) ? registry.libraries.length : 0,
|
|
643
|
+
unresolvedLibraries,
|
|
644
|
+
table: destinationTable,
|
|
645
|
+
},
|
|
646
|
+
};
|
|
647
|
+
|
|
648
|
+
if (flags.json) {
|
|
649
|
+
stdout.write(`${JSON.stringify(summary, null, 2)}\n`);
|
|
650
|
+
return 0;
|
|
651
|
+
}
|
|
652
|
+
stdout.write(`feedback: ${counts.pending} pending, ${counts.submitted} submitted, ${counts.bundled} bundled, ${counts.deferredUntilSession} deferred, ${counts.discarded} discarded, ${counts.pruned} pruned\n`);
|
|
653
|
+
stdout.write(`opt-out: ${optOut ? `yes (${summary.optOutSource})` : 'no'}\n`);
|
|
654
|
+
stdout.write(`gh: ${ghSummary.present ? (ghSummary.authed ? 'installed, authed on github.com' : 'installed, not logged in (submit will bundle)') : 'not installed (submit will bundle)'}\n`);
|
|
655
|
+
if (summary.destinations.unresolvedLibraries.length > 0) {
|
|
656
|
+
stdout.write(`destinations: ${summary.destinations.unresolvedLibraries.length} of ${summary.destinations.registeredLibraries} registered librar${summary.destinations.registeredLibraries === 1 ? 'y has' : 'ies have'} no resolvable destination:\n`);
|
|
657
|
+
// F-slice-3-04: text output must LIST every unresolved library
|
|
658
|
+
// (design 3.3 L163); JSON already emits the array.
|
|
659
|
+
for (const u of summary.destinations.unresolvedLibraries) {
|
|
660
|
+
const contact = u.publisherContact ? ` (contact: ${u.publisherContact})` : '';
|
|
661
|
+
stdout.write(` - ${u.libraryPrefix}: ${u.reason}${contact}\n`);
|
|
662
|
+
}
|
|
663
|
+
} else if (summary.destinations.registeredLibraries > 0) {
|
|
664
|
+
stdout.write(`destinations: all ${summary.destinations.registeredLibraries} registered librar${summary.destinations.registeredLibraries === 1 ? 'y resolves' : 'ies resolve'} to a feedback destination.\n`);
|
|
665
|
+
}
|
|
666
|
+
if (destinationTable.length > 0) {
|
|
667
|
+
stdout.write(`applied blueprints (${destinationTable.length}):\n`);
|
|
668
|
+
for (const row of destinationTable) {
|
|
669
|
+
const cell = row.repo
|
|
670
|
+
? `${row.repo} (${row.visibility}${row.derived ? ', derived' : ''})`
|
|
671
|
+
: `(unresolved${row.reason ? `: ${row.reason}` : ''})`;
|
|
672
|
+
stdout.write(` - ${row.ref} -> ${cell}\n`);
|
|
673
|
+
}
|
|
674
|
+
}
|
|
675
|
+
return 0;
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
/**
|
|
679
|
+
* Probe the gh adapter for install + auth state. Slice 4 wires this;
|
|
680
|
+
* the returned shape is what `feedback status --json` emits under
|
|
681
|
+
* `gh`. A failed probe never throws.
|
|
682
|
+
*
|
|
683
|
+
* @param {NodeJS.ProcessEnv} env
|
|
684
|
+
*/
|
|
685
|
+
async function probeGhSummary(env) {
|
|
686
|
+
try {
|
|
687
|
+
const gh = await loadGhAdapter(env);
|
|
688
|
+
const path = await gh.ghOnPath();
|
|
689
|
+
const present = !!(path.ok && path.value?.present !== false);
|
|
690
|
+
if (!present) {
|
|
691
|
+
return { present: false, authed: false, host: 'github.com', note: 'gh not on PATH' };
|
|
692
|
+
}
|
|
693
|
+
const auth = await gh.ghAuthStatus({ host: 'github.com' });
|
|
694
|
+
return {
|
|
695
|
+
present: true,
|
|
696
|
+
authed: !!auth.ok,
|
|
697
|
+
host: 'github.com',
|
|
698
|
+
note: auth.ok ? null : 'run `gh auth login` to enable submit',
|
|
699
|
+
};
|
|
700
|
+
} catch (err) {
|
|
701
|
+
return { present: null, authed: null, host: 'github.com', note: `probe failed: ${err.message}` };
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
function countByStatus(entries) {
|
|
706
|
+
// F-slice-1-09 fix: `pruned` is a real state now that retention
|
|
707
|
+
// sweeps stamp it, so status counts it too. Without this the count
|
|
708
|
+
// line silently under-reported the store.
|
|
709
|
+
const c = {
|
|
710
|
+
pending: 0, submitted: 0, bundled: 0, deferredUntilSession: 0, discarded: 0, pruned: 0,
|
|
711
|
+
};
|
|
712
|
+
for (const e of entries) {
|
|
713
|
+
if (Object.prototype.hasOwnProperty.call(c, e.status)) c[e.status] += 1;
|
|
714
|
+
}
|
|
715
|
+
return c;
|
|
716
|
+
}
|
|
717
|
+
|
|
718
|
+
// -- defer -----------------------------------------------------------------
|
|
719
|
+
|
|
720
|
+
const DEFER_OPTIONS = /** @type {const} */ ({
|
|
721
|
+
help: { type: 'boolean' },
|
|
722
|
+
});
|
|
723
|
+
|
|
724
|
+
async function handleDefer(argv, ctx) {
|
|
725
|
+
const { stdout, stderr, cwd } = ctx;
|
|
726
|
+
let parsed;
|
|
727
|
+
try {
|
|
728
|
+
parsed = parseArgs({ args: argv, options: DEFER_OPTIONS, allowPositionals: false, strict: true });
|
|
729
|
+
} catch (err) {
|
|
730
|
+
stderr.write(`[error] usage ${err.message}\n`);
|
|
731
|
+
return 2;
|
|
732
|
+
}
|
|
733
|
+
const flags = parsed.values;
|
|
734
|
+
if (flags.help) { stdout.write(HELP); return 0; }
|
|
735
|
+
|
|
736
|
+
const projectRoot = await findProjectRoot(cwd);
|
|
737
|
+
if (!projectRoot) {
|
|
738
|
+
stderr.write('[error] usage no project root found (no rcf/manifest.json in this directory or any ancestor).\n');
|
|
739
|
+
return 2;
|
|
740
|
+
}
|
|
741
|
+
const all = await readEntries(projectRoot);
|
|
742
|
+
const pending = all.filter((e) => e.status === 'pending');
|
|
743
|
+
if (pending.length === 0) {
|
|
744
|
+
stdout.write('no pending feedback entries to defer.\n');
|
|
745
|
+
return 0;
|
|
746
|
+
}
|
|
747
|
+
const at = ctx.now().toISOString().replace(/\.\d{3}Z$/, 'Z');
|
|
748
|
+
for (const e of pending) {
|
|
749
|
+
await appendState(projectRoot, {
|
|
750
|
+
id: e.id, at, status: 'deferredUntilSession', sessionId: ctx.sessionId,
|
|
751
|
+
});
|
|
752
|
+
}
|
|
753
|
+
stdout.write(`deferred ${pending.length} entr${pending.length === 1 ? 'y' : 'ies'} for session ${ctx.sessionId}.\n`);
|
|
754
|
+
return 0;
|
|
755
|
+
}
|
|
756
|
+
|
|
757
|
+
/**
|
|
758
|
+
* Requeue entries that were `deferredUntilSession` under a prior
|
|
759
|
+
* `sessionId` back to `pending` for the current session. Called from
|
|
760
|
+
* both `runSessionStartHook` and `runStopHook` so a defer taken in
|
|
761
|
+
* session A returns to the ask queue in session B whether the
|
|
762
|
+
* SessionStart hook is installed or not (design 3.1: defer = "not
|
|
763
|
+
* now", ask again next session; AC-16103-3).
|
|
764
|
+
*
|
|
765
|
+
* The transition line writes `{ id, at, status: 'pending' }` with
|
|
766
|
+
* NO `sessionId` field, so fold-by-id preserves the entry's prior
|
|
767
|
+
* `sessionId` (the session it was last deferred in). That keeps the
|
|
768
|
+
* `anyCarriedOver` gate in both hooks naturally true in the new
|
|
769
|
+
* session: `pending.sessionId !== currentSessionId`.
|
|
770
|
+
*
|
|
771
|
+
* Idempotent per session: entries whose folded `sessionId` already
|
|
772
|
+
* equals the current session (a fresh add this session, or a
|
|
773
|
+
* previous requeue for this same session) are skipped.
|
|
774
|
+
*
|
|
775
|
+
* @param {string} projectRoot
|
|
776
|
+
* @param {string | undefined} sessionId
|
|
777
|
+
* @param {() => Date} now
|
|
778
|
+
* @returns {Promise<number>} number of entries requeued
|
|
779
|
+
*/
|
|
780
|
+
async function requeueDeferredForSession(projectRoot, sessionId, now) {
|
|
781
|
+
if (!sessionId) return 0;
|
|
782
|
+
const all = await readEntries(projectRoot);
|
|
783
|
+
const toRequeue = all.filter((e) => {
|
|
784
|
+
if (e.status !== 'deferredUntilSession') return false;
|
|
785
|
+
const s = typeof e.sessionId === 'string' ? e.sessionId : '';
|
|
786
|
+
return s !== '' && s !== sessionId;
|
|
787
|
+
});
|
|
788
|
+
if (toRequeue.length === 0) return 0;
|
|
789
|
+
const at = now().toISOString().replace(/\.\d{3}Z$/, 'Z');
|
|
790
|
+
for (const e of toRequeue) {
|
|
791
|
+
await appendState(projectRoot, {
|
|
792
|
+
id: e.id, at, status: 'pending',
|
|
793
|
+
});
|
|
794
|
+
}
|
|
795
|
+
return toRequeue.length;
|
|
796
|
+
}
|
|
797
|
+
|
|
798
|
+
// -- discard ---------------------------------------------------------------
|
|
799
|
+
|
|
800
|
+
const DISCARD_OPTIONS = /** @type {const} */ ({
|
|
801
|
+
all: { type: 'boolean' },
|
|
802
|
+
help: { type: 'boolean' },
|
|
803
|
+
});
|
|
804
|
+
|
|
805
|
+
async function handleDiscard(argv, ctx) {
|
|
806
|
+
const { stdout, stderr, cwd } = ctx;
|
|
807
|
+
let parsed;
|
|
808
|
+
try {
|
|
809
|
+
parsed = parseArgs({ args: argv, options: DISCARD_OPTIONS, allowPositionals: true, strict: true });
|
|
810
|
+
} catch (err) {
|
|
811
|
+
stderr.write(`[error] usage ${err.message}\n`);
|
|
812
|
+
return 2;
|
|
813
|
+
}
|
|
814
|
+
const flags = parsed.values;
|
|
815
|
+
if (flags.help) { stdout.write(HELP); return 0; }
|
|
816
|
+
|
|
817
|
+
const projectRoot = await findProjectRoot(cwd);
|
|
818
|
+
if (!projectRoot) {
|
|
819
|
+
stderr.write('[error] usage no project root found (no rcf/manifest.json in this directory or any ancestor).\n');
|
|
820
|
+
return 2;
|
|
821
|
+
}
|
|
822
|
+
const all = await readEntries(projectRoot);
|
|
823
|
+
// F-slice-1-11: design 3.1 L137 allows discard against any id, not
|
|
824
|
+
// only pending. A user changing their mind about a deferred or a
|
|
825
|
+
// bundled entry must be able to say so. Only already-discarded /
|
|
826
|
+
// pruned entries are refused (idempotency).
|
|
827
|
+
const active = all.filter((e) => e.status !== 'discarded' && e.status !== 'pruned');
|
|
828
|
+
const pending = all.filter((e) => e.status === 'pending');
|
|
829
|
+
let targets;
|
|
830
|
+
if (flags.all) {
|
|
831
|
+
if (parsed.positionals.length > 0) {
|
|
832
|
+
stderr.write('[error] usage --all cannot be combined with entry ids\n');
|
|
833
|
+
return 2;
|
|
834
|
+
}
|
|
835
|
+
// `--all` (kept scope: pending only) matches slice-1 semantics
|
|
836
|
+
// so a hook-triggered mass discard does not accidentally nuke
|
|
837
|
+
// submitted issue links.
|
|
838
|
+
targets = pending;
|
|
839
|
+
} else {
|
|
840
|
+
if (parsed.positionals.length === 0) {
|
|
841
|
+
stderr.write('[error] usage discard: at least one entry id, or --all\n');
|
|
842
|
+
return 2;
|
|
843
|
+
}
|
|
844
|
+
const wanted = new Set(parsed.positionals);
|
|
845
|
+
const byId = new Map(active.map((e) => [e.id, e]));
|
|
846
|
+
targets = [];
|
|
847
|
+
const missing = [];
|
|
848
|
+
for (const id of wanted) {
|
|
849
|
+
const e = byId.get(id);
|
|
850
|
+
if (!e) { missing.push(id); continue; }
|
|
851
|
+
targets.push(e);
|
|
852
|
+
}
|
|
853
|
+
if (missing.length > 0) {
|
|
854
|
+
stderr.write(`[error] usage unknown entry id(s): ${missing.join(', ')}\n`);
|
|
855
|
+
return 2;
|
|
856
|
+
}
|
|
857
|
+
}
|
|
858
|
+
if (targets.length === 0) {
|
|
859
|
+
stdout.write('no feedback entries to discard.\n');
|
|
860
|
+
return 0;
|
|
861
|
+
}
|
|
862
|
+
const at = ctx.now().toISOString().replace(/\.\d{3}Z$/, 'Z');
|
|
863
|
+
for (const e of targets) {
|
|
864
|
+
await appendState(projectRoot, { id: e.id, at, status: 'discarded' });
|
|
865
|
+
}
|
|
866
|
+
stdout.write(`discarded ${targets.length} entr${targets.length === 1 ? 'y' : 'ies'}.\n`);
|
|
867
|
+
return 0;
|
|
868
|
+
}
|
|
869
|
+
|
|
870
|
+
// -- preview (slice 2, FBS-181) -------------------------------------------
|
|
871
|
+
|
|
872
|
+
const PREVIEW_OPTIONS = /** @type {const} */ ({
|
|
873
|
+
json: { type: 'boolean' },
|
|
874
|
+
help: { type: 'boolean' },
|
|
875
|
+
});
|
|
876
|
+
|
|
877
|
+
/**
|
|
878
|
+
* Render each named (or every pending) entry as the title and body it
|
|
879
|
+
* would take on the GitHub issue tracker, plus a redaction disclosure
|
|
880
|
+
* ledger and any residual-secret markers rule 8b turned up. This is
|
|
881
|
+
* what the operator sees before consenting to submit; it is read-only
|
|
882
|
+
* and never touches the network.
|
|
883
|
+
*
|
|
884
|
+
* Text output: one framed block per entry with the destination line,
|
|
885
|
+
* the rendered title, the rendered body inside a `---` fence, and the
|
|
886
|
+
* ledger printed as diff-style `- before / + after (rule, count)`
|
|
887
|
+
* rows. `--json` emits the same as one object per entry.
|
|
888
|
+
*
|
|
889
|
+
* @param {string[]} argv
|
|
890
|
+
* @param {object} ctx
|
|
891
|
+
* @returns {Promise<number>}
|
|
892
|
+
*/
|
|
893
|
+
async function handlePreview(argv, ctx) {
|
|
894
|
+
const { stdout, stderr, cwd } = ctx;
|
|
895
|
+
let parsed;
|
|
896
|
+
try {
|
|
897
|
+
parsed = parseArgs({ args: argv, options: PREVIEW_OPTIONS, allowPositionals: true, strict: true });
|
|
898
|
+
} catch (err) {
|
|
899
|
+
stderr.write(`[error] usage ${err.message}\n`);
|
|
900
|
+
return 2;
|
|
901
|
+
}
|
|
902
|
+
const flags = parsed.values;
|
|
903
|
+
if (flags.help) { stdout.write(HELP); return 0; }
|
|
904
|
+
|
|
905
|
+
const projectRoot = await findProjectRoot(cwd);
|
|
906
|
+
if (!projectRoot) {
|
|
907
|
+
stderr.write('[error] usage no project root found (no rcf/manifest.json in this directory or any ancestor).\n');
|
|
908
|
+
return 2;
|
|
909
|
+
}
|
|
910
|
+
|
|
911
|
+
const all = await readEntries(projectRoot);
|
|
912
|
+
const pending = all.filter((e) => e.status === 'pending');
|
|
913
|
+
const wantedIds = new Set(parsed.positionals);
|
|
914
|
+
const entries = wantedIds.size > 0
|
|
915
|
+
? pending.filter((e) => wantedIds.has(e.id))
|
|
916
|
+
: pending;
|
|
917
|
+
|
|
918
|
+
if (wantedIds.size > 0) {
|
|
919
|
+
const missing = [...wantedIds].filter((id) => !pending.some((e) => e.id === id));
|
|
920
|
+
if (missing.length > 0) {
|
|
921
|
+
stderr.write(`[error] usage unknown pending entry id(s): ${missing.join(', ')}\n`);
|
|
922
|
+
return 2;
|
|
923
|
+
}
|
|
924
|
+
}
|
|
925
|
+
|
|
926
|
+
const context = await buildRedactionContext(projectRoot);
|
|
927
|
+
const resolverInputs = await loadResolverInputs(projectRoot);
|
|
928
|
+
|
|
929
|
+
const previews = await Promise.all(
|
|
930
|
+
entries.map((e) => buildPreview(e, context, resolverInputs)),
|
|
931
|
+
);
|
|
932
|
+
|
|
933
|
+
if (flags.json) {
|
|
934
|
+
stdout.write(`${JSON.stringify(previews, null, 2)}\n`);
|
|
935
|
+
return 0;
|
|
936
|
+
}
|
|
937
|
+
|
|
938
|
+
if (previews.length === 0) {
|
|
939
|
+
stdout.write('no pending feedback entries to preview.\n');
|
|
940
|
+
return 0;
|
|
941
|
+
}
|
|
942
|
+
|
|
943
|
+
for (const p of previews) {
|
|
944
|
+
stdout.write(`--- ${p.id} ---\n`);
|
|
945
|
+
// F-slice-3-03: preview must show derived-source disclosure and
|
|
946
|
+
// the unresolved-library bundle message, not just repo + visibility.
|
|
947
|
+
stdout.write(`destination: ${p.destination.repo ?? '(unresolved)'} (${p.destination.visibility})\n`);
|
|
948
|
+
if (p.destination.derived === true) {
|
|
949
|
+
stdout.write(" source: derived from the library's git source (no explicit issues field on the library)\n");
|
|
950
|
+
} else if (p.destination.source) {
|
|
951
|
+
stdout.write(` source: ${p.destination.source}\n`);
|
|
952
|
+
}
|
|
953
|
+
if (p.destination.visibility === 'unresolved') {
|
|
954
|
+
const reason = p.destination.reason ?? 'unresolved';
|
|
955
|
+
const contact = p.destination.publisherContact ? ` (library contact: ${p.destination.publisherContact})` : '';
|
|
956
|
+
stdout.write(` no issue destination declared${p.destination.reason ? ` (${reason})` : ''}; bundle will be written${contact}\n`);
|
|
957
|
+
}
|
|
958
|
+
stdout.write(`fingerprint: ${p.fingerprint}\n`);
|
|
959
|
+
if (p.fingerprintFallback) {
|
|
960
|
+
stdout.write('warning: no anchor on this entry; the fingerprint falls back to normalised-title tokens and duplicates may not fold.\n');
|
|
961
|
+
}
|
|
962
|
+
stdout.write(`title: ${p.titleRendered}\n`);
|
|
963
|
+
stdout.write('body:\n');
|
|
964
|
+
stdout.write('---\n');
|
|
965
|
+
stdout.write(`${p.bodyRendered}\n`);
|
|
966
|
+
stdout.write('---\n');
|
|
967
|
+
if (p.ledger.length === 0) {
|
|
968
|
+
stdout.write('redaction ledger: nothing replaced.\n');
|
|
969
|
+
} else {
|
|
970
|
+
stdout.write('redaction ledger:\n');
|
|
971
|
+
for (const row of p.ledger) {
|
|
972
|
+
stdout.write(` - ${row.before}\n`);
|
|
973
|
+
stdout.write(` + ${row.after} (${row.rule}, x${row.count})\n`);
|
|
974
|
+
}
|
|
975
|
+
}
|
|
976
|
+
if (p.residual.length > 0) {
|
|
977
|
+
stdout.write('residual secret markers (submit will refuse):\n');
|
|
978
|
+
for (const r of p.residual) {
|
|
979
|
+
stdout.write(` residual secret at line ${r.line}: ${r.snippet} (${r.pattern})\n`);
|
|
980
|
+
}
|
|
981
|
+
}
|
|
982
|
+
stdout.write('\n');
|
|
983
|
+
}
|
|
984
|
+
return 0;
|
|
985
|
+
}
|
|
986
|
+
|
|
987
|
+
/**
|
|
988
|
+
* Assemble the redaction context from the project's identity seed and
|
|
989
|
+
* manifest. Best-effort: a missing file leaves that field undefined
|
|
990
|
+
* rather than failing the preview.
|
|
991
|
+
*
|
|
992
|
+
* @param {string} projectRoot
|
|
993
|
+
* @returns {Promise<import('../feedback/redact.js').RedactionContext>}
|
|
994
|
+
*/
|
|
995
|
+
async function buildRedactionContext(projectRoot) {
|
|
996
|
+
let operatorName;
|
|
997
|
+
try {
|
|
998
|
+
const profile = await readFile(resolve(projectRoot, 'rcf', '.identity', 'profile.md'), 'utf8');
|
|
999
|
+
const m = profile.match(/^##\s+Name\s*\n([^\n]+)/m);
|
|
1000
|
+
if (m) {
|
|
1001
|
+
const n = m[1].trim();
|
|
1002
|
+
if (n && !/placeholder|todo|your name/i.test(n)) operatorName = n;
|
|
1003
|
+
}
|
|
1004
|
+
} catch { /* absent is fine */ }
|
|
1005
|
+
|
|
1006
|
+
let projectName;
|
|
1007
|
+
const remotes = new Set();
|
|
1008
|
+
try {
|
|
1009
|
+
const manifest = JSON.parse(await readFile(resolve(projectRoot, 'rcf', 'manifest.json'), 'utf8'));
|
|
1010
|
+
if (typeof manifest.projectName === 'string') projectName = manifest.projectName;
|
|
1011
|
+
if (typeof manifest.gitRemote === 'string') remotes.add(manifest.gitRemote);
|
|
1012
|
+
} catch { /* absent is fine */ }
|
|
1013
|
+
|
|
1014
|
+
// F-slice-2-07: also walk `git remote -v` so ordinary projects
|
|
1015
|
+
// without a manifest.gitRemote still have their HTTPS remote
|
|
1016
|
+
// redacted. Best-effort; a missing git or a non-repo directory
|
|
1017
|
+
// just leaves the set unchanged.
|
|
1018
|
+
try {
|
|
1019
|
+
const { stdout } = await execFileP('git', ['-C', projectRoot, 'remote', '-v'], { encoding: 'utf8' });
|
|
1020
|
+
for (const line of stdout.split('\n')) {
|
|
1021
|
+
const parts = line.split(/\s+/);
|
|
1022
|
+
if (parts.length >= 2 && parts[1]) remotes.add(parts[1]);
|
|
1023
|
+
}
|
|
1024
|
+
} catch { /* no git or no remotes is fine */ }
|
|
1025
|
+
|
|
1026
|
+
let allowHostsExt = [];
|
|
1027
|
+
try {
|
|
1028
|
+
const settings = JSON.parse(await readFile(resolve(projectRoot, 'rcf', 'feedback-settings.json'), 'utf8'));
|
|
1029
|
+
if (Array.isArray(settings?.redaction?.allowHosts)) {
|
|
1030
|
+
allowHostsExt = settings.redaction.allowHosts;
|
|
1031
|
+
}
|
|
1032
|
+
} catch { /* absent is fine */ }
|
|
1033
|
+
// Assemble the extended allow-list once so downstream callers can
|
|
1034
|
+
// print it if they want to; the redactor itself accepts the raw
|
|
1035
|
+
// extension array.
|
|
1036
|
+
void allowedHosts;
|
|
1037
|
+
|
|
1038
|
+
// F-slice-2-06: pass BOTH the typed spelling and the realpath
|
|
1039
|
+
// spelling of the project root so a path expressed either way
|
|
1040
|
+
// (e.g. /tmp/foo vs /private/tmp/foo on macOS) is stripped.
|
|
1041
|
+
const rootSpellings = [projectRoot];
|
|
1042
|
+
try {
|
|
1043
|
+
const real = await realpath(projectRoot);
|
|
1044
|
+
if (real && real !== projectRoot) rootSpellings.push(real);
|
|
1045
|
+
} catch { /* absent is fine */ }
|
|
1046
|
+
|
|
1047
|
+
return {
|
|
1048
|
+
projectRoot: rootSpellings,
|
|
1049
|
+
projectName,
|
|
1050
|
+
operatorName,
|
|
1051
|
+
gitRemote: [...remotes].filter((r) => typeof r === 'string' && r.length > 0),
|
|
1052
|
+
allowHosts: allowHostsExt,
|
|
1053
|
+
};
|
|
1054
|
+
}
|
|
1055
|
+
|
|
1056
|
+
/**
|
|
1057
|
+
* Load the resolver's read-only inputs (manifest, registry) once per
|
|
1058
|
+
* preview call so a batch of entries all consult the same on-disk
|
|
1059
|
+
* state. Best-effort: a missing manifest or registry file falls back
|
|
1060
|
+
* to empty shapes, which the resolver treats as "unresolved" for
|
|
1061
|
+
* blueprint entries and "core" for core entries.
|
|
1062
|
+
*
|
|
1063
|
+
* @param {string} projectRoot
|
|
1064
|
+
* @returns {Promise<{ manifest: object | null, registry: object | null }>}
|
|
1065
|
+
*/
|
|
1066
|
+
async function loadResolverInputs(projectRoot) {
|
|
1067
|
+
let manifest = null;
|
|
1068
|
+
try {
|
|
1069
|
+
const raw = await readFile(resolve(projectRoot, 'rcf', 'manifest.json'), 'utf8');
|
|
1070
|
+
manifest = JSON.parse(raw);
|
|
1071
|
+
} catch { /* absent is fine */ }
|
|
1072
|
+
const registry = await readLibraryRegistry(projectRoot);
|
|
1073
|
+
// readLibraryRegistry returns an rcfError object on parse failure;
|
|
1074
|
+
// preview should not blow up on a broken registry. Treat that shape
|
|
1075
|
+
// as "no registry", so blueprint entries fall through to unresolved
|
|
1076
|
+
// rather than crashing.
|
|
1077
|
+
const usableRegistry = (registry && typeof registry === 'object' && 'kind' in registry)
|
|
1078
|
+
? { libraries: [] }
|
|
1079
|
+
: registry;
|
|
1080
|
+
return { manifest, registry: usableRegistry };
|
|
1081
|
+
}
|
|
1082
|
+
|
|
1083
|
+
/**
|
|
1084
|
+
* Build one preview record for `--json` output and for the text
|
|
1085
|
+
* renderer. Uses the destination resolver (slice 3) so the destination
|
|
1086
|
+
* shape now matches the design 3.3 walk.
|
|
1087
|
+
*
|
|
1088
|
+
* @param {object} entry
|
|
1089
|
+
* @param {import('../feedback/redact.js').RedactionContext} context
|
|
1090
|
+
* @param {{ manifest: object | null, registry: object | null }} resolverInputs
|
|
1091
|
+
* @returns {Promise<object>}
|
|
1092
|
+
*/
|
|
1093
|
+
async function buildPreview(entry, context, resolverInputs) {
|
|
1094
|
+
const titleRes = redact(entry.title ?? '', context);
|
|
1095
|
+
const bodyRes = redact(entry.body ?? '', context);
|
|
1096
|
+
const evidenceRedacted = (entry.evidence ?? []).map((ev) => {
|
|
1097
|
+
const r = redact(ev.value ?? '', context);
|
|
1098
|
+
return { kind: ev.kind, value: r.text, ledger: r.ledger };
|
|
1099
|
+
});
|
|
1100
|
+
const combinedLedger = mergeLedger([titleRes.ledger, bodyRes.ledger, ...evidenceRedacted.map((e) => e.ledger)]);
|
|
1101
|
+
const fp = fingerprint(entry);
|
|
1102
|
+
const destination = await resolveDestination(entry, resolverInputs);
|
|
1103
|
+
const rendered = renderIssue(entry, {
|
|
1104
|
+
title: titleRes.text,
|
|
1105
|
+
body: bodyRes.text,
|
|
1106
|
+
evidence: evidenceRedacted.map((e) => ({ kind: e.kind, value: e.value })),
|
|
1107
|
+
ledger: combinedLedger,
|
|
1108
|
+
}, { fingerprint: fp, destination });
|
|
1109
|
+
// F-slice-2-08: preview must run the residual pass over the
|
|
1110
|
+
// RENDERED body (which inlines evidence values) so an evidence
|
|
1111
|
+
// pointer carrying a residual secret is called out at preview
|
|
1112
|
+
// time, not silently landed in the issue. Also merge evidence
|
|
1113
|
+
// residuals from the per-field pass so the operator sees where
|
|
1114
|
+
// each hit came from.
|
|
1115
|
+
const evidenceResidual = evidenceRedacted.flatMap((e) => findResidualSecrets(String(e.value ?? '')));
|
|
1116
|
+
const renderedResidual = findResidualSecrets(rendered.body);
|
|
1117
|
+
const residual = dedupeResidual([
|
|
1118
|
+
...titleRes.residual,
|
|
1119
|
+
...bodyRes.residual,
|
|
1120
|
+
...evidenceResidual,
|
|
1121
|
+
...renderedResidual,
|
|
1122
|
+
]);
|
|
1123
|
+
return {
|
|
1124
|
+
id: entry.id,
|
|
1125
|
+
fingerprint: fp,
|
|
1126
|
+
fingerprintFallback: entry.anchor == null || String(entry.anchor).trim() === '',
|
|
1127
|
+
destination,
|
|
1128
|
+
titleRendered: rendered.title,
|
|
1129
|
+
bodyRendered: rendered.body,
|
|
1130
|
+
labels: rendered.labels,
|
|
1131
|
+
ledger: combinedLedger,
|
|
1132
|
+
residual,
|
|
1133
|
+
};
|
|
1134
|
+
}
|
|
1135
|
+
|
|
1136
|
+
/**
|
|
1137
|
+
* Dedupe residual-hit rows on (pattern, line, snippet) so a hit found
|
|
1138
|
+
* both in an evidence pass and again in the rendered body does not
|
|
1139
|
+
* double-count in the preview surface.
|
|
1140
|
+
*
|
|
1141
|
+
* @param {Array<{line: number, snippet: string, pattern: string}>} hits
|
|
1142
|
+
*/
|
|
1143
|
+
function dedupeResidual(hits) {
|
|
1144
|
+
const seen = new Set();
|
|
1145
|
+
const out = [];
|
|
1146
|
+
for (const h of hits) {
|
|
1147
|
+
const key = `${h.pattern}|${h.line}|${h.snippet}`;
|
|
1148
|
+
if (seen.has(key)) continue;
|
|
1149
|
+
seen.add(key);
|
|
1150
|
+
out.push(h);
|
|
1151
|
+
}
|
|
1152
|
+
return out;
|
|
1153
|
+
}
|
|
1154
|
+
|
|
1155
|
+
/**
|
|
1156
|
+
* Fold ledgers from several redact() calls into one. Rows are grouped
|
|
1157
|
+
* by (rule, before) so distinct samples of the same rule survive the
|
|
1158
|
+
* merge into the preview surface (F-slice-2-09): the redactor already
|
|
1159
|
+
* keeps one row per distinct before-sample; if this fold then collapsed
|
|
1160
|
+
* everything under a rule name to a single row, the operator would see
|
|
1161
|
+
* only one out of many stripped values. Counts sum within a (rule,
|
|
1162
|
+
* before) group. Ordering is first-seen so the preview reads in the
|
|
1163
|
+
* order rules fired.
|
|
1164
|
+
*
|
|
1165
|
+
* @param {Array<Array<{ rule: string, before: string, after: string, count: number }>>} ledgers
|
|
1166
|
+
* @returns {Array<{ rule: string, before: string, after: string, count: number }>}
|
|
1167
|
+
*/
|
|
1168
|
+
function mergeLedger(ledgers) {
|
|
1169
|
+
const byKey = new Map();
|
|
1170
|
+
const order = [];
|
|
1171
|
+
for (const ledger of ledgers) {
|
|
1172
|
+
for (const row of ledger) {
|
|
1173
|
+
const key = `${row.rule}|${row.before}`;
|
|
1174
|
+
if (!byKey.has(key)) {
|
|
1175
|
+
order.push(key);
|
|
1176
|
+
byKey.set(key, { rule: row.rule, before: row.before, after: row.after, count: row.count });
|
|
1177
|
+
} else {
|
|
1178
|
+
byKey.get(key).count += row.count;
|
|
1179
|
+
}
|
|
1180
|
+
}
|
|
1181
|
+
}
|
|
1182
|
+
return order.map((k) => byKey.get(k));
|
|
1183
|
+
}
|
|
1184
|
+
|
|
1185
|
+
// -- submit (slice 4, FBS-183) --------------------------------------------
|
|
1186
|
+
|
|
1187
|
+
const SUBMIT_OPTIONS = /** @type {const} */ ({
|
|
1188
|
+
yes: { type: 'boolean' },
|
|
1189
|
+
'dry-run': { type: 'boolean' },
|
|
1190
|
+
'no-preview': { type: 'boolean' },
|
|
1191
|
+
help: { type: 'boolean' },
|
|
1192
|
+
});
|
|
1193
|
+
|
|
1194
|
+
/**
|
|
1195
|
+
* `rcf feedback submit`: file each pending entry (or those named by
|
|
1196
|
+
* positional id) under the reporter's ambient gh login. Refuses
|
|
1197
|
+
* without `--yes` on a non-TTY (design section 9's consent contract);
|
|
1198
|
+
* on a TTY the sub-verb prompts once. `--dry-run` runs the preflight
|
|
1199
|
+
* and dedupe search and prints the plan without any create/comment.
|
|
1200
|
+
*
|
|
1201
|
+
* Preflight order (per destination): gh on PATH -> gh auth status ->
|
|
1202
|
+
* gh repo view (visibility + viewerPermission + hasIssuesEnabled).
|
|
1203
|
+
* First failure routes that destination's entries to a bundle. The
|
|
1204
|
+
* unresolved-destination case (destination.resolve returned unresolved)
|
|
1205
|
+
* bundles directly with no gh calls for those entries (AC-16001-4).
|
|
1206
|
+
*
|
|
1207
|
+
* Dedupe (per entry passing preflight): gh search issues on the
|
|
1208
|
+
* destination for `rcf-feedback-fingerprint: <fp>` (open, in:body,
|
|
1209
|
+
* limit 5). Zero hits -> create. One hit -> +1 comment. Many hits ->
|
|
1210
|
+
* comment on the lowest number and mention the others. Search failure
|
|
1211
|
+
* -> create with dedupe:unchecked. Closed search runs only after a
|
|
1212
|
+
* zero-hit open search so the create body can reference the prior
|
|
1213
|
+
* number.
|
|
1214
|
+
*
|
|
1215
|
+
* Create/comment failure (network/4xx/5xx/ratelimit or unexpected
|
|
1216
|
+
* label rejection): retry once WITHOUT labels; still failing, bundle
|
|
1217
|
+
* that entry only. Exit 0 when every entry ended submitted or
|
|
1218
|
+
* bundled; exit 3 when a residual secret leaves one pending.
|
|
1219
|
+
*
|
|
1220
|
+
* @param {string[]} argv
|
|
1221
|
+
* @param {object} ctx
|
|
1222
|
+
* @returns {Promise<number>}
|
|
1223
|
+
*/
|
|
1224
|
+
async function handleSubmit(argv, ctx) {
|
|
1225
|
+
const { stdout, stderr, cwd, env, now, sessionId } = ctx;
|
|
1226
|
+
let parsed;
|
|
1227
|
+
try {
|
|
1228
|
+
parsed = parseArgs({ args: argv, options: SUBMIT_OPTIONS, allowPositionals: true, strict: true });
|
|
1229
|
+
} catch (err) {
|
|
1230
|
+
stderr.write(`[error] usage ${err.message}\n`);
|
|
1231
|
+
return 2;
|
|
1232
|
+
}
|
|
1233
|
+
const flags = parsed.values;
|
|
1234
|
+
if (flags.help) { stdout.write(HELP); return 0; }
|
|
1235
|
+
|
|
1236
|
+
const projectRoot = await findProjectRoot(cwd);
|
|
1237
|
+
if (!projectRoot) {
|
|
1238
|
+
stderr.write('[error] usage no project root found (no rcf/manifest.json in this directory or any ancestor).\n');
|
|
1239
|
+
return 2;
|
|
1240
|
+
}
|
|
1241
|
+
|
|
1242
|
+
// Consent gate: --yes is required unless stdin is a TTY and the
|
|
1243
|
+
// user answers y. In practice the agent always passes --yes after
|
|
1244
|
+
// the operator said yes in conversation; the flag is the contract
|
|
1245
|
+
// that a human answered. AC-15901-2 asserts the non-TTY branch.
|
|
1246
|
+
if (!flags.yes) {
|
|
1247
|
+
const stdin = process.stdin;
|
|
1248
|
+
const isTty = typeof stdin?.isTTY === 'boolean' ? stdin.isTTY : false;
|
|
1249
|
+
if (!isTty) {
|
|
1250
|
+
stderr.write('[error] usage rcf feedback submit requires --yes (or an interactive TTY where you can confirm the send).\n');
|
|
1251
|
+
return 2;
|
|
1252
|
+
}
|
|
1253
|
+
const ok = await promptForYes(stdin, stdout);
|
|
1254
|
+
if (!ok) {
|
|
1255
|
+
stdout.write('submit cancelled.\n');
|
|
1256
|
+
return 0;
|
|
1257
|
+
}
|
|
1258
|
+
}
|
|
1259
|
+
|
|
1260
|
+
const all = await readEntries(projectRoot);
|
|
1261
|
+
const pending = all.filter((e) => e.status === 'pending');
|
|
1262
|
+
const wantedIds = new Set(parsed.positionals);
|
|
1263
|
+
const entries = wantedIds.size > 0
|
|
1264
|
+
? pending.filter((e) => wantedIds.has(e.id))
|
|
1265
|
+
: pending;
|
|
1266
|
+
|
|
1267
|
+
if (wantedIds.size > 0) {
|
|
1268
|
+
const missing = [...wantedIds].filter((id) => !pending.some((e) => e.id === id));
|
|
1269
|
+
if (missing.length > 0) {
|
|
1270
|
+
stderr.write(`[error] usage unknown pending entry id(s): ${missing.join(', ')}\n`);
|
|
1271
|
+
return 2;
|
|
1272
|
+
}
|
|
1273
|
+
}
|
|
1274
|
+
|
|
1275
|
+
if (entries.length === 0) {
|
|
1276
|
+
stdout.write('no pending feedback entries to submit.\n');
|
|
1277
|
+
return 0;
|
|
1278
|
+
}
|
|
1279
|
+
|
|
1280
|
+
const context = await buildRedactionContext(projectRoot);
|
|
1281
|
+
const resolverInputs = await loadResolverInputs(projectRoot);
|
|
1282
|
+
const gh = await loadGhAdapter(env);
|
|
1283
|
+
const rcfLiteVersion = await readOwnVersion();
|
|
1284
|
+
|
|
1285
|
+
// Group entries by destination repo so the preflight (auth,
|
|
1286
|
+
// repo-view, label-list) runs once per repo, not once per entry.
|
|
1287
|
+
// Unresolved destinations get their own bucket so the case-5 path
|
|
1288
|
+
// (AC-16001-4) is a first-class fold, not a special-case.
|
|
1289
|
+
const buckets = new Map();
|
|
1290
|
+
for (const e of entries) {
|
|
1291
|
+
const destination = await resolveDestination(e, resolverInputs);
|
|
1292
|
+
const key = destination.repo ?? `__unresolved__:${destination.reason ?? 'unknown'}`;
|
|
1293
|
+
if (!buckets.has(key)) buckets.set(key, { destination, entries: [] });
|
|
1294
|
+
buckets.get(key).entries.push(e);
|
|
1295
|
+
}
|
|
1296
|
+
|
|
1297
|
+
// Preflight once per bucket; per-destination results feed the
|
|
1298
|
+
// per-entry submit loop.
|
|
1299
|
+
const preflightCache = new Map();
|
|
1300
|
+
for (const [key, bucket] of buckets) {
|
|
1301
|
+
if (bucket.destination.visibility === 'unresolved') {
|
|
1302
|
+
preflightCache.set(key, { ok: false, reason: 'unresolved-destination', bucket: true });
|
|
1303
|
+
} else {
|
|
1304
|
+
preflightCache.set(key, await runPreflight(bucket.destination, gh));
|
|
1305
|
+
}
|
|
1306
|
+
}
|
|
1307
|
+
|
|
1308
|
+
const summary = {
|
|
1309
|
+
submitted: 0,
|
|
1310
|
+
bundled: 0,
|
|
1311
|
+
pending: 0,
|
|
1312
|
+
};
|
|
1313
|
+
const bundleRowsByKey = new Map();
|
|
1314
|
+
|
|
1315
|
+
for (const [key, bucket] of buckets) {
|
|
1316
|
+
const destination = bucket.destination;
|
|
1317
|
+
const pre = preflightCache.get(key);
|
|
1318
|
+
|
|
1319
|
+
if (!pre.ok && pre.bucket === true) {
|
|
1320
|
+
// Whole-destination fallback: build one bundle file for every
|
|
1321
|
+
// entry in this bucket; the message is the preflight reason.
|
|
1322
|
+
const rows = [];
|
|
1323
|
+
for (const e of bucket.entries) {
|
|
1324
|
+
const built = await buildEntryPayload(e, context, rcfLiteVersion);
|
|
1325
|
+
if (built.residual.length > 0) {
|
|
1326
|
+
await markResidual(projectRoot, e.id, at(now), sessionId);
|
|
1327
|
+
stdout.write(`${e.id} -> pending (residual secret in body; run \`rcf feedback preview\` and rewrite)\n`);
|
|
1328
|
+
summary.pending += 1;
|
|
1329
|
+
continue;
|
|
1330
|
+
}
|
|
1331
|
+
rows.push({ entry: e, redacted: built.redacted, fingerprint: built.fingerprint });
|
|
1332
|
+
}
|
|
1333
|
+
if (rows.length > 0) {
|
|
1334
|
+
bundleRowsByKey.set(key, { destination, rows, reason: pre.message });
|
|
1335
|
+
}
|
|
1336
|
+
continue;
|
|
1337
|
+
}
|
|
1338
|
+
|
|
1339
|
+
for (const e of bucket.entries) {
|
|
1340
|
+
const built = await buildEntryPayload(e, context, rcfLiteVersion);
|
|
1341
|
+
if (built.residual.length > 0) {
|
|
1342
|
+
await markResidual(projectRoot, e.id, at(now), sessionId);
|
|
1343
|
+
stdout.write(`${e.id} -> pending (residual secret in body; run \`rcf feedback preview\` and rewrite)\n`);
|
|
1344
|
+
summary.pending += 1;
|
|
1345
|
+
continue;
|
|
1346
|
+
}
|
|
1347
|
+
|
|
1348
|
+
// Label pre-check per entry-repo pair. Cached on the preflight
|
|
1349
|
+
// record so the second entry against the same repo does not
|
|
1350
|
+
// re-list.
|
|
1351
|
+
if (!pre.labelsChecked) {
|
|
1352
|
+
pre.labels = await runLabelPrecheck(destination.repo, gh);
|
|
1353
|
+
pre.labelsChecked = true;
|
|
1354
|
+
}
|
|
1355
|
+
const requestedLabels = labelsForEntry(e.severity, e.kind);
|
|
1356
|
+
const availableLabels = pre.labels?.available ?? null;
|
|
1357
|
+
const usedLabels = availableLabels
|
|
1358
|
+
? requestedLabels.filter((l) => availableLabels.includes(l))
|
|
1359
|
+
: requestedLabels;
|
|
1360
|
+
const droppedLabels = availableLabels
|
|
1361
|
+
? requestedLabels.filter((l) => !availableLabels.includes(l))
|
|
1362
|
+
: [];
|
|
1363
|
+
|
|
1364
|
+
// Dedupe search on the destination (open first).
|
|
1365
|
+
const searchOpen = await gh.ghIssueSearch({
|
|
1366
|
+
repo: destination.repo,
|
|
1367
|
+
query: `rcf-feedback-fingerprint: ${built.fingerprint}`,
|
|
1368
|
+
state: 'open',
|
|
1369
|
+
limit: 5,
|
|
1370
|
+
});
|
|
1371
|
+
|
|
1372
|
+
let dedupe = 'new';
|
|
1373
|
+
let closedRef = null;
|
|
1374
|
+
let matches = [];
|
|
1375
|
+
if (!searchOpen.ok) {
|
|
1376
|
+
dedupe = 'unchecked';
|
|
1377
|
+
} else {
|
|
1378
|
+
matches = searchOpen.value?.matches ?? [];
|
|
1379
|
+
}
|
|
1380
|
+
|
|
1381
|
+
if (flags['dry-run']) {
|
|
1382
|
+
const plan = matches.length === 1
|
|
1383
|
+
? `comment on #${matches[0].number}`
|
|
1384
|
+
: matches.length > 1
|
|
1385
|
+
? `comment on #${matches.sort((a, b) => a.number - b.number)[0].number} (${matches.length} matches)`
|
|
1386
|
+
: 'create';
|
|
1387
|
+
stdout.write(`${e.id} -> dry-run ${plan} (${dedupe === 'unchecked' ? 'unchecked' : matches.length === 0 ? 'new' : 'comment'})\n`);
|
|
1388
|
+
continue;
|
|
1389
|
+
}
|
|
1390
|
+
|
|
1391
|
+
// Zero-open-hit case: check closed-hit so the create body can
|
|
1392
|
+
// reference the previously reported number.
|
|
1393
|
+
if (matches.length === 0 && dedupe !== 'unchecked') {
|
|
1394
|
+
const searchClosed = await gh.ghIssueSearch({
|
|
1395
|
+
repo: destination.repo,
|
|
1396
|
+
query: `rcf-feedback-fingerprint: ${built.fingerprint}`,
|
|
1397
|
+
state: 'closed',
|
|
1398
|
+
limit: 1,
|
|
1399
|
+
});
|
|
1400
|
+
if (searchClosed.ok && (searchClosed.value?.matches ?? []).length > 0) {
|
|
1401
|
+
closedRef = searchClosed.value.matches[0].number;
|
|
1402
|
+
}
|
|
1403
|
+
}
|
|
1404
|
+
|
|
1405
|
+
let result;
|
|
1406
|
+
if (matches.length === 0) {
|
|
1407
|
+
// Create.
|
|
1408
|
+
let createBody = built.rendered.body;
|
|
1409
|
+
if (closedRef) {
|
|
1410
|
+
createBody = `${createBody}\nPreviously reported and closed as #${closedRef}.\n`;
|
|
1411
|
+
}
|
|
1412
|
+
result = await createWithRetry(gh, {
|
|
1413
|
+
repo: destination.repo,
|
|
1414
|
+
title: built.rendered.title,
|
|
1415
|
+
body: createBody,
|
|
1416
|
+
labels: usedLabels,
|
|
1417
|
+
});
|
|
1418
|
+
} else if (matches.length === 1) {
|
|
1419
|
+
// Comment.
|
|
1420
|
+
dedupe = 'comment';
|
|
1421
|
+
const commentBody = renderComment(e, {
|
|
1422
|
+
body: built.redacted.body,
|
|
1423
|
+
ledger: built.redacted.ledger,
|
|
1424
|
+
}, { fingerprint: built.fingerprint, includeBody: false }).body;
|
|
1425
|
+
result = await commentWithRetry(gh, {
|
|
1426
|
+
repo: destination.repo,
|
|
1427
|
+
number: matches[0].number,
|
|
1428
|
+
body: commentBody,
|
|
1429
|
+
});
|
|
1430
|
+
} else {
|
|
1431
|
+
// Many: comment on lowest, mention the others.
|
|
1432
|
+
dedupe = 'comment';
|
|
1433
|
+
const sorted = matches.slice().sort((a, b) => a.number - b.number);
|
|
1434
|
+
const others = sorted.slice(1).map((m) => `#${m.number}`).join(', ');
|
|
1435
|
+
const base = renderComment(e, {
|
|
1436
|
+
body: built.redacted.body,
|
|
1437
|
+
ledger: built.redacted.ledger,
|
|
1438
|
+
}, { fingerprint: built.fingerprint, includeBody: false }).body;
|
|
1439
|
+
const commentBody = `${base}\nalso see ${others}\n`;
|
|
1440
|
+
result = await commentWithRetry(gh, {
|
|
1441
|
+
repo: destination.repo,
|
|
1442
|
+
number: sorted[0].number,
|
|
1443
|
+
body: commentBody,
|
|
1444
|
+
});
|
|
1445
|
+
}
|
|
1446
|
+
|
|
1447
|
+
if (result.ok) {
|
|
1448
|
+
await appendState(projectRoot, {
|
|
1449
|
+
id: e.id,
|
|
1450
|
+
at: at(now),
|
|
1451
|
+
status: 'submitted',
|
|
1452
|
+
issueUrl: result.url,
|
|
1453
|
+
dedupe,
|
|
1454
|
+
droppedLabels,
|
|
1455
|
+
sessionId,
|
|
1456
|
+
});
|
|
1457
|
+
stdout.write(`${e.id} -> ${result.url} (${dedupe})\n`);
|
|
1458
|
+
summary.submitted += 1;
|
|
1459
|
+
} else {
|
|
1460
|
+
// Retry-without-labels failed too: bundle this one entry.
|
|
1461
|
+
const rows = bundleRowsByKey.get(`__perentry__:${e.id}`)?.rows ?? [];
|
|
1462
|
+
rows.push({ entry: e, redacted: built.redacted, fingerprint: built.fingerprint });
|
|
1463
|
+
bundleRowsByKey.set(`__perentry__:${e.id}`, {
|
|
1464
|
+
destination,
|
|
1465
|
+
rows,
|
|
1466
|
+
reason: `create/comment failed: ${result.reason}`,
|
|
1467
|
+
});
|
|
1468
|
+
}
|
|
1469
|
+
}
|
|
1470
|
+
}
|
|
1471
|
+
|
|
1472
|
+
// Write bundle files (whole-destination and per-entry).
|
|
1473
|
+
const generatedAt = now().toISOString().replace(/\.\d{3}Z$/, 'Z');
|
|
1474
|
+
for (const [key, bundle] of bundleRowsByKey) {
|
|
1475
|
+
// Round 4 (F-01, design R3c): `submit --dry-run` writes nothing
|
|
1476
|
+
// under `.rcf/feedback/`, including outbox bundles for the
|
|
1477
|
+
// unresolved-destination and whole-destination-fallback branches.
|
|
1478
|
+
// Previously the dry-run gate on the create/comment path (L1340)
|
|
1479
|
+
// let the bundle write path run unconditionally, so an
|
|
1480
|
+
// `unresolved` entry produced a real outbox file on a dry-run.
|
|
1481
|
+
if (flags['dry-run']) {
|
|
1482
|
+
const issuesUrl = bundle.destination.repo
|
|
1483
|
+
? `https://github.com/${bundle.destination.repo}/issues/new`
|
|
1484
|
+
: '(no repo; paste to the library owner)';
|
|
1485
|
+
const contactLine = bundle.destination.publisherContact
|
|
1486
|
+
? ` (contact: ${bundle.destination.publisherContact})`
|
|
1487
|
+
: '';
|
|
1488
|
+
stdout.write(`${bundle.rows.map((r) => r.entry.id).join(', ')} -> dry-run bundle ${issuesUrl}${contactLine}\n`);
|
|
1489
|
+
continue;
|
|
1490
|
+
}
|
|
1491
|
+
let outboxPath;
|
|
1492
|
+
try {
|
|
1493
|
+
outboxPath = await writeBundle(projectRoot, bundle.destination, bundle.rows, {
|
|
1494
|
+
generatedAt,
|
|
1495
|
+
rcfLiteVersion,
|
|
1496
|
+
reasonNotFiled: bundle.reason,
|
|
1497
|
+
});
|
|
1498
|
+
} catch (err) {
|
|
1499
|
+
// Round 3 (AC-15601-4 regression): writeBundle throws
|
|
1500
|
+
// FEEDBACK_BUNDLE_RESIDUAL when the safeguard's whole-bundle
|
|
1501
|
+
// residual scan bites. The uncaught throw propagated all the
|
|
1502
|
+
// way to the dispatcher and turned the exit code into 1; the
|
|
1503
|
+
// documented shape is exit 3 (at least one entry pending),
|
|
1504
|
+
// matching the per-entry residual path. Catch it here, keep
|
|
1505
|
+
// every bundle row PENDING with residual:true, and let
|
|
1506
|
+
// `summary.pending > 0 ? 3 : 0` return the 3.
|
|
1507
|
+
if (/** @type {any} */ (err)?.code === 'FEEDBACK_BUNDLE_RESIDUAL') {
|
|
1508
|
+
stdout.write(`${bundle.rows.map((r) => r.entry.id).join(', ')} -> pending (bundle-level residual secret; run \`rcf feedback preview\` and rewrite before submit)\n`);
|
|
1509
|
+
stderr.write(`[safeguard] ${err.message}\n`);
|
|
1510
|
+
for (const row of bundle.rows) {
|
|
1511
|
+
await markResidual(projectRoot, row.entry.id, at(now), sessionId);
|
|
1512
|
+
summary.pending += 1;
|
|
1513
|
+
}
|
|
1514
|
+
continue;
|
|
1515
|
+
}
|
|
1516
|
+
throw err;
|
|
1517
|
+
}
|
|
1518
|
+
const issuesUrl = bundle.destination.repo
|
|
1519
|
+
? `https://github.com/${bundle.destination.repo}/issues/new`
|
|
1520
|
+
: '(no repo; paste to the library owner)';
|
|
1521
|
+
const contactLine = bundle.destination.publisherContact
|
|
1522
|
+
? ` (contact: ${bundle.destination.publisherContact})`
|
|
1523
|
+
: '';
|
|
1524
|
+
stdout.write(`${bundle.rows.map((r) => r.entry.id).join(', ')} -> bundle ${outboxPath} | ${issuesUrl}${contactLine}\n`);
|
|
1525
|
+
for (const row of bundle.rows) {
|
|
1526
|
+
await appendState(projectRoot, {
|
|
1527
|
+
id: row.entry.id,
|
|
1528
|
+
at: at(now),
|
|
1529
|
+
status: 'bundled',
|
|
1530
|
+
outboxPath,
|
|
1531
|
+
reason: bundle.reason,
|
|
1532
|
+
sessionId,
|
|
1533
|
+
});
|
|
1534
|
+
summary.bundled += 1;
|
|
1535
|
+
}
|
|
1536
|
+
}
|
|
1537
|
+
|
|
1538
|
+
return summary.pending > 0 ? 3 : 0;
|
|
1539
|
+
}
|
|
1540
|
+
|
|
1541
|
+
/**
|
|
1542
|
+
* Read up to a single line of yes/no from stdin (blocking one-shot).
|
|
1543
|
+
* Returns true only for `y` or `yes` (case-insensitive).
|
|
1544
|
+
*
|
|
1545
|
+
* @param {NodeJS.ReadStream} stdin
|
|
1546
|
+
* @param {NodeJS.WritableStream} stdout
|
|
1547
|
+
* @returns {Promise<boolean>}
|
|
1548
|
+
*/
|
|
1549
|
+
async function promptForYes(stdin, stdout) {
|
|
1550
|
+
stdout.write('submit each pending entry under your ambient gh login? [y/N] ');
|
|
1551
|
+
return new Promise((resolvePromise) => {
|
|
1552
|
+
let buf = '';
|
|
1553
|
+
const onData = (chunk) => {
|
|
1554
|
+
buf += chunk.toString('utf8');
|
|
1555
|
+
const nl = buf.indexOf('\n');
|
|
1556
|
+
if (nl >= 0) {
|
|
1557
|
+
stdin.off('data', onData);
|
|
1558
|
+
try { stdin.pause(); } catch { /* ignore */ }
|
|
1559
|
+
const answer = buf.slice(0, nl).trim().toLowerCase();
|
|
1560
|
+
resolvePromise(answer === 'y' || answer === 'yes');
|
|
1561
|
+
}
|
|
1562
|
+
};
|
|
1563
|
+
stdin.on('data', onData);
|
|
1564
|
+
try { stdin.resume(); } catch { /* ignore */ }
|
|
1565
|
+
});
|
|
1566
|
+
}
|
|
1567
|
+
|
|
1568
|
+
/**
|
|
1569
|
+
* Build the redacted body/title and the rendered issue payload for
|
|
1570
|
+
* one entry. Records residual-secret markers on the returned object
|
|
1571
|
+
* so the caller can refuse the entry.
|
|
1572
|
+
*
|
|
1573
|
+
* @param {object} entry
|
|
1574
|
+
* @param {import('../feedback/redact.js').RedactionContext} context
|
|
1575
|
+
* @param {string} rcfLiteVersion
|
|
1576
|
+
*/
|
|
1577
|
+
async function buildEntryPayload(entry, context, rcfLiteVersion) {
|
|
1578
|
+
const titleRes = redact(entry.title ?? '', context);
|
|
1579
|
+
const bodyRes = redact(entry.body ?? '', context);
|
|
1580
|
+
const evidenceRedacted = (entry.evidence ?? []).map((ev) => {
|
|
1581
|
+
const r = redact(ev.value ?? '', context);
|
|
1582
|
+
return { kind: ev.kind, value: r.text, ledger: r.ledger };
|
|
1583
|
+
});
|
|
1584
|
+
const ledger = mergeLedger([titleRes.ledger, bodyRes.ledger, ...evidenceRedacted.map((e) => e.ledger)]);
|
|
1585
|
+
const fp = fingerprint(entry);
|
|
1586
|
+
// A destination shape the render helper accepts; the submit path
|
|
1587
|
+
// does not use bundle-specific fields on rendered issues.
|
|
1588
|
+
const rendered = renderIssue(entry, {
|
|
1589
|
+
title: titleRes.text,
|
|
1590
|
+
body: bodyRes.text,
|
|
1591
|
+
evidence: evidenceRedacted.map((e) => ({ kind: e.kind, value: e.value })),
|
|
1592
|
+
ledger,
|
|
1593
|
+
}, { fingerprint: fp, destination: { repo: null, visibility: 'unresolved' } });
|
|
1594
|
+
const residual = [
|
|
1595
|
+
...titleRes.residual,
|
|
1596
|
+
...bodyRes.residual,
|
|
1597
|
+
...findResidualSecrets(rendered.body),
|
|
1598
|
+
];
|
|
1599
|
+
void rcfLiteVersion;
|
|
1600
|
+
return {
|
|
1601
|
+
fingerprint: fp,
|
|
1602
|
+
redacted: {
|
|
1603
|
+
title: titleRes.text,
|
|
1604
|
+
body: bodyRes.text,
|
|
1605
|
+
evidence: evidenceRedacted.map((e) => ({ kind: e.kind, value: e.value })),
|
|
1606
|
+
ledger,
|
|
1607
|
+
},
|
|
1608
|
+
rendered,
|
|
1609
|
+
residual,
|
|
1610
|
+
};
|
|
1611
|
+
}
|
|
1612
|
+
|
|
1613
|
+
/**
|
|
1614
|
+
* Preflight one destination repo. Records the classified reason on
|
|
1615
|
+
* failure so the bundle message can name it.
|
|
1616
|
+
*
|
|
1617
|
+
* @param {object} destination
|
|
1618
|
+
* @param {import('../feedback/gh.js').GhAdapter} gh
|
|
1619
|
+
*/
|
|
1620
|
+
async function runPreflight(destination, gh) {
|
|
1621
|
+
// (1) gh on PATH.
|
|
1622
|
+
const path = await gh.ghOnPath();
|
|
1623
|
+
if (!path.ok || (path.ok && path.value?.present === false)) {
|
|
1624
|
+
return {
|
|
1625
|
+
ok: false,
|
|
1626
|
+
bucket: true,
|
|
1627
|
+
reason: 'gh-missing',
|
|
1628
|
+
message: 'gh not on PATH; install from https://cli.github.com',
|
|
1629
|
+
};
|
|
1630
|
+
}
|
|
1631
|
+
// (2) gh auth status.
|
|
1632
|
+
const auth = await gh.ghAuthStatus({ host: 'github.com' });
|
|
1633
|
+
if (!auth.ok) {
|
|
1634
|
+
return {
|
|
1635
|
+
ok: false,
|
|
1636
|
+
bucket: true,
|
|
1637
|
+
reason: 'gh-auth',
|
|
1638
|
+
message: 'gh is not logged in; run `gh auth login`',
|
|
1639
|
+
};
|
|
1640
|
+
}
|
|
1641
|
+
// (3) repo access, visibility, hasIssuesEnabled.
|
|
1642
|
+
const view = await gh.ghRepoView({ repo: destination.repo });
|
|
1643
|
+
if (!view.ok) {
|
|
1644
|
+
return {
|
|
1645
|
+
ok: false,
|
|
1646
|
+
bucket: true,
|
|
1647
|
+
reason: 'repo-unreachable',
|
|
1648
|
+
message: `cannot reach ${destination.repo}: ${view.message}`,
|
|
1649
|
+
};
|
|
1650
|
+
}
|
|
1651
|
+
const v = view.value;
|
|
1652
|
+
const isPrivate = (v?.visibility && String(v.visibility).toLowerCase() === 'private')
|
|
1653
|
+
|| destination.visibility === 'private';
|
|
1654
|
+
if (isPrivate && (v?.viewerPermission === null || v?.viewerPermission === undefined || String(v.viewerPermission).toUpperCase() === 'NONE')) {
|
|
1655
|
+
const contact = destination.publisherContact ? ` (library contact: ${destination.publisherContact})` : '';
|
|
1656
|
+
return {
|
|
1657
|
+
ok: false,
|
|
1658
|
+
bucket: true,
|
|
1659
|
+
reason: 'private-no-access',
|
|
1660
|
+
message: `no access to private repo ${destination.repo}${contact}`,
|
|
1661
|
+
};
|
|
1662
|
+
}
|
|
1663
|
+
if (v?.hasIssuesEnabled === false) {
|
|
1664
|
+
return {
|
|
1665
|
+
ok: false,
|
|
1666
|
+
bucket: true,
|
|
1667
|
+
reason: 'issues-disabled',
|
|
1668
|
+
message: `issues are disabled on ${destination.repo}`,
|
|
1669
|
+
};
|
|
1670
|
+
}
|
|
1671
|
+
return { ok: true, view: v };
|
|
1672
|
+
}
|
|
1673
|
+
|
|
1674
|
+
/**
|
|
1675
|
+
* Label pre-check: list labels on the destination once and cache the
|
|
1676
|
+
* `available` set of the requested six (any not-present label is
|
|
1677
|
+
* dropped). A gh label list failure returns null available so the
|
|
1678
|
+
* submit path proceeds with the requested labels (best-effort per
|
|
1679
|
+
* design section 4.3 note).
|
|
1680
|
+
*
|
|
1681
|
+
* @param {string} repo
|
|
1682
|
+
* @param {import('../feedback/gh.js').GhAdapter} gh
|
|
1683
|
+
*/
|
|
1684
|
+
async function runLabelPrecheck(repo, gh) {
|
|
1685
|
+
const r = await gh.ghLabelList({ repo });
|
|
1686
|
+
if (!r.ok) return { available: null };
|
|
1687
|
+
const names = r.value?.names ?? [];
|
|
1688
|
+
return { available: names };
|
|
1689
|
+
}
|
|
1690
|
+
|
|
1691
|
+
async function createWithRetry(gh, opts) {
|
|
1692
|
+
const first = await gh.ghIssueCreate(opts);
|
|
1693
|
+
if (first.ok) return { ok: true, url: first.value.url, number: first.value.number };
|
|
1694
|
+
// Retry once without labels.
|
|
1695
|
+
const second = await gh.ghIssueCreate({ ...opts, labels: [] });
|
|
1696
|
+
if (second.ok) return { ok: true, url: second.value.url, number: second.value.number };
|
|
1697
|
+
return { ok: false, reason: second.message };
|
|
1698
|
+
}
|
|
1699
|
+
|
|
1700
|
+
async function commentWithRetry(gh, opts) {
|
|
1701
|
+
const first = await gh.ghIssueComment(opts);
|
|
1702
|
+
if (first.ok) return { ok: true, url: first.value.url };
|
|
1703
|
+
const second = await gh.ghIssueComment(opts);
|
|
1704
|
+
if (second.ok) return { ok: true, url: second.value.url };
|
|
1705
|
+
return { ok: false, reason: second.message };
|
|
1706
|
+
}
|
|
1707
|
+
|
|
1708
|
+
/**
|
|
1709
|
+
* Write one bundle file under `.rcf/feedback/outbox/`. Filename shape:
|
|
1710
|
+
* `<ISO-timestamp>-<repo-slug>.md`; unresolved destinations use
|
|
1711
|
+
* `<ISO-timestamp>-unresolved.md`. Returns the absolute path.
|
|
1712
|
+
*
|
|
1713
|
+
* @param {string} projectRoot
|
|
1714
|
+
* @param {object} destination
|
|
1715
|
+
* @param {Array<{ entry: object, redacted: object, fingerprint: string }>} rows
|
|
1716
|
+
* @param {{ generatedAt: string, rcfLiteVersion: string, reasonNotFiled?: string }} meta
|
|
1717
|
+
* @returns {Promise<string>}
|
|
1718
|
+
*/
|
|
1719
|
+
async function writeBundle(projectRoot, destination, rows, meta) {
|
|
1720
|
+
const dir = outboxDir(projectRoot);
|
|
1721
|
+
await mkdir(dir, { recursive: true });
|
|
1722
|
+
const stampSafe = meta.generatedAt.replace(/[:]/g, '-');
|
|
1723
|
+
const slug = destination.repo
|
|
1724
|
+
? destination.repo.replace(/[^A-Za-z0-9._-]+/g, '-').toLowerCase()
|
|
1725
|
+
: 'unresolved';
|
|
1726
|
+
// A per-entry fallback bundle (retry-then-fail) uses the entry id as
|
|
1727
|
+
// a disambiguator so two fallbacks in the same second do not
|
|
1728
|
+
// overwrite each other. A whole-destination bundle keeps the base
|
|
1729
|
+
// filename shape.
|
|
1730
|
+
const tail = rows.length === 1 ? `-${rows[0].entry.id}` : '';
|
|
1731
|
+
const filename = `${stampSafe}-${slug}${tail}.md`;
|
|
1732
|
+
const path = resolve(dir, filename);
|
|
1733
|
+
const bundleDestination = {
|
|
1734
|
+
repo: destination.repo,
|
|
1735
|
+
visibility: destination.visibility === 'private' ? 'private' : (destination.repo ? 'public' : 'unresolved'),
|
|
1736
|
+
reasonNotFiled: meta.reasonNotFiled,
|
|
1737
|
+
libraryContact: destination.publisherContact,
|
|
1738
|
+
};
|
|
1739
|
+
const text = renderBundle(bundleDestination, rows, {
|
|
1740
|
+
generatedAt: meta.generatedAt,
|
|
1741
|
+
rcfLiteVersion: meta.rcfLiteVersion,
|
|
1742
|
+
});
|
|
1743
|
+
// Design safeguard (fix round 2, AC-15601-4): a final whole-text
|
|
1744
|
+
// residual-secret pass over the fully assembled and normalised
|
|
1745
|
+
// bundle text. Each row's rendered body already passed the
|
|
1746
|
+
// per-entry check in buildEntryPayload, but the bundle is the
|
|
1747
|
+
// last surface before bytes hit disk; if renderBundle's header
|
|
1748
|
+
// or section framing somehow ever reintroduces a residual shape,
|
|
1749
|
+
// the write is refused with a fail-closed error rather than a
|
|
1750
|
+
// silent leak.
|
|
1751
|
+
const bundleResiduals = findResidualSecrets(text);
|
|
1752
|
+
if (bundleResiduals.length > 0) {
|
|
1753
|
+
const first = bundleResiduals[0];
|
|
1754
|
+
const err = new Error(
|
|
1755
|
+
`[safeguard] refusing to write bundle ${filename}: residual secret pattern ${first.pattern} at line ${first.line} (${bundleResiduals.length} hit${bundleResiduals.length === 1 ? '' : 's'}). `
|
|
1756
|
+
+ 'This is a defence-in-depth refusal - the per-entry residual check already runs against each rendered body; a bundle-level hit means the bundle assembly re-introduced a shape and MUST be investigated before submit is re-run.',
|
|
1757
|
+
);
|
|
1758
|
+
/** @type {any} */ (err).code = 'FEEDBACK_BUNDLE_RESIDUAL';
|
|
1759
|
+
throw err;
|
|
1760
|
+
}
|
|
1761
|
+
await writeFile(path, text, 'utf8');
|
|
1762
|
+
return path;
|
|
1763
|
+
}
|
|
1764
|
+
|
|
1765
|
+
/**
|
|
1766
|
+
* Stamp a residual-secret refusal on the entry state (kept pending).
|
|
1767
|
+
*
|
|
1768
|
+
* @param {string} projectRoot
|
|
1769
|
+
* @param {string} id
|
|
1770
|
+
* @param {string} atStamp
|
|
1771
|
+
* @param {string} sessionId
|
|
1772
|
+
*/
|
|
1773
|
+
async function markResidual(projectRoot, id, atStamp, sessionId) {
|
|
1774
|
+
await appendState(projectRoot, {
|
|
1775
|
+
id,
|
|
1776
|
+
at: atStamp,
|
|
1777
|
+
status: 'pending',
|
|
1778
|
+
residual: true,
|
|
1779
|
+
sessionId,
|
|
1780
|
+
});
|
|
1781
|
+
}
|
|
1782
|
+
|
|
1783
|
+
function at(now) {
|
|
1784
|
+
return now().toISOString().replace(/\.\d{3}Z$/, 'Z');
|
|
1785
|
+
}
|
|
1786
|
+
|
|
1787
|
+
// -- opt-in / opt-out (slice 5, FBS-184) ----------------------------------
|
|
1788
|
+
|
|
1789
|
+
const OPT_OPTIONS = /** @type {const} */ ({
|
|
1790
|
+
help: { type: 'boolean' },
|
|
1791
|
+
json: { type: 'boolean' },
|
|
1792
|
+
});
|
|
1793
|
+
|
|
1794
|
+
/**
|
|
1795
|
+
* Toggle the per-project ask via `rcf/feedback-settings.json`.
|
|
1796
|
+
* `opt-out` writes `ask: false`; `opt-in` writes `ask: true`. Other
|
|
1797
|
+
* fields (settingsVersion, quietMinutes, redaction) survive the merge
|
|
1798
|
+
* (design section 8). The env-driven silences (RCF_FEEDBACK_ASK,
|
|
1799
|
+
* RCF_FEEDBACK_DISABLE) are complementary and never toggled here.
|
|
1800
|
+
*
|
|
1801
|
+
* @param {'opt-in' | 'opt-out'} which
|
|
1802
|
+
* @param {string[]} argv
|
|
1803
|
+
* @param {object} ctx
|
|
1804
|
+
*/
|
|
1805
|
+
async function handleOptToggle(which, argv, ctx) {
|
|
1806
|
+
const { stdout, stderr, cwd } = ctx;
|
|
1807
|
+
let parsed;
|
|
1808
|
+
try {
|
|
1809
|
+
parsed = parseArgs({ args: argv, options: OPT_OPTIONS, allowPositionals: false, strict: true });
|
|
1810
|
+
} catch (err) {
|
|
1811
|
+
stderr.write(`[error] usage ${err.message}\n`);
|
|
1812
|
+
return 2;
|
|
1813
|
+
}
|
|
1814
|
+
const flags = parsed.values;
|
|
1815
|
+
if (flags.help) { stdout.write(HELP); return 0; }
|
|
1816
|
+
|
|
1817
|
+
const projectRoot = await findProjectRoot(cwd);
|
|
1818
|
+
if (!projectRoot) {
|
|
1819
|
+
stderr.write('[error] usage no project root found (no rcf/manifest.json in this directory or any ancestor).\n');
|
|
1820
|
+
return 2;
|
|
1821
|
+
}
|
|
1822
|
+
|
|
1823
|
+
const ask = which === 'opt-in';
|
|
1824
|
+
const result = await writeFeedbackSettings(projectRoot, { ask });
|
|
1825
|
+
if (flags.json) {
|
|
1826
|
+
stdout.write(`${JSON.stringify({ action: result.action, path: 'rcf/feedback-settings.json', settings: result.settings }, null, 2)}\n`);
|
|
1827
|
+
return 0;
|
|
1828
|
+
}
|
|
1829
|
+
if (result.action === 'noop') {
|
|
1830
|
+
stdout.write(`feedback ${which}: no change (rcf/feedback-settings.json already has ask: ${ask}).\n`);
|
|
1831
|
+
return 0;
|
|
1832
|
+
}
|
|
1833
|
+
const verb = result.action === 'created' ? 'wrote' : 'updated';
|
|
1834
|
+
const posture = ask
|
|
1835
|
+
? 'the harness will ask once per session at a natural pause (design 3.5).'
|
|
1836
|
+
: 'the harness will not ask on this project; add / preview / submit still work by hand.';
|
|
1837
|
+
stdout.write(`feedback ${which}: ${verb} rcf/feedback-settings.json (ask: ${ask}); ${posture}\n`);
|
|
1838
|
+
return 0;
|
|
1839
|
+
}
|
|
1840
|
+
|
|
1841
|
+
// -- hook (slice 5, FBS-184) ---------------------------------------------
|
|
1842
|
+
|
|
1843
|
+
const HOOK_OPTIONS = /** @type {const} */ ({
|
|
1844
|
+
harness: { type: 'string' },
|
|
1845
|
+
help: { type: 'boolean' },
|
|
1846
|
+
});
|
|
1847
|
+
|
|
1848
|
+
/**
|
|
1849
|
+
* Harness hook handler (design 3.5). Sub-shape:
|
|
1850
|
+
* rcf feedback hook <stop|session-end|session-start> [--harness <h>]
|
|
1851
|
+
*
|
|
1852
|
+
* Reads harness JSON from stdin (session_id, cwd, hook_event_name,
|
|
1853
|
+
* stop_hook_active, last_assistant_message on Stop) and never blocks
|
|
1854
|
+
* longer than 1 second (the 1.5s SessionEnd shared budget on Claude
|
|
1855
|
+
* Code). The store IO is small; no network is ever touched.
|
|
1856
|
+
*
|
|
1857
|
+
* Behaviour by sub-verb:
|
|
1858
|
+
* - stop: apply the quiet rule, and on 'ask' append the ledger
|
|
1859
|
+
* record BEFORE emitting so a crash between emit and reply
|
|
1860
|
+
* cannot cause a second ask; then emit per the harness.
|
|
1861
|
+
* - session-end: write a bundle of every pending entry into
|
|
1862
|
+
* `.rcf/feedback/outbox/`. Byte-idempotent: a re-run whose
|
|
1863
|
+
* rendered payload matches the last-written bundle does not
|
|
1864
|
+
* rewrite the file.
|
|
1865
|
+
* - session-start: with pending entries carried over from a
|
|
1866
|
+
* prior sessionId, print (or emit in the Codex shape) one
|
|
1867
|
+
* context line so the harness re-surfaces the ask at the next
|
|
1868
|
+
* natural pause (RULE 17). Never mutates state.json.
|
|
1869
|
+
*
|
|
1870
|
+
* @param {string[]} argv
|
|
1871
|
+
* @param {object} ctx
|
|
1872
|
+
*/
|
|
1873
|
+
async function handleHook(argv, ctx) {
|
|
1874
|
+
const { stdout, stderr, cwd, env, now, sessionId: fallbackSession } = ctx;
|
|
1875
|
+
if (argv.length === 0 || argv[0] === '--help' || argv[0] === '-h') {
|
|
1876
|
+
stdout.write(HELP);
|
|
1877
|
+
return argv.length === 0 ? 2 : 0;
|
|
1878
|
+
}
|
|
1879
|
+
const sub = argv[0];
|
|
1880
|
+
const rest = argv.slice(1);
|
|
1881
|
+
let parsed;
|
|
1882
|
+
try {
|
|
1883
|
+
parsed = parseArgs({ args: rest, options: HOOK_OPTIONS, allowPositionals: false, strict: true });
|
|
1884
|
+
} catch (err) {
|
|
1885
|
+
stderr.write(`[error] usage ${err.message}\n`);
|
|
1886
|
+
return 2;
|
|
1887
|
+
}
|
|
1888
|
+
const flags = parsed.values;
|
|
1889
|
+
if (flags.help) { stdout.write(HELP); return 0; }
|
|
1890
|
+
|
|
1891
|
+
const harness = normaliseHarness(flags.harness, env);
|
|
1892
|
+
if (harness === 'unknown') {
|
|
1893
|
+
// The hook must always know which shape to emit; refuse rather
|
|
1894
|
+
// than guess. A missing --harness on a machine without either
|
|
1895
|
+
// env signature is a configuration bug in the installer.
|
|
1896
|
+
stderr.write("[error] usage --harness required (one of 'claude-code', 'codex') when neither CLAUDECODE nor CODEX_* env is set.\n");
|
|
1897
|
+
return 2;
|
|
1898
|
+
}
|
|
1899
|
+
if (!['stop', 'session-end', 'session-start'].includes(sub)) {
|
|
1900
|
+
stderr.write(`[error] usage unknown feedback hook sub-verb '${sub}' (expected stop, session-end, session-start).\n`);
|
|
1901
|
+
return 2;
|
|
1902
|
+
}
|
|
1903
|
+
|
|
1904
|
+
const payload = await readHarnessPayload(ctx);
|
|
1905
|
+
const projectRootHint = typeof payload?.cwd === 'string' && payload.cwd.length > 0
|
|
1906
|
+
? payload.cwd
|
|
1907
|
+
: cwd;
|
|
1908
|
+
const projectRoot = await findProjectRoot(projectRootHint);
|
|
1909
|
+
if (!projectRoot) {
|
|
1910
|
+
// No project root: silently exit 0 (a hook on a non-rcf tree
|
|
1911
|
+
// must never block or shout at the user; design 3.5 says the
|
|
1912
|
+
// hook is quiet by default).
|
|
1913
|
+
return 0;
|
|
1914
|
+
}
|
|
1915
|
+
|
|
1916
|
+
const sessionIdIncoming = typeof payload?.session_id === 'string' && payload.session_id.length > 0
|
|
1917
|
+
? payload.session_id
|
|
1918
|
+
: fallbackSession;
|
|
1919
|
+
|
|
1920
|
+
if (sub === 'session-end') {
|
|
1921
|
+
return runSessionEndHook(projectRoot, { now });
|
|
1922
|
+
}
|
|
1923
|
+
if (sub === 'session-start') {
|
|
1924
|
+
return runSessionStartHook(projectRoot, harness, sessionIdIncoming, now, { stdout });
|
|
1925
|
+
}
|
|
1926
|
+
return runStopHook(projectRoot, harness, sessionIdIncoming, payload, env, now, { stdout, stderr });
|
|
1927
|
+
}
|
|
1928
|
+
|
|
1929
|
+
function normaliseHarness(flag, env) {
|
|
1930
|
+
if (flag === 'claude-code' || flag === 'codex') return flag;
|
|
1931
|
+
if (flag && flag !== '') return 'unknown';
|
|
1932
|
+
if (env.CLAUDECODE === '1') return 'claude-code';
|
|
1933
|
+
for (const k of Object.keys(env)) {
|
|
1934
|
+
if (k.startsWith('CODEX_')) return 'codex';
|
|
1935
|
+
}
|
|
1936
|
+
return 'unknown';
|
|
1937
|
+
}
|
|
1938
|
+
|
|
1939
|
+
async function readHarnessPayload(ctx) {
|
|
1940
|
+
// The wrapper trusts the caller only to supply the payload; when
|
|
1941
|
+
// driven by the harness the JSON arrives on stdin. Tests inject
|
|
1942
|
+
// via ctx.hookStdin (a string) to avoid piping through process.
|
|
1943
|
+
if (typeof ctx.hookStdin === 'string' && ctx.hookStdin.length > 0) {
|
|
1944
|
+
try { return JSON.parse(ctx.hookStdin); } catch { return null; }
|
|
1945
|
+
}
|
|
1946
|
+
const stdin = process.stdin;
|
|
1947
|
+
if (!stdin || (typeof stdin.isTTY === 'boolean' && stdin.isTTY)) return null;
|
|
1948
|
+
const buf = await new Promise((resolvePromise) => {
|
|
1949
|
+
let acc = '';
|
|
1950
|
+
let done = false;
|
|
1951
|
+
const finish = () => { if (!done) { done = true; resolvePromise(acc); } };
|
|
1952
|
+
stdin.setEncoding('utf8');
|
|
1953
|
+
stdin.on('data', (chunk) => { acc += chunk; });
|
|
1954
|
+
stdin.on('end', finish);
|
|
1955
|
+
stdin.on('error', finish);
|
|
1956
|
+
// A 1-second cap; hooks share a small budget and must never
|
|
1957
|
+
// block the harness on a stalled parent.
|
|
1958
|
+
setTimeout(finish, 1000).unref?.();
|
|
1959
|
+
});
|
|
1960
|
+
if (!buf) return null;
|
|
1961
|
+
try { return JSON.parse(buf); } catch { return null; }
|
|
1962
|
+
}
|
|
1963
|
+
|
|
1964
|
+
async function runStopHook(projectRoot, harness, sessionId, payload, env, now, streams) {
|
|
1965
|
+
const settingsRead = await readFeedbackSettings(projectRoot);
|
|
1966
|
+
const fileOptOut = settingsRead.settings.ask === false;
|
|
1967
|
+
const envOptOut = env.RCF_FEEDBACK_ASK === '0' || env.RCF_FEEDBACK_DISABLE === '1';
|
|
1968
|
+
const optedOut = fileOptOut || envOptOut;
|
|
1969
|
+
|
|
1970
|
+
// AC-16103-3: deferred entries from an earlier sessionId return to
|
|
1971
|
+
// pending here so a defer taken in session A is asked again in
|
|
1972
|
+
// session B whether or not the SessionStart hook fired first.
|
|
1973
|
+
await requeueDeferredForSession(projectRoot, sessionId, now);
|
|
1974
|
+
|
|
1975
|
+
const all = await readEntries(projectRoot);
|
|
1976
|
+
const pending = all.filter((e) => e.status === 'pending');
|
|
1977
|
+
const pendingCount = pending.length;
|
|
1978
|
+
|
|
1979
|
+
const ledger = await readAskLedger(projectRoot);
|
|
1980
|
+
const askedThisSession = Boolean(sessionId)
|
|
1981
|
+
&& Array.isArray(ledger.asked)
|
|
1982
|
+
&& ledger.asked.some((r) => r?.sessionId === sessionId);
|
|
1983
|
+
|
|
1984
|
+
const stopHookActive = payload && (payload.stop_hook_active === true
|
|
1985
|
+
|| payload.stopHookActive === true);
|
|
1986
|
+
|
|
1987
|
+
const nowMs = now().getTime();
|
|
1988
|
+
const ages = pending
|
|
1989
|
+
.map((e) => Date.parse(e.recordedAt ?? ''))
|
|
1990
|
+
.filter((t) => Number.isFinite(t))
|
|
1991
|
+
.map((t) => nowMs - t);
|
|
1992
|
+
const newestPendingAgeMs = ages.length === 0 ? null : Math.min(...ages);
|
|
1993
|
+
const anyAskNow = pending.some((e) => e.askNow === true);
|
|
1994
|
+
const anyCarriedOver = Boolean(sessionId) && pending.some((e) => {
|
|
1995
|
+
const s = typeof e.sessionId === 'string' ? e.sessionId : '';
|
|
1996
|
+
return s !== '' && s !== sessionId;
|
|
1997
|
+
});
|
|
1998
|
+
const queueComplete = typeof ledger.queueStateAt === 'string' && ledger.queueStateAt.length > 0;
|
|
1999
|
+
|
|
2000
|
+
const decision = shouldAsk({
|
|
2001
|
+
optedOut,
|
|
2002
|
+
pendingCount,
|
|
2003
|
+
askedThisSession,
|
|
2004
|
+
stopHookActive,
|
|
2005
|
+
anyAskNow,
|
|
2006
|
+
newestPendingAgeMs,
|
|
2007
|
+
quietMinutes: settingsRead.settings.quietMinutes,
|
|
2008
|
+
queueComplete,
|
|
2009
|
+
anyCarriedOver,
|
|
2010
|
+
});
|
|
2011
|
+
|
|
2012
|
+
if (decision === 'ask' && sessionId) {
|
|
2013
|
+
// Ledger first, then emit (design 3.5 crash-safety clause).
|
|
2014
|
+
const askedAt = now().toISOString().replace(/\.\d{3}Z$/, 'Z');
|
|
2015
|
+
const next = {
|
|
2016
|
+
...ledger,
|
|
2017
|
+
asked: [...(Array.isArray(ledger.asked) ? ledger.asked : []), { sessionId, askedAt }],
|
|
2018
|
+
};
|
|
2019
|
+
await writeAskLedger(projectRoot, next);
|
|
2020
|
+
}
|
|
2021
|
+
const reason = buildAskReason(pendingCount);
|
|
2022
|
+
return emitHook(harness, decision, reason, streams);
|
|
2023
|
+
}
|
|
2024
|
+
|
|
2025
|
+
async function runSessionStartHook(projectRoot, harness, sessionId, now, streams) {
|
|
2026
|
+
// AC-16103-3: deferred entries from an earlier sessionId return to
|
|
2027
|
+
// pending on SessionStart so the same session's Stop offers the
|
|
2028
|
+
// ask (design 3.1: defer = "not now", ask again next session).
|
|
2029
|
+
// The transition preserves the entry's prior sessionId so the
|
|
2030
|
+
// carry-over gate below still fires for the requeued entries.
|
|
2031
|
+
await requeueDeferredForSession(projectRoot, sessionId, now);
|
|
2032
|
+
|
|
2033
|
+
const all = await readEntries(projectRoot);
|
|
2034
|
+
const pending = all.filter((e) => e.status === 'pending');
|
|
2035
|
+
const anyCarriedOver = pending.some((e) => {
|
|
2036
|
+
const s = typeof e.sessionId === 'string' ? e.sessionId : '';
|
|
2037
|
+
// Treat every pending entry as carried-over when we do not yet
|
|
2038
|
+
// have a sessionId to compare against (a first SessionStart on
|
|
2039
|
+
// a new session; the recorded sessionId is by definition prior).
|
|
2040
|
+
return s !== '' && (!sessionId || s !== sessionId);
|
|
2041
|
+
});
|
|
2042
|
+
if (!anyCarriedOver) return 0;
|
|
2043
|
+
const line = buildCarryOverLine(pending.length);
|
|
2044
|
+
return emitSessionStart(harness, line, streams);
|
|
2045
|
+
}
|
|
2046
|
+
|
|
2047
|
+
async function runSessionEndHook(projectRoot, { now }) {
|
|
2048
|
+
const all = await readEntries(projectRoot);
|
|
2049
|
+
const pending = all.filter((e) => e.status === 'pending');
|
|
2050
|
+
if (pending.length === 0) return 0;
|
|
2051
|
+
// Compose a fingerprint-only bundle text (idempotency check reads
|
|
2052
|
+
// the last-written file and compares by content hash). We do not
|
|
2053
|
+
// change entry state on session-end; slice 4's `submit` remains
|
|
2054
|
+
// the terminal step. This is a safety flush of the exact set of
|
|
2055
|
+
// pending titles so a crashed session's findings are pastable.
|
|
2056
|
+
const stampSafe = now().toISOString().replace(/\.\d{3}Z$/, 'Z').replace(/[:]/g, '-');
|
|
2057
|
+
const dir = outboxDir(projectRoot);
|
|
2058
|
+
await mkdir(dir, { recursive: true });
|
|
2059
|
+
const filename = `${stampSafe}-session-end.md`;
|
|
2060
|
+
const path = resolve(dir, filename);
|
|
2061
|
+
const body = renderSessionEndBundle(pending, now());
|
|
2062
|
+
// Idempotency: two consecutive runs with the same pending set MUST
|
|
2063
|
+
// produce a single file. The only field that legitimately differs
|
|
2064
|
+
// between the two bodies is the `Generated:` timestamp; a naive
|
|
2065
|
+
// byte-compare therefore flaked whenever the two calls straddled a
|
|
2066
|
+
// second boundary (AC-16103-1 intermittent failure). Compare on a
|
|
2067
|
+
// canonical form that stamps the timestamp with a fixed placeholder,
|
|
2068
|
+
// so the byte-idempotency check honours the design intent (same
|
|
2069
|
+
// pending set = same bundle) regardless of wall-clock drift.
|
|
2070
|
+
const canon = (s) => s.replace(/^Generated: [^\n]*$/m, 'Generated: <stamp>');
|
|
2071
|
+
const bodyCanon = canon(body);
|
|
2072
|
+
try {
|
|
2073
|
+
const entries = await readdir(dir);
|
|
2074
|
+
for (const f of entries) {
|
|
2075
|
+
if (!f.endsWith('-session-end.md')) continue;
|
|
2076
|
+
try {
|
|
2077
|
+
const existing = await readFile(resolve(dir, f), 'utf8');
|
|
2078
|
+
if (canon(existing) === bodyCanon) return 0;
|
|
2079
|
+
} catch { /* ignore */ }
|
|
2080
|
+
}
|
|
2081
|
+
} catch { /* ignore */ }
|
|
2082
|
+
await writeFile(path, body, 'utf8');
|
|
2083
|
+
return 0;
|
|
2084
|
+
}
|
|
2085
|
+
|
|
2086
|
+
function renderSessionEndBundle(pending, when) {
|
|
2087
|
+
const stamp = when.toISOString().replace(/\.\d{3}Z$/, 'Z');
|
|
2088
|
+
const lines = [];
|
|
2089
|
+
lines.push('# rcf feedback: session-end pending bundle');
|
|
2090
|
+
lines.push('');
|
|
2091
|
+
lines.push(`Generated: ${stamp}`);
|
|
2092
|
+
lines.push(`Entries pending on this project at session end: ${pending.length}`);
|
|
2093
|
+
lines.push('');
|
|
2094
|
+
lines.push('The next session offers to send these on Stop (design 3.5).');
|
|
2095
|
+
lines.push('This bundle is a local reminder; no issue was filed.');
|
|
2096
|
+
lines.push('');
|
|
2097
|
+
for (const e of pending) {
|
|
2098
|
+
lines.push(`## ${e.id}: ${e.title ?? '(no title)'}`);
|
|
2099
|
+
lines.push('');
|
|
2100
|
+
lines.push(`- kind: ${e.kind ?? '?'}`);
|
|
2101
|
+
lines.push(`- target: ${e?.target?.ref ?? '?'}`);
|
|
2102
|
+
lines.push(`- anchor: ${e.anchor ?? '-'}`);
|
|
2103
|
+
lines.push(`- class: ${e.symptomClass ?? '?'}`);
|
|
2104
|
+
lines.push(`- severity: ${e.severity ?? '?'}`);
|
|
2105
|
+
if (e.fingerprint) lines.push(`- fingerprint: ${e.fingerprint}`);
|
|
2106
|
+
lines.push('');
|
|
2107
|
+
}
|
|
2108
|
+
return lines.join('\n');
|
|
2109
|
+
}
|
|
2110
|
+
|
|
2111
|
+
|
|
2112
|
+
// -- helpers ---------------------------------------------------------------
|
|
2113
|
+
|
|
2114
|
+
function inferHarness(env) {
|
|
2115
|
+
// F-slice-1-05: design 3.6 pins CLAUDECODE=1 and returns `unknown`
|
|
2116
|
+
// when neither harness leaves a signature. `other` is a legitimate
|
|
2117
|
+
// OPERATOR-declared value on --harness; the auto-fallback must not
|
|
2118
|
+
// conflate "unidentified" with a declared choice.
|
|
2119
|
+
if (env.CLAUDECODE === '1') return 'claude-code';
|
|
2120
|
+
for (const k of Object.keys(env)) {
|
|
2121
|
+
if (k.startsWith('CODEX_')) return 'codex';
|
|
2122
|
+
}
|
|
2123
|
+
return 'unknown';
|
|
2124
|
+
}
|
|
2125
|
+
|
|
2126
|
+
/**
|
|
2127
|
+
* F-slice-1-09: sweep discarded entries older than the design 3.1
|
|
2128
|
+
* 30-day window. A `pruned` state line is appended for each expiring
|
|
2129
|
+
* entry so the reader's fold-by-id drops it from list/count surfaces
|
|
2130
|
+
* on the next read; the historical JSONL rows stay untouched (append-
|
|
2131
|
+
* only invariant). Best-effort: failures never break the caller.
|
|
2132
|
+
*
|
|
2133
|
+
* @param {string} projectRoot
|
|
2134
|
+
* @param {() => Date} nowFn
|
|
2135
|
+
* @param {number} [windowDays]
|
|
2136
|
+
*/
|
|
2137
|
+
async function pruneOldDiscarded(projectRoot, nowFn, windowDays = 30) {
|
|
2138
|
+
try {
|
|
2139
|
+
const all = await readEntries(projectRoot);
|
|
2140
|
+
const discardedAt = await readDiscardTimestamps(projectRoot);
|
|
2141
|
+
const now = typeof nowFn === 'function' ? nowFn() : new Date();
|
|
2142
|
+
const cutoff = now.getTime() - windowDays * 24 * 60 * 60 * 1000;
|
|
2143
|
+
for (const e of all) {
|
|
2144
|
+
if (e.status !== 'discarded') continue;
|
|
2145
|
+
// F-slice-1-09 fix: the 30-day clock runs from the discard
|
|
2146
|
+
// transition, not `recordedAt`. Design 3.1 L137 says "30 days
|
|
2147
|
+
// after discard"; the earlier reading would prune an entry
|
|
2148
|
+
// discarded today just because it was recorded 60 days ago.
|
|
2149
|
+
// If we cannot find a discard timestamp (a hand-authored
|
|
2150
|
+
// entry seeded with status:discarded, for instance), we err
|
|
2151
|
+
// on the safe side and keep the entry.
|
|
2152
|
+
const discardTs = discardedAt.get(e.id);
|
|
2153
|
+
if (typeof discardTs !== 'string') continue;
|
|
2154
|
+
const t = Date.parse(discardTs);
|
|
2155
|
+
if (!Number.isFinite(t) || t > cutoff) continue;
|
|
2156
|
+
// The state line is the only trace after prune; the raw body
|
|
2157
|
+
// stays visible in the fold-by-id read so `list --all` (below)
|
|
2158
|
+
// can still cite what was there and why it went. Never a silent
|
|
2159
|
+
// removal.
|
|
2160
|
+
await appendState(projectRoot, {
|
|
2161
|
+
id: e.id,
|
|
2162
|
+
at: now.toISOString().replace(/\.\d{3}Z$/, 'Z'),
|
|
2163
|
+
status: 'pruned',
|
|
2164
|
+
});
|
|
2165
|
+
}
|
|
2166
|
+
} catch (err) {
|
|
2167
|
+
if (process.env.RCF_FEEDBACK_TRACE_PRUNE === '1') {
|
|
2168
|
+
process.stderr.write(`[prune] failed: ${err.message}\n`);
|
|
2169
|
+
}
|
|
2170
|
+
}
|
|
2171
|
+
}
|
|
2172
|
+
|
|
2173
|
+
async function readOwnVersion() {
|
|
2174
|
+
try {
|
|
2175
|
+
const pkg = JSON.parse(await readFile(resolve(PACKAGE_ROOT, 'package.json'), 'utf8'));
|
|
2176
|
+
return pkg.version ?? '0.0.0';
|
|
2177
|
+
} catch {
|
|
2178
|
+
return '0.0.0';
|
|
2179
|
+
}
|
|
2180
|
+
}
|
|
2181
|
+
|
|
2182
|
+
/**
|
|
2183
|
+
* Lookup a blueprint entry on `rcf/manifest.json:blueprints[]` by ref.
|
|
2184
|
+
* The lookup accepts a shelf slug (`security-auth-magic-link`), a
|
|
2185
|
+
* prefix:slug shape (`wsd:std-error-envelope`) and an effective slug
|
|
2186
|
+
* (`wsd-std-error-envelope`). Slice 3 lands the full resolver; slice 1
|
|
2187
|
+
* just needs the yes/no answer for the exit-3 branch.
|
|
2188
|
+
*
|
|
2189
|
+
* @param {string} projectRoot
|
|
2190
|
+
* @param {string} ref
|
|
2191
|
+
* @returns {Promise<null | { slug: string, version?: string | null, libraryPrefix?: string | null, libraryRef?: string | null, pin?: object }>}
|
|
2192
|
+
*/
|
|
2193
|
+
async function lookupBlueprintRecord(projectRoot, ref) {
|
|
2194
|
+
try {
|
|
2195
|
+
const manifest = JSON.parse(await readFile(resolve(projectRoot, 'rcf', 'manifest.json'), 'utf8'));
|
|
2196
|
+
// Delegate to the resolver's own findBlueprintRecord so the
|
|
2197
|
+
// qualified-ref safety (F-slice-3-01) applies here too; slice-1
|
|
2198
|
+
// stamping and slice-3 destination resolution walk the same
|
|
2199
|
+
// matcher, so a qualified WSD ref never picks up a shelf record
|
|
2200
|
+
// by slug collision.
|
|
2201
|
+
return findBlueprintRecord(manifest, ref);
|
|
2202
|
+
} catch { /* fall through to null */ }
|
|
2203
|
+
return null;
|
|
2204
|
+
}
|