rcf-lite 0.27.0 → 0.28.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (601) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/README.md +10 -0
  3. package/bin/rcf.js +2 -0
  4. package/blueprints/application-account-settings/CHANGELOG.md +35 -6
  5. package/blueprints/application-account-settings/README.md +1 -1
  6. package/blueprints/application-account-settings/blueprint.json +4 -2
  7. package/blueprints/application-account-settings/contributions/adrs/adr-2602-application-account-settings-security-surface-shape.json +1 -1
  8. package/blueprints/application-account-settings/contributions/probes/probe-utils.mjs +177 -0
  9. package/blueprints/application-account-settings/contributions/probes/profile-form-autocomplete.mjs +67 -0
  10. package/blueprints/application-account-settings/contributions/probes/run-profile-form-autocomplete.mjs +5 -0
  11. package/blueprints/application-account-settings/contributions/probes/run-sessions-adapter-uniform.mjs +5 -0
  12. package/blueprints/application-account-settings/contributions/probes/run-sessions-surface-shape.mjs +5 -0
  13. package/blueprints/application-account-settings/contributions/probes/run-shell-tablist-per-capability.mjs +5 -0
  14. package/blueprints/application-account-settings/contributions/probes/run-theme-radiogroup.mjs +5 -0
  15. package/blueprints/application-account-settings/contributions/probes/sessions-adapter-uniform.mjs +130 -0
  16. package/blueprints/application-account-settings/contributions/probes/sessions-surface-shape.mjs +70 -0
  17. package/blueprints/application-account-settings/contributions/probes/shell-tablist-per-capability.mjs +60 -0
  18. package/blueprints/application-account-settings/contributions/probes/theme-radiogroup.mjs +126 -0
  19. package/blueprints/application-admin-console/CHANGELOG.md +32 -6
  20. package/blueprints/application-admin-console/README.md +1 -1
  21. package/blueprints/application-admin-console/blueprint.json +4 -2
  22. package/blueprints/application-admin-console/contributions/adrs/adr-2201-application-admin-console-capability-vocabulary.json +1 -1
  23. package/blueprints/application-admin-console/contributions/probes/audit-log-surface.mjs +79 -0
  24. package/blueprints/application-admin-console/contributions/probes/org-switcher-surface.mjs +83 -0
  25. package/blueprints/application-admin-console/contributions/probes/permission-matrix-grid.mjs +67 -0
  26. package/blueprints/application-admin-console/contributions/probes/probe-utils.mjs +177 -0
  27. package/blueprints/application-admin-console/contributions/probes/run-audit-log-surface.mjs +5 -0
  28. package/blueprints/application-admin-console/contributions/probes/run-org-switcher-surface.mjs +5 -0
  29. package/blueprints/application-admin-console/contributions/probes/run-permission-matrix-grid.mjs +5 -0
  30. package/blueprints/application-admin-console/contributions/probes/run-sign-in-access-gated-surface.mjs +5 -0
  31. package/blueprints/application-admin-console/contributions/probes/run-users-directory-surface.mjs +5 -0
  32. package/blueprints/application-admin-console/contributions/probes/sign-in-access-gated-surface.mjs +117 -0
  33. package/blueprints/application-admin-console/contributions/probes/users-directory-surface.mjs +145 -0
  34. package/blueprints/application-api-rest/CHANGELOG.md +16 -8
  35. package/blueprints/application-api-rest/README.md +3 -3
  36. package/blueprints/application-api-rest/blueprint.json +3 -2
  37. package/blueprints/application-api-rest/contributions/adrs/adr-302-application-api-rest-auth-model.json +1 -1
  38. package/blueprints/application-api-rest/contributions/probes/cursor-pagination-round-trip.mjs +154 -0
  39. package/blueprints/application-api-rest/contributions/probes/health-probes-distinct.mjs +124 -0
  40. package/blueprints/application-api-rest/contributions/probes/probe-utils.mjs +177 -0
  41. package/blueprints/application-api-rest/contributions/probes/problem-details-on-error.mjs +77 -0
  42. package/blueprints/application-api-rest/contributions/probes/request-id-echoed.mjs +76 -0
  43. package/blueprints/application-api-rest/contributions/probes/run-cursor-pagination-round-trip.mjs +5 -0
  44. package/blueprints/application-api-rest/contributions/probes/run-health-probes-distinct.mjs +5 -0
  45. package/blueprints/application-api-rest/contributions/probes/run-problem-details-on-error.mjs +5 -0
  46. package/blueprints/application-api-rest/contributions/probes/run-request-id-echoed.mjs +5 -0
  47. package/blueprints/application-api-rest/docs/topics.md +1 -1
  48. package/blueprints/application-charts/CHANGELOG.md +35 -9
  49. package/blueprints/application-charts/README.md +6 -6
  50. package/blueprints/application-charts/blueprint.json +5 -3
  51. package/blueprints/application-charts/contributions/adrs/adr-1901-application-charts-engine-choice.json +1 -1
  52. package/blueprints/application-charts/contributions/probes/keyboard-traversal.mjs +151 -0
  53. package/blueprints/application-charts/contributions/probes/non-colour-distinction.mjs +67 -0
  54. package/blueprints/application-charts/contributions/probes/probe-utils.mjs +177 -0
  55. package/blueprints/application-charts/contributions/probes/run-keyboard-traversal.mjs +5 -0
  56. package/blueprints/application-charts/contributions/probes/run-non-colour-distinction.mjs +5 -0
  57. package/blueprints/application-charts/contributions/probes/run-text-alternative-table.mjs +5 -0
  58. package/blueprints/application-charts/contributions/probes/text-alternative-table.mjs +139 -0
  59. package/blueprints/application-charts/contributions/requirements/application-charts-req-001.json +1 -1
  60. package/blueprints/application-charts/contributions/requirements/application-charts-req-002.json +1 -1
  61. package/blueprints/application-charts/contributions/user-stories/application-charts-us-18101.json +5 -5
  62. package/blueprints/application-charts/contributions/user-stories/application-charts-us-18106.json +1 -1
  63. package/blueprints/application-charts/guide/application-charts.md +1 -1
  64. package/blueprints/application-dashboard/CHANGELOG.md +20 -10
  65. package/blueprints/application-dashboard/README.md +6 -6
  66. package/blueprints/application-dashboard/assets/guidance/dashboard-design.md +2 -2
  67. package/blueprints/application-dashboard/blueprint.json +3 -2
  68. package/blueprints/application-dashboard/contributions/adrs/adr-2001-application-dashboard-primary-kpi-enum.json +1 -1
  69. package/blueprints/application-dashboard/contributions/adrs/adr-2002-application-dashboard-timeframe-presets.json +1 -1
  70. package/blueprints/application-dashboard/contributions/probes/export-handle-formats.mjs +75 -0
  71. package/blueprints/application-dashboard/contributions/probes/four-tile-states.mjs +75 -0
  72. package/blueprints/application-dashboard/contributions/probes/primary-kpi-top-left.mjs +58 -0
  73. package/blueprints/application-dashboard/contributions/probes/probe-utils.mjs +177 -0
  74. package/blueprints/application-dashboard/contributions/probes/run-export-handle-formats.mjs +4 -0
  75. package/blueprints/application-dashboard/contributions/probes/run-four-tile-states.mjs +4 -0
  76. package/blueprints/application-dashboard/contributions/probes/run-primary-kpi-top-left.mjs +4 -0
  77. package/blueprints/application-dashboard/contributions/probes/run-shell-five-regions.mjs +4 -0
  78. package/blueprints/application-dashboard/contributions/probes/shell-five-regions.mjs +93 -0
  79. package/blueprints/application-dashboard/contributions/requirements/application-dashboard-req-002.json +1 -1
  80. package/blueprints/application-dashboard/contributions/requirements/application-dashboard-req-003.json +1 -1
  81. package/blueprints/application-dashboard/contributions/tacs/tac-2002-application-dashboard-filter-chrome.json +1 -1
  82. package/blueprints/application-dashboard/contributions/tacs/tac-2003-application-dashboard-export-handle.json +2 -2
  83. package/blueprints/application-dashboard/contributions/user-stories/application-dashboard-us-19101.json +2 -2
  84. package/blueprints/application-dashboard/contributions/user-stories/application-dashboard-us-19102.json +2 -2
  85. package/blueprints/application-dashboard/contributions/user-stories/application-dashboard-us-19103.json +1 -1
  86. package/blueprints/application-dashboard/contributions/user-stories/application-dashboard-us-19104.json +1 -1
  87. package/blueprints/application-dashboard/contributions/user-stories/application-dashboard-us-19105.json +1 -1
  88. package/blueprints/application-dashboard/contributions/user-stories/application-dashboard-us-19106.json +2 -2
  89. package/blueprints/application-dashboard/contributions/user-stories/application-dashboard-us-19107.json +5 -5
  90. package/blueprints/application-dashboard/docs/topics.md +2 -2
  91. package/blueprints/application-dashboard/guide/application-dashboard.md +2 -2
  92. package/blueprints/application-datatable/CHANGELOG.md +19 -9
  93. package/blueprints/application-datatable/README.md +2 -2
  94. package/blueprints/application-datatable/blueprint.json +3 -2
  95. package/blueprints/application-datatable/contributions/probes/apg-table-shape.mjs +57 -0
  96. package/blueprints/application-datatable/contributions/probes/four-states-regions.mjs +80 -0
  97. package/blueprints/application-datatable/contributions/probes/probe-utils.mjs +177 -0
  98. package/blueprints/application-datatable/contributions/probes/run-apg-table-shape.mjs +4 -0
  99. package/blueprints/application-datatable/contributions/probes/run-four-states-regions.mjs +4 -0
  100. package/blueprints/application-datatable/contributions/probes/run-search-adapter-round-trip.mjs +4 -0
  101. package/blueprints/application-datatable/contributions/probes/run-sort-adapter-round-trip.mjs +4 -0
  102. package/blueprints/application-datatable/contributions/probes/search-adapter-round-trip.mjs +58 -0
  103. package/blueprints/application-datatable/contributions/probes/sort-adapter-round-trip.mjs +60 -0
  104. package/blueprints/application-datatable/contributions/requirements/application-datatable-req-006.json +1 -1
  105. package/blueprints/application-datatable/docs/topics.md +1 -1
  106. package/blueprints/application-empty-error-states/CHANGELOG.md +33 -3
  107. package/blueprints/application-empty-error-states/blueprint.json +4 -2
  108. package/blueprints/application-empty-error-states/contributions/probes/empty-list-and-no-search.mjs +66 -0
  109. package/blueprints/application-empty-error-states/contributions/probes/error-boundary-alert.mjs +65 -0
  110. package/blueprints/application-empty-error-states/contributions/probes/forbidden-and-server-error.mjs +167 -0
  111. package/blueprints/application-empty-error-states/contributions/probes/not-found-and-recovery.mjs +61 -0
  112. package/blueprints/application-empty-error-states/contributions/probes/permission-denied-and-offline.mjs +155 -0
  113. package/blueprints/application-empty-error-states/contributions/probes/probe-utils.mjs +177 -0
  114. package/blueprints/application-empty-error-states/contributions/probes/run-empty-list-and-no-search.mjs +5 -0
  115. package/blueprints/application-empty-error-states/contributions/probes/run-error-boundary-alert.mjs +5 -0
  116. package/blueprints/application-empty-error-states/contributions/probes/run-forbidden-and-server-error.mjs +5 -0
  117. package/blueprints/application-empty-error-states/contributions/probes/run-not-found-and-recovery.mjs +5 -0
  118. package/blueprints/application-empty-error-states/contributions/probes/run-permission-denied-and-offline.mjs +5 -0
  119. package/blueprints/application-error-handling/CHANGELOG.md +45 -6
  120. package/blueprints/application-error-handling/blueprint.json +3 -2
  121. package/blueprints/application-error-handling/contributions/probes/category-vocabulary.mjs +90 -0
  122. package/blueprints/application-error-handling/contributions/probes/probe-utils.mjs +177 -0
  123. package/blueprints/application-error-handling/contributions/probes/record-shape-adr-1701.mjs +78 -0
  124. package/blueprints/application-error-handling/contributions/probes/run-category-vocabulary.mjs +5 -0
  125. package/blueprints/application-error-handling/contributions/probes/run-record-shape-adr-1701.mjs +5 -0
  126. package/blueprints/application-error-handling/contributions/probes/run-two-boundaries-registered.mjs +5 -0
  127. package/blueprints/application-error-handling/contributions/probes/two-boundaries-registered.mjs +343 -0
  128. package/blueprints/application-file-upload/CHANGELOG.md +28 -6
  129. package/blueprints/application-file-upload/README.md +1 -1
  130. package/blueprints/application-file-upload/blueprint.json +3 -2
  131. package/blueprints/application-file-upload/contributions/probes/assertive-completion-slot.mjs +78 -0
  132. package/blueprints/application-file-upload/contributions/probes/chunked-transport-endpoints.mjs +173 -0
  133. package/blueprints/application-file-upload/contributions/probes/per-file-progressbar.mjs +124 -0
  134. package/blueprints/application-file-upload/contributions/probes/probe-utils.mjs +177 -0
  135. package/blueprints/application-file-upload/contributions/probes/run-assertive-completion-slot.mjs +4 -0
  136. package/blueprints/application-file-upload/contributions/probes/run-chunked-transport-endpoints.mjs +4 -0
  137. package/blueprints/application-file-upload/contributions/probes/run-per-file-progressbar.mjs +4 -0
  138. package/blueprints/application-file-upload/contributions/probes/run-upload-surface-shape.mjs +4 -0
  139. package/blueprints/application-file-upload/contributions/probes/upload-surface-shape.mjs +55 -0
  140. package/blueprints/application-file-upload/contributions/requirements/application-file-upload-req-001.json +1 -1
  141. package/blueprints/application-file-upload/contributions/requirements/application-file-upload-req-002.json +1 -1
  142. package/blueprints/application-file-upload/contributions/requirements/application-file-upload-req-003.json +1 -1
  143. package/blueprints/application-file-upload/contributions/requirements/application-file-upload-req-004.json +1 -1
  144. package/blueprints/application-file-upload/contributions/requirements/application-file-upload-req-005.json +1 -1
  145. package/blueprints/application-file-upload/probe-packs/application-file-upload.pack.mjs +1 -1
  146. package/blueprints/application-forms-wizard/CHANGELOG.md +20 -6
  147. package/blueprints/application-forms-wizard/README.md +2 -2
  148. package/blueprints/application-forms-wizard/blueprint.json +3 -2
  149. package/blueprints/application-forms-wizard/contributions/probes/draft-persistence-round-trip.mjs +110 -0
  150. package/blueprints/application-forms-wizard/contributions/probes/probe-utils.mjs +177 -0
  151. package/blueprints/application-forms-wizard/contributions/probes/run-draft-persistence-round-trip.mjs +4 -0
  152. package/blueprints/application-forms-wizard/contributions/probes/run-step-page-shape.mjs +4 -0
  153. package/blueprints/application-forms-wizard/contributions/probes/run-task-list-surface.mjs +4 -0
  154. package/blueprints/application-forms-wizard/contributions/probes/step-page-shape.mjs +61 -0
  155. package/blueprints/application-forms-wizard/contributions/probes/task-list-surface.mjs +109 -0
  156. package/blueprints/application-forms-wizard/contributions/requirements/application-forms-wizard-req-001.json +1 -1
  157. package/blueprints/application-forms-wizard/contributions/requirements/application-forms-wizard-req-002.json +1 -1
  158. package/blueprints/application-forms-wizard/contributions/requirements/application-forms-wizard-req-003.json +1 -1
  159. package/blueprints/application-forms-wizard/contributions/requirements/application-forms-wizard-req-004.json +1 -1
  160. package/blueprints/application-forms-wizard/contributions/requirements/application-forms-wizard-req-005.json +1 -1
  161. package/blueprints/application-forms-wizard/probe-packs/application-forms-wizard.pack.mjs +1 -1
  162. package/blueprints/application-notifications-in-app/CHANGELOG.md +38 -5
  163. package/blueprints/application-notifications-in-app/README.md +4 -4
  164. package/blueprints/application-notifications-in-app/blueprint.json +4 -2
  165. package/blueprints/application-notifications-in-app/contributions/adrs/adr-2101-application-notifications-in-app-live-region-role-mapping.json +1 -1
  166. package/blueprints/application-notifications-in-app/contributions/probes/centre-acknowledge-round-trip.mjs +210 -0
  167. package/blueprints/application-notifications-in-app/contributions/probes/live-region-preseeding.mjs +93 -0
  168. package/blueprints/application-notifications-in-app/contributions/probes/probe-utils.mjs +177 -0
  169. package/blueprints/application-notifications-in-app/contributions/probes/run-centre-acknowledge-round-trip.mjs +5 -0
  170. package/blueprints/application-notifications-in-app/contributions/probes/run-live-region-preseeding.mjs +5 -0
  171. package/blueprints/application-notifications-in-app/contributions/probes/run-toast-contract.mjs +5 -0
  172. package/blueprints/application-notifications-in-app/contributions/probes/toast-contract.mjs +92 -0
  173. package/blueprints/application-notifications-in-app/contributions/tacs/tac-2101-application-notifications-in-app-live-region.json +3 -3
  174. package/blueprints/application-notifications-in-app/contributions/tacs/tac-2102-application-notifications-in-app-centre.json +1 -1
  175. package/blueprints/application-notifications-in-app/contributions/user-stories/application-notifications-in-app-us-20101.json +1 -1
  176. package/blueprints/application-notifications-in-app/contributions/user-stories/application-notifications-in-app-us-20102.json +1 -1
  177. package/blueprints/application-notifications-in-app/contributions/user-stories/application-notifications-in-app-us-20103.json +1 -1
  178. package/blueprints/application-notifications-in-app/contributions/user-stories/application-notifications-in-app-us-20105.json +1 -1
  179. package/blueprints/application-notifications-in-app/guide/application-notifications-in-app.md +3 -3
  180. package/blueprints/application-onboarding-tour/CHANGELOG.md +31 -5
  181. package/blueprints/application-onboarding-tour/README.md +1 -1
  182. package/blueprints/application-onboarding-tour/blueprint.json +5 -3
  183. package/blueprints/application-onboarding-tour/contributions/probes/checklist-anchor-open.mjs +81 -0
  184. package/blueprints/application-onboarding-tour/contributions/probes/completion-persistence.mjs +159 -0
  185. package/blueprints/application-onboarding-tour/contributions/probes/first-run-detection.mjs +67 -0
  186. package/blueprints/application-onboarding-tour/contributions/probes/probe-utils.mjs +177 -0
  187. package/blueprints/application-onboarding-tour/contributions/probes/run-checklist-anchor-open.mjs +5 -0
  188. package/blueprints/application-onboarding-tour/contributions/probes/run-completion-persistence.mjs +5 -0
  189. package/blueprints/application-onboarding-tour/contributions/probes/run-first-run-detection.mjs +5 -0
  190. package/blueprints/application-onboarding-tour/contributions/probes/run-stepper-role-dialog.mjs +5 -0
  191. package/blueprints/application-onboarding-tour/contributions/probes/stepper-role-dialog.mjs +45 -0
  192. package/blueprints/application-spa/CHANGELOG.md +20 -11
  193. package/blueprints/application-spa/README.md +9 -10
  194. package/blueprints/application-spa/blueprint.json +3 -2
  195. package/blueprints/application-spa/contributions/adrs/adr-202-application-spa-theming.json +1 -1
  196. package/blueprints/application-spa/contributions/adrs/adr-206-application-spa-iconography.json +1 -1
  197. package/blueprints/application-spa/contributions/probes/designed-empty-state.mjs +72 -0
  198. package/blueprints/application-spa/contributions/probes/probe-utils.mjs +177 -0
  199. package/blueprints/application-spa/contributions/probes/route-inventory-published.mjs +185 -0
  200. package/blueprints/application-spa/contributions/probes/run-designed-empty-state.mjs +5 -0
  201. package/blueprints/application-spa/contributions/probes/run-route-inventory-published.mjs +5 -0
  202. package/blueprints/application-spa/contributions/probes/run-shell-nav-present.mjs +5 -0
  203. package/blueprints/application-spa/contributions/probes/shell-nav-present.mjs +69 -0
  204. package/blueprints/application-spa/contributions/tacs/tac-207-application-spa-token-adherence-probe.json +1 -1
  205. package/blueprints/application-spa/contributions/tacs/tac-208-application-spa-icon-adherence-probe.json +2 -2
  206. package/blueprints/application-spa/contributions/tacs/tac-209-application-spa-csp-styled-adherence-probe.json +3 -3
  207. package/blueprints/application-spa/contributions/tacs/tac-210-application-spa-external-dependency-provisioning-probe.json +2 -2
  208. package/blueprints/application-spa/contributions/tacs/tac-211-application-spa-core-flow-e2e-probe.json +2 -2
  209. package/blueprints/application-spa/contributions/user-stories/application-spa-us-1131.json +1 -1
  210. package/blueprints/application-spa/docs/topics.md +1 -1
  211. package/blueprints/delivery-ci-workflows/CHANGELOG.md +31 -11
  212. package/blueprints/delivery-ci-workflows/README.md +3 -3
  213. package/blueprints/delivery-ci-workflows/blueprint.json +3 -2
  214. package/blueprints/delivery-ci-workflows/contributions/adrs/adr-702-delivery-ci-workflows-strict-coverage-gate.json +2 -2
  215. package/blueprints/delivery-ci-workflows/contributions/probes/node-gate-entrypoint.mjs +76 -0
  216. package/blueprints/delivery-ci-workflows/contributions/probes/probe-utils.mjs +56 -0
  217. package/blueprints/delivery-ci-workflows/contributions/probes/real-account-github-actions-run-record.mjs +139 -0
  218. package/blueprints/delivery-ci-workflows/contributions/probes/run-node-gate-entrypoint.mjs +3 -0
  219. package/blueprints/delivery-ci-workflows/contributions/probes/run-real-account-github-actions-run-record.mjs +3 -0
  220. package/blueprints/delivery-ci-workflows/contributions/probes/run-workflow-template-shape.mjs +3 -0
  221. package/blueprints/delivery-ci-workflows/contributions/probes/workflow-template-shape.mjs +94 -0
  222. package/blueprints/delivery-ci-workflows/contributions/requirements/delivery-ci-workflows-req-004.json +1 -1
  223. package/blueprints/delivery-ci-workflows/docs/topics.md +2 -3
  224. package/blueprints/deploy-cloudflare-workers/CHANGELOG.md +4 -4
  225. package/blueprints/deploy-cloudflare-workers/README.md +3 -3
  226. package/blueprints/deploy-cloudflare-workers/contributions/adrs/adr-1306-deploy-cloudflare-workers-spa-shape.json +2 -2
  227. package/blueprints/deploy-cloudflare-workers/docs/topics.md +2 -2
  228. package/blueprints/deploy-hetzner-server/CHANGELOG.md +98 -7
  229. package/blueprints/deploy-hetzner-server/blueprint.json +7 -6
  230. package/blueprints/deploy-hetzner-server/contributions/probes/cloud-init-render-lint.mjs +46 -21
  231. package/blueprints/deploy-hetzner-server/contributions/probes/hcloud-dry-run-mock.mjs +344 -83
  232. package/blueprints/deploy-hetzner-server/contributions/probes/manifest-schema-validate.mjs +211 -42
  233. package/blueprints/deploy-hetzner-server/contributions/probes/probe-utils.mjs +140 -22
  234. package/blueprints/deploy-hetzner-server/contributions/probes/real-account-cloud-init-hardened.mjs +111 -30
  235. package/blueprints/deploy-hetzner-server/contributions/probes/real-account-snapshot-on-demand.mjs +158 -30
  236. package/blueprints/deploy-hetzner-server/contributions/probes/real-account-throwaway-server-provision.mjs +154 -32
  237. package/blueprints/edge-cloudflare-access/CHANGELOG.md +6 -5
  238. package/blueprints/edge-cloudflare-access/blueprint.json +1 -1
  239. package/blueprints/edge-cloudflare-access/contributions/probes/admin-console-gate-surface.mjs +9 -1
  240. package/blueprints/edge-cloudflare-access/docs/topics.md +1 -1
  241. package/blueprints/edge-cloudflare-rate-limiting/CHANGELOG.md +4 -7
  242. package/blueprints/edge-cloudflare-rate-limiting/docs/topics.md +1 -1
  243. package/blueprints/edge-cloudflare-tunnel/CHANGELOG.md +4 -6
  244. package/blueprints/edge-cloudflare-tunnel/README.md +1 -2
  245. package/blueprints/edge-cloudflare-tunnel/docs/topics.md +1 -1
  246. package/blueprints/edge-cloudflare-turnstile/CHANGELOG.md +2 -3
  247. package/blueprints/edge-cloudflare-turnstile/docs/topics.md +1 -1
  248. package/blueprints/email-smtp-resend/CHANGELOG.md +24 -8
  249. package/blueprints/email-smtp-resend/README.md +2 -2
  250. package/blueprints/email-smtp-resend/blueprint.json +3 -2
  251. package/blueprints/email-smtp-resend/contributions/probes/probe-utils.mjs +50 -0
  252. package/blueprints/email-smtp-resend/contributions/probes/real-account-resend-send.mjs +50 -0
  253. package/blueprints/email-smtp-resend/contributions/probes/run-real-account-resend-send.mjs +3 -0
  254. package/blueprints/email-smtp-resend/contributions/probes/run-smtp-round-trip.mjs +3 -0
  255. package/blueprints/email-smtp-resend/contributions/probes/run-unverified-sender-refusal.mjs +3 -0
  256. package/blueprints/email-smtp-resend/contributions/probes/smtp-round-trip.mjs +43 -0
  257. package/blueprints/email-smtp-resend/contributions/probes/unverified-sender-refusal.mjs +99 -0
  258. package/blueprints/email-smtp-resend/docs/topics.md +2 -3
  259. package/blueprints/jobs-background/CHANGELOG.md +66 -5
  260. package/blueprints/jobs-background/README.md +2 -2
  261. package/blueprints/jobs-background/blueprint.json +3 -2
  262. package/blueprints/jobs-background/contributions/probes/apply-time-override.mjs +38 -10
  263. package/blueprints/jobs-background/contributions/probes/apply-time-refusal.mjs +28 -6
  264. package/blueprints/jobs-background/contributions/probes/event-secrecy.mjs +16 -2
  265. package/blueprints/jobs-background/contributions/probes/fake-clock-cron.mjs +102 -21
  266. package/blueprints/jobs-background/contributions/probes/probe-utils.mjs +10 -2
  267. package/blueprints/jobs-background/contributions/probes/retry-and-fail-real-account.mjs +355 -0
  268. package/blueprints/jobs-background/contributions/probes/retry-and-fail.mjs +33 -2
  269. package/blueprints/jobs-background/contributions/probes/run-retry-and-fail-real-account.mjs +12 -0
  270. package/blueprints/jobs-background/docs/topics.md +1 -1
  271. package/blueprints/jobs-background/guide/jobs-background.md +1 -1
  272. package/blueprints/messaging-queue-cloudflare/CHANGELOG.md +25 -19
  273. package/blueprints/messaging-queue-cloudflare/README.md +12 -12
  274. package/blueprints/messaging-queue-cloudflare/blueprint.json +1 -1
  275. package/blueprints/messaging-queue-cloudflare/contributions/adrs/adr-3001-messaging-queue-cloudflare-adapter.json +2 -2
  276. package/blueprints/messaging-queue-cloudflare/contributions/adrs/adr-3002-messaging-queue-cloudflare-delivery-semantics.json +1 -1
  277. package/blueprints/messaging-queue-cloudflare/contributions/probes/real-account-concurrency-smoke.mjs +180 -12
  278. package/blueprints/messaging-queue-cloudflare/contributions/requirements/messaging-queue-cloudflare-req-006.json +1 -1
  279. package/blueprints/messaging-queue-cloudflare/docs/topics.md +2 -2
  280. package/blueprints/messaging-queue-cloudflare/guide/messaging-queue-cloudflare.md +2 -2
  281. package/blueprints/object-storage-s3/CHANGELOG.md +75 -4
  282. package/blueprints/object-storage-s3/blueprint.json +3 -2
  283. package/blueprints/object-storage-s3/contributions/probes/event-secrecy.mjs +73 -12
  284. package/blueprints/object-storage-s3/contributions/probes/facade-round-trip.mjs +55 -7
  285. package/blueprints/object-storage-s3/contributions/probes/hetzner-object-storage-round-trip.mjs +102 -18
  286. package/blueprints/object-storage-s3/contributions/probes/multipart-upload.mjs +105 -36
  287. package/blueprints/object-storage-s3/contributions/probes/presigned-url.mjs +104 -55
  288. package/blueprints/object-storage-s3/contributions/probes/probe-utils.mjs +129 -7
  289. package/blueprints/object-storage-s3/contributions/probes/put-get-round-trip.mjs +80 -18
  290. package/blueprints/object-storage-s3/contributions/probes/r2-real-account-smoke.mjs +291 -37
  291. package/blueprints/object-storage-s3/contributions/probes/run-event-secrecy.mjs +8 -2
  292. package/blueprints/object-storage-s3/contributions/probes/run-facade-round-trip.mjs +5 -5
  293. package/blueprints/object-storage-s3/contributions/probes/run-hetzner-object-storage-round-trip.mjs +8 -5
  294. package/blueprints/object-storage-s3/contributions/probes/run-multipart-upload.mjs +8 -2
  295. package/blueprints/object-storage-s3/contributions/probes/run-presigned-url.mjs +8 -2
  296. package/blueprints/object-storage-s3/contributions/probes/run-put-get-round-trip.mjs +6 -3
  297. package/blueprints/object-storage-s3/contributions/probes/run-r2-real-account-smoke.mjs +10 -2
  298. package/blueprints/object-storage-s3/contributions/requirements/object-storage-s3-req-006.json +1 -1
  299. package/blueprints/object-storage-s3/docs/topics.md +1 -1
  300. package/blueprints/object-storage-s3/guide/object-storage-s3.md +1 -1
  301. package/blueprints/observability-essentials/CHANGELOG.md +23 -7
  302. package/blueprints/observability-essentials/README.md +2 -2
  303. package/blueprints/observability-essentials/assets/probe-samples/probe-response-baseline.v2.json +1 -1
  304. package/blueprints/observability-essentials/blueprint.json +3 -2
  305. package/blueprints/observability-essentials/contributions/probes/liveness-probe.mjs +84 -0
  306. package/blueprints/observability-essentials/contributions/probes/metrics-endpoint.mjs +96 -0
  307. package/blueprints/observability-essentials/contributions/probes/probe-utils.mjs +52 -0
  308. package/blueprints/observability-essentials/contributions/probes/readiness-probe.mjs +171 -0
  309. package/blueprints/observability-essentials/contributions/probes/run-liveness-probe.mjs +3 -0
  310. package/blueprints/observability-essentials/contributions/probes/run-metrics-endpoint.mjs +3 -0
  311. package/blueprints/observability-essentials/contributions/probes/run-readiness-probe.mjs +3 -0
  312. package/blueprints/observability-essentials/docs/topics.md +2 -3
  313. package/blueprints/observability-logging/CHANGELOG.md +29 -4
  314. package/blueprints/observability-logging/README.md +2 -2
  315. package/blueprints/observability-logging/blueprint.json +3 -2
  316. package/blueprints/observability-logging/contributions/probes/correlation-id-flow.mjs +173 -0
  317. package/blueprints/observability-logging/contributions/probes/line-shape-and-fields.mjs +82 -0
  318. package/blueprints/observability-logging/contributions/probes/probe-utils.mjs +47 -0
  319. package/blueprints/observability-logging/contributions/probes/redaction-boundary.mjs +130 -0
  320. package/blueprints/observability-logging/contributions/probes/run-correlation-id-flow.mjs +3 -0
  321. package/blueprints/observability-logging/contributions/probes/run-line-shape-and-fields.mjs +3 -0
  322. package/blueprints/observability-logging/contributions/probes/run-redaction-boundary.mjs +3 -0
  323. package/blueprints/observability-probe-endpoints/CHANGELOG.md +23 -8
  324. package/blueprints/observability-probe-endpoints/README.md +3 -3
  325. package/blueprints/observability-probe-endpoints/blueprint.json +3 -2
  326. package/blueprints/observability-probe-endpoints/contributions/probes/kubernetes-startup-enabled.mjs +80 -0
  327. package/blueprints/observability-probe-endpoints/contributions/probes/partial-profile-refusal.mjs +101 -0
  328. package/blueprints/observability-probe-endpoints/contributions/probes/probe-utils.mjs +49 -0
  329. package/blueprints/observability-probe-endpoints/contributions/probes/profile-boot-materialisation.mjs +69 -0
  330. package/blueprints/observability-probe-endpoints/contributions/probes/run-kubernetes-startup-enabled.mjs +3 -0
  331. package/blueprints/observability-probe-endpoints/contributions/probes/run-partial-profile-refusal.mjs +3 -0
  332. package/blueprints/observability-probe-endpoints/contributions/probes/run-profile-boot-materialisation.mjs +3 -0
  333. package/blueprints/observability-probe-endpoints/docs/topics.md +2 -2
  334. package/blueprints/persistence-data-d1/CHANGELOG.md +16 -3
  335. package/blueprints/persistence-data-d1/README.md +2 -2
  336. package/blueprints/persistence-data-d1/blueprint.json +3 -2
  337. package/blueprints/persistence-data-d1/contributions/adrs/adr-1404-persistence-data-d1-store-boundary.json +1 -1
  338. package/blueprints/persistence-data-d1/contributions/probes/facade-round-trip.mjs +140 -0
  339. package/blueprints/persistence-data-d1/contributions/probes/migrations-forward-only.mjs +66 -0
  340. package/blueprints/persistence-data-d1/contributions/probes/probe-utils.mjs +51 -0
  341. package/blueprints/persistence-data-d1/contributions/probes/real-account-d1-round-trip.mjs +133 -0
  342. package/blueprints/persistence-data-d1/contributions/probes/run-facade-round-trip.mjs +3 -0
  343. package/blueprints/persistence-data-d1/contributions/probes/run-migrations-forward-only.mjs +3 -0
  344. package/blueprints/persistence-data-d1/contributions/probes/run-real-account-d1-round-trip.mjs +3 -0
  345. package/blueprints/persistence-data-d1/docs/topics.md +2 -3
  346. package/blueprints/persistence-data-postgres/CHANGELOG.md +84 -4
  347. package/blueprints/persistence-data-postgres/README.md +2 -2
  348. package/blueprints/persistence-data-postgres/blueprint.json +3 -2
  349. package/blueprints/persistence-data-postgres/contributions/adrs/adr-2801-persistence-data-postgres-driver.json +1 -1
  350. package/blueprints/persistence-data-postgres/contributions/probes/facade-round-trip.mjs +87 -12
  351. package/blueprints/persistence-data-postgres/contributions/probes/migration-apply.mjs +245 -19
  352. package/blueprints/persistence-data-postgres/contributions/probes/pool-posture-smoke.mjs +109 -26
  353. package/blueprints/persistence-data-postgres/contributions/probes/prepared-statement-scan.mjs +151 -38
  354. package/blueprints/persistence-data-postgres/contributions/probes/probe-utils.mjs +24 -6
  355. package/blueprints/persistence-data-postgres/contributions/probes/recovery-restore-round-trip.mjs +261 -48
  356. package/blueprints/persistence-data-postgres/contributions/probes/transaction-atomicity.mjs +76 -20
  357. package/blueprints/persistence-data-postgres/contributions/requirements/persistence-data-postgres-req-003.json +1 -1
  358. package/blueprints/persistence-data-postgres/docs/topics.md +1 -1
  359. package/blueprints/persistence-data-sqlite/CHANGELOG.md +16 -2
  360. package/blueprints/persistence-data-sqlite/README.md +2 -2
  361. package/blueprints/persistence-data-sqlite/blueprint.json +3 -2
  362. package/blueprints/persistence-data-sqlite/contributions/probes/boot-open-migrate.mjs +90 -0
  363. package/blueprints/persistence-data-sqlite/contributions/probes/facade-round-trip.mjs +82 -0
  364. package/blueprints/persistence-data-sqlite/contributions/probes/probe-utils.mjs +83 -0
  365. package/blueprints/persistence-data-sqlite/contributions/probes/run-boot-open-migrate.mjs +5 -0
  366. package/blueprints/persistence-data-sqlite/contributions/probes/run-facade-round-trip.mjs +5 -0
  367. package/blueprints/persistence-data-sqlite/contributions/probes/run-wal-checkpoint.mjs +5 -0
  368. package/blueprints/persistence-data-sqlite/contributions/probes/wal-checkpoint.mjs +137 -0
  369. package/blueprints/persistence-data-sqlite/docs/topics.md +2 -3
  370. package/blueprints/platform-cloudflare-cron-triggers/CHANGELOG.md +5 -5
  371. package/blueprints/platform-cloudflare-cron-triggers/README.md +2 -3
  372. package/blueprints/platform-cloudflare-cron-triggers/docs/topics.md +1 -1
  373. package/blueprints/platform-cloudflare-durable-objects/CHANGELOG.md +6 -10
  374. package/blueprints/platform-cloudflare-durable-objects/docs/topics.md +1 -1
  375. package/blueprints/platform-cloudflare-kv/CHANGELOG.md +16 -12
  376. package/blueprints/platform-cloudflare-kv/README.md +2 -4
  377. package/blueprints/platform-cloudflare-kv/blueprint.json +2 -2
  378. package/blueprints/platform-cloudflare-kv/docs/topics.md +1 -1
  379. package/blueprints/platform-docker-compose-host/CHANGELOG.md +92 -5
  380. package/blueprints/platform-docker-compose-host/blueprint.json +2 -2
  381. package/blueprints/platform-docker-compose-host/contributions/probes/caddyfile-validate.mjs +116 -29
  382. package/blueprints/platform-docker-compose-host/contributions/probes/compose-config-lint.mjs +181 -109
  383. package/blueprints/platform-docker-compose-host/contributions/probes/probe-utils.mjs +146 -26
  384. package/blueprints/platform-docker-compose-host/contributions/probes/real-account-minimal-stack-up.mjs +238 -24
  385. package/blueprints/platform-docker-compose-host/contributions/probes/real-account-reload-burst.mjs +207 -21
  386. package/blueprints/platform-docker-compose-host/contributions/probes/secrets-as-files-scan.mjs +246 -42
  387. package/blueprints/platform-docker-compose-host/docs/topics.md +1 -1
  388. package/blueprints/security-auth-clerk/CHANGELOG.md +18 -6
  389. package/blueprints/security-auth-clerk/README.md +3 -3
  390. package/blueprints/security-auth-clerk/assets/wiring/workers-wrangler-toml-shape.md +1 -1
  391. package/blueprints/security-auth-clerk/blueprint.json +3 -2
  392. package/blueprints/security-auth-clerk/contributions/probes/hosted-identity-ui-config.mjs +61 -0
  393. package/blueprints/security-auth-clerk/contributions/probes/probe-utils.mjs +188 -0
  394. package/blueprints/security-auth-clerk/contributions/probes/real-account-principal-directory-round-trip.mjs +216 -0
  395. package/blueprints/security-auth-clerk/contributions/probes/real-account-session-inventory.mjs +260 -0
  396. package/blueprints/security-auth-clerk/contributions/probes/role-model-adapter.mjs +53 -0
  397. package/blueprints/security-auth-clerk/contributions/probes/run-hosted-identity-ui-config.mjs +4 -0
  398. package/blueprints/security-auth-clerk/contributions/probes/run-real-account-principal-directory-round-trip.mjs +4 -0
  399. package/blueprints/security-auth-clerk/contributions/probes/run-real-account-session-inventory.mjs +4 -0
  400. package/blueprints/security-auth-clerk/contributions/probes/run-role-model-adapter.mjs +4 -0
  401. package/blueprints/security-auth-clerk/docs/topics.md +2 -3
  402. package/blueprints/security-auth-keycloak/CHANGELOG.md +18 -7
  403. package/blueprints/security-auth-keycloak/README.md +2 -2
  404. package/blueprints/security-auth-keycloak/blueprint.json +3 -2
  405. package/blueprints/security-auth-keycloak/contributions/probes/discovery-shape.mjs +68 -0
  406. package/blueprints/security-auth-keycloak/contributions/probes/introspection-shape.mjs +88 -0
  407. package/blueprints/security-auth-keycloak/contributions/probes/jwt-verifier-shape.mjs +86 -0
  408. package/blueprints/security-auth-keycloak/contributions/probes/probe-utils.mjs +180 -0
  409. package/blueprints/security-auth-keycloak/contributions/probes/real-account-realm-round-trip.mjs +91 -0
  410. package/blueprints/security-auth-keycloak/contributions/probes/role-adapter-shape.mjs +69 -0
  411. package/blueprints/security-auth-keycloak/contributions/probes/run-discovery-shape.mjs +4 -0
  412. package/blueprints/security-auth-keycloak/contributions/probes/run-introspection-shape.mjs +4 -0
  413. package/blueprints/security-auth-keycloak/contributions/probes/run-jwt-verifier-shape.mjs +4 -0
  414. package/blueprints/security-auth-keycloak/contributions/probes/run-real-account-realm-round-trip.mjs +4 -0
  415. package/blueprints/security-auth-keycloak/contributions/probes/run-role-adapter-shape.mjs +4 -0
  416. package/blueprints/security-auth-keycloak/docs/topics.md +1 -2
  417. package/blueprints/security-auth-magic-link/CHANGELOG.md +15 -4
  418. package/blueprints/security-auth-magic-link/README.md +2 -2
  419. package/blueprints/security-auth-magic-link/assets/principal-registry-samples/single-address.md +1 -1
  420. package/blueprints/security-auth-magic-link/blueprint.json +3 -2
  421. package/blueprints/security-auth-magic-link/contributions/probes/probe-utils.mjs +174 -0
  422. package/blueprints/security-auth-magic-link/contributions/probes/real-account-magic-link-send.mjs +139 -0
  423. package/blueprints/security-auth-magic-link/contributions/probes/run-real-account-magic-link-send.mjs +4 -0
  424. package/blueprints/security-auth-magic-link/contributions/probes/run-token-entropy-shape.mjs +4 -0
  425. package/blueprints/security-auth-magic-link/contributions/probes/run-token-issue-verify.mjs +4 -0
  426. package/blueprints/security-auth-magic-link/contributions/probes/token-entropy-shape.mjs +60 -0
  427. package/blueprints/security-auth-magic-link/contributions/probes/token-issue-verify.mjs +90 -0
  428. package/blueprints/security-auth-magic-link/docs/topics.md +1 -1
  429. package/blueprints/security-auth-oauth2/CHANGELOG.md +16 -5
  430. package/blueprints/security-auth-oauth2/README.md +2 -2
  431. package/blueprints/security-auth-oauth2/blueprint.json +3 -2
  432. package/blueprints/security-auth-oauth2/contributions/probes/authorisation-code-flow-shape.mjs +259 -0
  433. package/blueprints/security-auth-oauth2/contributions/probes/pkce-challenge-shape.mjs +58 -0
  434. package/blueprints/security-auth-oauth2/contributions/probes/probe-utils.mjs +190 -0
  435. package/blueprints/security-auth-oauth2/contributions/probes/provider-adapter-shape.mjs +64 -0
  436. package/blueprints/security-auth-oauth2/contributions/probes/real-account-authorisation-code-flow.mjs +93 -0
  437. package/blueprints/security-auth-oauth2/contributions/probes/run-authorisation-code-flow-shape.mjs +4 -0
  438. package/blueprints/security-auth-oauth2/contributions/probes/run-pkce-challenge-shape.mjs +4 -0
  439. package/blueprints/security-auth-oauth2/contributions/probes/run-provider-adapter-shape.mjs +4 -0
  440. package/blueprints/security-auth-oauth2/contributions/probes/run-real-account-authorisation-code-flow.mjs +4 -0
  441. package/blueprints/security-auth-oauth2/contributions/probes/run-session-bridge-shape.mjs +4 -0
  442. package/blueprints/security-auth-oauth2/contributions/probes/session-bridge-shape.mjs +78 -0
  443. package/blueprints/security-auth-oauth2/docs/topics.md +1 -2
  444. package/blueprints/security-secrets-management/CHANGELOG.md +15 -4
  445. package/blueprints/security-secrets-management/README.md +2 -2
  446. package/blueprints/security-secrets-management/blueprint.json +3 -2
  447. package/blueprints/security-secrets-management/contributions/probes/add-recipient-rotation.mjs +107 -0
  448. package/blueprints/security-secrets-management/contributions/probes/encrypt-decrypt-round-trip.mjs +122 -0
  449. package/blueprints/security-secrets-management/contributions/probes/key-rotation.mjs +93 -0
  450. package/blueprints/security-secrets-management/contributions/probes/mismatched-key-refusal.mjs +74 -0
  451. package/blueprints/security-secrets-management/contributions/probes/probe-utils.mjs +214 -0
  452. package/blueprints/security-secrets-management/contributions/probes/run-add-recipient-rotation.mjs +4 -0
  453. package/blueprints/security-secrets-management/contributions/probes/run-encrypt-decrypt-round-trip.mjs +4 -0
  454. package/blueprints/security-secrets-management/contributions/probes/run-key-rotation.mjs +4 -0
  455. package/blueprints/security-secrets-management/contributions/probes/run-mismatched-key-refusal.mjs +4 -0
  456. package/blueprints/security-secrets-management/docs/topics.md +2 -3
  457. package/fixtures/canary-manifest.json +9 -9
  458. package/guidance/harness-template.md +25 -0
  459. package/guidance/managed/agent-instructions-block.hash +1 -1
  460. package/guidance/managed/agent-instructions-block.md +25 -0
  461. package/package.json +2 -2
  462. package/rcf/adrs/adr-4101-feedback-store-gitignored.json +20 -0
  463. package/rcf/adrs/adr-4102-fingerprint-and-labels.json +25 -0
  464. package/rcf/adrs/adr-4103-redaction-rule-based.json +20 -0
  465. package/rcf/adrs/adr-4104-destination-on-library.json +25 -0
  466. package/rcf/adrs/adr-4105-gh-ambient-auth.json +20 -0
  467. package/rcf/adrs/adr-4106-bundled-entries-terminal.json +20 -0
  468. package/rcf/adrs/adr-4107-stop-is-ask-event.json +30 -0
  469. package/rcf/adrs/adr-4108-hooks-in-committed-config.json +25 -0
  470. package/rcf/adrs/adr-4109-referee-validate-adr-crosslinks.json +25 -0
  471. package/rcf/adrs/adr-4110-referee-coverage-strict-by-default.json +25 -0
  472. package/rcf/adrs/adr-4111-referee-finalise-refusals.json +20 -0
  473. package/rcf/adrs/adr-4112-referee-finalise-verified-invariant.json +30 -0
  474. package/rcf/code-nodes/cn-600.json +45 -0
  475. package/rcf/code-nodes/cn-601.json +18 -0
  476. package/rcf/code-nodes/cn-602.json +15 -0
  477. package/rcf/code-nodes/cn-603.json +12 -0
  478. package/rcf/code-nodes/cn-604.json +14 -0
  479. package/rcf/code-nodes/cn-605.json +17 -0
  480. package/rcf/code-nodes/cn-606.json +12 -0
  481. package/rcf/code-nodes/cn-607.json +12 -0
  482. package/rcf/code-nodes/cn-608.json +14 -0
  483. package/rcf/code-nodes/cn-609.json +17 -0
  484. package/rcf/code-nodes/cn-620.json +18 -0
  485. package/rcf/code-nodes/cn-621.json +14 -0
  486. package/rcf/code-nodes/cn-622.json +15 -0
  487. package/rcf/code-nodes/cn-623.json +16 -0
  488. package/rcf/code-nodes/cn-624.json +14 -0
  489. package/rcf/code-nodes/cn-625.json +15 -0
  490. package/rcf/code-nodes/cn-626.json +13 -0
  491. package/rcf/code-nodes/cn-627.json +13 -0
  492. package/rcf/code-nodes/cn-628.json +14 -0
  493. package/rcf/code-nodes/cn-629.json +12 -0
  494. package/rcf/code-nodes/cn-630.json +12 -0
  495. package/rcf/code-nodes/cn-631.json +13 -0
  496. package/rcf/code-nodes/cn-632.json +13 -0
  497. package/rcf/fbs/fbs-180.json +45 -0
  498. package/rcf/fbs/fbs-181.json +45 -0
  499. package/rcf/fbs/fbs-182.json +42 -0
  500. package/rcf/fbs/fbs-183.json +50 -0
  501. package/rcf/fbs/fbs-184.json +49 -0
  502. package/rcf/fbs/fbs-185.json +34 -0
  503. package/rcf/fbs/fbs-186.json +16 -0
  504. package/rcf/fbs/fbs-187.json +17 -0
  505. package/rcf/fbs/fbs-188.json +17 -0
  506. package/rcf/fbs/fbs-189.json +17 -0
  507. package/rcf/requirements/req-155.json +13 -0
  508. package/rcf/requirements/req-156.json +13 -0
  509. package/rcf/requirements/req-157.json +13 -0
  510. package/rcf/requirements/req-158.json +13 -0
  511. package/rcf/requirements/req-159.json +13 -0
  512. package/rcf/requirements/req-160.json +13 -0
  513. package/rcf/requirements/req-161.json +13 -0
  514. package/rcf/requirements/req-162.json +13 -0
  515. package/rcf/requirements/req-163.json +13 -0
  516. package/rcf/requirements/req-164.json +13 -0
  517. package/rcf/requirements/req-165.json +13 -0
  518. package/rcf/tacs/tac-4101-feedback-cli.json +77 -0
  519. package/rcf/tacs/tac-4102-feedback-store.json +50 -0
  520. package/rcf/tacs/tac-4103-feedback-redact.json +39 -0
  521. package/rcf/tacs/tac-4104-feedback-fingerprint.json +33 -0
  522. package/rcf/tacs/tac-4105-feedback-render.json +45 -0
  523. package/rcf/tacs/tac-4106-feedback-destination.json +39 -0
  524. package/rcf/tacs/tac-4107-feedback-gh.json +43 -0
  525. package/rcf/tacs/tac-4108-feedback-hook.json +46 -0
  526. package/rcf/tacs/tac-4109-referee-validate-adr-crosslinks.json +20 -0
  527. package/rcf/tacs/tac-4110-referee-coverage-mode-selector.json +21 -0
  528. package/rcf/tacs/tac-4111-referee-finalise-per-ac-refusals.json +21 -0
  529. package/rcf/tacs/tac-4112-referee-finalise-verified-invariant.json +22 -0
  530. package/rcf/test-suites/ts-140.json +9 -9
  531. package/rcf/test-suites/ts-150.json +9 -9
  532. package/rcf/test-suites/ts-185.json +54 -0
  533. package/rcf/test-suites/ts-186.json +58 -0
  534. package/rcf/test-suites/ts-187.json +44 -0
  535. package/rcf/test-suites/ts-188.json +166 -0
  536. package/rcf/test-suites/ts-189.json +38 -0
  537. package/rcf/test-suites/ts-190.json +30 -0
  538. package/rcf/test-suites/ts-191.json +51 -0
  539. package/rcf/test-suites/ts-192.json +37 -0
  540. package/rcf/test-suites/ts-193.json +60 -0
  541. package/rcf/test-suites/ts-194.json +67 -0
  542. package/rcf/test-suites/ts-195.json +52 -0
  543. package/rcf/test-suites/ts-196.json +58 -0
  544. package/rcf/test-suites/ts-197.json +66 -0
  545. package/rcf/test-suites/ts-198.json +87 -0
  546. package/rcf/test-suites/ts-199.json +51 -0
  547. package/rcf/test-suites/ts-200.json +30 -0
  548. package/rcf/test-suites/ts-201.json +38 -0
  549. package/rcf/test-suites/ts-202.json +38 -0
  550. package/rcf/test-suites/ts-203.json +38 -0
  551. package/rcf/user-stories/us-15501.json +60 -0
  552. package/rcf/user-stories/us-15502.json +33 -0
  553. package/rcf/user-stories/us-15503.json +33 -0
  554. package/rcf/user-stories/us-15601.json +51 -0
  555. package/rcf/user-stories/us-15701.json +42 -0
  556. package/rcf/user-stories/us-15801.json +42 -0
  557. package/rcf/user-stories/us-15802.json +33 -0
  558. package/rcf/user-stories/us-15901.json +33 -0
  559. package/rcf/user-stories/us-15902.json +51 -0
  560. package/rcf/user-stories/us-16001.json +51 -0
  561. package/rcf/user-stories/us-16101.json +42 -0
  562. package/rcf/user-stories/us-16102.json +33 -0
  563. package/rcf/user-stories/us-16103.json +42 -0
  564. package/rcf/user-stories/us-16104.json +42 -0
  565. package/rcf/user-stories/us-16201.json +33 -0
  566. package/rcf/user-stories/us-16301.json +36 -0
  567. package/rcf/user-stories/us-16401.json +45 -0
  568. package/rcf/user-stories/us-16501.json +45 -0
  569. package/rcf/user-stories/us-16502.json +45 -0
  570. package/releases/releases.yaml +11 -1
  571. package/src/blueprint/library-loader.js +48 -0
  572. package/src/blueprint/library-registry.js +13 -0
  573. package/src/browser-verify/pack-runner.js +7 -12
  574. package/src/build/mark.js +1 -1
  575. package/src/cli/blueprint-library.js +149 -0
  576. package/src/cli/coverage.js +49 -24
  577. package/src/cli/doctor.js +195 -7
  578. package/src/cli/feedback.js +2204 -0
  579. package/src/cli/finalise.js +158 -1
  580. package/src/cli/help.js +6 -0
  581. package/src/cli/init.js +63 -0
  582. package/src/cli/update.js +21 -1
  583. package/src/core/store/walker.js +33 -0
  584. package/src/core/store/writer.js +23 -0
  585. package/src/feedback/destination.js +361 -0
  586. package/src/feedback/fingerprint.js +132 -0
  587. package/src/feedback/gh.js +376 -0
  588. package/src/feedback/hook.js +183 -0
  589. package/src/feedback/labels.js +87 -0
  590. package/src/feedback/redact-allowlist.json +14 -0
  591. package/src/feedback/redact.js +1108 -0
  592. package/src/feedback/render.js +267 -0
  593. package/src/feedback/store.js +604 -0
  594. package/src/finalise/index.js +4 -0
  595. package/src/finalise/ingest.js +61 -0
  596. package/src/finalise/ship-without-eval.js +19 -7
  597. package/src/mcp/tools.js +8 -2
  598. package/src/setup/feedback-hooks.js +397 -0
  599. package/src/setup/managed-gitignore.js +3 -0
  600. package/src/view/html-page.js +5 -5
  601. package/src/view/style.css +2 -2
@@ -0,0 +1,604 @@
1
+ // Feedback local store (TAC-4102). Slice 1 (FBS-180): the on-disk log
2
+ // under `.rcf/feedback/`. Append-only JSONL for entries, fold-by-id on
3
+ // read; a per-session state ledger at `state.json`; an outbox directory
4
+ // for bundle files (written in slice 4, referenced here so the store's
5
+ // path helpers are complete).
6
+ //
7
+ // The store is gitignored via the 0.6.0 managed-block aggregator
8
+ // (`src/setup/managed-gitignore.js`). This module OWNS the aggregator
9
+ // entry constant (`feedbackGitignoreEntry`), mirroring the pattern in
10
+ // `src/preflight/secrets.js:preflightEntry` and
11
+ // `src/setup/identity-seed.js:identityEntry`. Adding it to the
12
+ // aggregator is a one-import, one-array-line change.
13
+ //
14
+ // A pre-write refusal (`ensureGitignore`) is the belt to the aggregator's
15
+ // braces: on a project whose `.gitignore` does not effectively cover
16
+ // `.rcf/feedback/` the first `rcf feedback add` refuses instead of
17
+ // creating the log, protecting a pre-upgrade project against an
18
+ // accidental push of raw entries. `--force` overrides for the test
19
+ // path and for the operator who has audited their `.gitignore` by
20
+ // hand.
21
+
22
+ import {
23
+ appendFile, mkdir, readFile, stat, writeFile,
24
+ } from 'node:fs/promises';
25
+ import { dirname, join } from 'node:path';
26
+ import { spawn } from 'node:child_process';
27
+
28
+ /** Absolute path helpers under a project root. */
29
+ const FEEDBACK_DIR = '.rcf/feedback';
30
+
31
+ /**
32
+ * Relative path (from project root) of the per-project feedback
33
+ * settings file. Committed to the repo; the hooks and the CLI treat
34
+ * this as the source of truth for `ask`, `quietMinutes` and the
35
+ * `redaction.allowHosts` extension list (design section 8).
36
+ */
37
+ export const FEEDBACK_SETTINGS_PATH = 'rcf/feedback-settings.json';
38
+
39
+ /**
40
+ * Default settings the hook and the ask-branch fall back to when
41
+ * `rcf/feedback-settings.json` is missing or empty. `ask: true` keeps
42
+ * the RULE 17 posture: silent capture, one ask per session at a
43
+ * pause, unless the operator has opted out for the project.
44
+ */
45
+ export const DEFAULT_FEEDBACK_SETTINGS = Object.freeze({
46
+ settingsVersion: 1,
47
+ ask: true,
48
+ quietMinutes: 15,
49
+ redaction: Object.freeze({ allowHosts: [] }),
50
+ });
51
+
52
+ /**
53
+ * Managed-gitignore aggregator entry (§4.1's 0.7.0-style extension:
54
+ * feature modules own their entry constant; the aggregator imports it).
55
+ * The trailing slash keeps the whole directory ignored (log, state,
56
+ * outbox and any future sibling files).
57
+ */
58
+ export const feedbackGitignoreEntry = Object.freeze({
59
+ path: '.rcf/feedback/',
60
+ owner: 'rcf feedback: local feedback log and outbox (never committed)',
61
+ since: '0.28.0',
62
+ });
63
+
64
+ /**
65
+ * @param {string} projectRoot
66
+ * @returns {string}
67
+ */
68
+ export function feedbackDir(projectRoot) {
69
+ return join(projectRoot, FEEDBACK_DIR);
70
+ }
71
+
72
+ /**
73
+ * @param {string} projectRoot
74
+ * @returns {string}
75
+ */
76
+ export function entriesPath(projectRoot) {
77
+ return join(projectRoot, FEEDBACK_DIR, 'entries.jsonl');
78
+ }
79
+
80
+ /**
81
+ * @param {string} projectRoot
82
+ * @returns {string}
83
+ */
84
+ export function statePath(projectRoot) {
85
+ return join(projectRoot, FEEDBACK_DIR, 'state.json');
86
+ }
87
+
88
+ /**
89
+ * @param {string} projectRoot
90
+ * @returns {string}
91
+ */
92
+ export function outboxDir(projectRoot) {
93
+ return join(projectRoot, FEEDBACK_DIR, 'outbox');
94
+ }
95
+
96
+ /**
97
+ * @typedef {object} FeedbackEntry
98
+ * @property {string} id fb-<yyyymmdd>-<4-hex>
99
+ * @property {string} recordedAt ISO timestamp
100
+ * @property {string} sessionId session id at capture time
101
+ * @property {'blueprint' | 'core'} kind
102
+ * @property {object} target see design §4.1
103
+ * @property {string | null} anchor AC/REQ/TAC/ADR id, or null
104
+ * @property {string} symptomClass closed enum (design §6)
105
+ * @property {'blocker' | 'major' | 'minor'} severity
106
+ * @property {string} title <= 120 chars
107
+ * @property {string} body <= 8 KB
108
+ * @property {Array<{ kind: string, value: string }>} evidence
109
+ * @property {object} environment harness / rcfLiteVersion / nodeVersion / platform
110
+ * @property {boolean} askNow
111
+ * @property {'pending' | 'submitted' | 'bundled' | 'discarded' | 'deferredUntilSession'} status
112
+ * @property {object} destination
113
+ */
114
+
115
+ /**
116
+ * @typedef {object} StateTransition
117
+ * @property {string} id
118
+ * @property {string} at ISO timestamp
119
+ * @property {'pending' | 'submitted' | 'bundled' | 'deferredUntilSession' | 'discarded'} status
120
+ * @property {string} [issueUrl]
121
+ * @property {string} [outboxPath]
122
+ * @property {'new' | 'comment' | 'unchecked'} [dedupe]
123
+ * @property {string} [sessionId]
124
+ */
125
+
126
+ /**
127
+ * Read `entries.jsonl` and fold by id: for each id the LAST line wins.
128
+ * Returns an array of current-state entries in first-seen order, so
129
+ * `list` prints them by recording time by default.
130
+ *
131
+ * @param {string} projectRoot
132
+ * @returns {Promise<FeedbackEntry[]>}
133
+ */
134
+ export async function readEntries(projectRoot) {
135
+ let text;
136
+ try {
137
+ text = await readFile(entriesPath(projectRoot), 'utf8');
138
+ } catch (err) {
139
+ if (/** @type {NodeJS.ErrnoException} */ (err).code === 'ENOENT') return [];
140
+ throw err;
141
+ }
142
+ const byId = new Map();
143
+ const order = [];
144
+ for (const raw of text.split('\n')) {
145
+ const line = raw.trim();
146
+ if (line === '') continue;
147
+ let obj;
148
+ try {
149
+ obj = JSON.parse(line);
150
+ } catch {
151
+ // A malformed line is not the store's failure surface; the writer
152
+ // never appends malformed lines. If one appears, skip and let the
153
+ // audit tools surface it.
154
+ continue;
155
+ }
156
+ if (typeof obj?.id !== 'string') continue;
157
+ if (!byId.has(obj.id)) {
158
+ order.push(obj.id);
159
+ byId.set(obj.id, obj);
160
+ } else {
161
+ byId.set(obj.id, { ...byId.get(obj.id), ...obj });
162
+ }
163
+ }
164
+ return order.map((id) => byId.get(id));
165
+ }
166
+
167
+ /**
168
+ * Append one entry to the JSONL log. Ensures the parent directory
169
+ * exists (mkdir recursive) so the first call on a fresh project does
170
+ * not require a separate init step.
171
+ *
172
+ * @param {string} projectRoot
173
+ * @param {FeedbackEntry} entry
174
+ * @returns {Promise<void>}
175
+ */
176
+ export async function appendEntry(projectRoot, entry) {
177
+ await mkdir(feedbackDir(projectRoot), { recursive: true });
178
+ const line = `${JSON.stringify(entry)}\n`;
179
+ await appendFile(entriesPath(projectRoot), line, 'utf8');
180
+ }
181
+
182
+ /**
183
+ * Read the raw JSONL log and return the FIRST `discarded` transition
184
+ * timestamp per id. Used by the retention sweep so the 30-day clock
185
+ * runs from when the operator discarded the entry, not from when it
186
+ * was first recorded (F-slice-1-09 fix: an entry discarded today that
187
+ * was recorded 60 days ago must not prune on the next add).
188
+ *
189
+ * @param {string} projectRoot
190
+ * @returns {Promise<Map<string, string>>}
191
+ */
192
+ export async function readDiscardTimestamps(projectRoot) {
193
+ const out = new Map();
194
+ let text;
195
+ try {
196
+ text = await readFile(entriesPath(projectRoot), 'utf8');
197
+ } catch (err) {
198
+ if (/** @type {NodeJS.ErrnoException} */ (err).code === 'ENOENT') return out;
199
+ throw err;
200
+ }
201
+ for (const raw of text.split('\n')) {
202
+ const line = raw.trim();
203
+ if (line === '') continue;
204
+ let obj;
205
+ try { obj = JSON.parse(line); } catch { continue; }
206
+ if (typeof obj?.id !== 'string') continue;
207
+ if (obj.status !== 'discarded') continue;
208
+ if (out.has(obj.id)) continue;
209
+ // A real state transition carries `at`; a seeded initial entry
210
+ // written with status:'discarded' from the start has only
211
+ // `recordedAt`. Both are legitimate first-discarded timestamps.
212
+ const ts = typeof obj.at === 'string'
213
+ ? obj.at
214
+ : (typeof obj.recordedAt === 'string' ? obj.recordedAt : null);
215
+ if (ts) out.set(obj.id, ts);
216
+ }
217
+ return out;
218
+ }
219
+
220
+ /**
221
+ * Append one state-transition line for an existing id. Callers pass a
222
+ * SHAPE that the reader's fold-by-id merges over the base entry; state
223
+ * transitions are additive, never destructive rewrites.
224
+ *
225
+ * @param {string} projectRoot
226
+ * @param {StateTransition} transition
227
+ * @returns {Promise<void>}
228
+ */
229
+ export async function appendState(projectRoot, transition) {
230
+ await mkdir(feedbackDir(projectRoot), { recursive: true });
231
+ const line = `${JSON.stringify(transition)}\n`;
232
+ await appendFile(entriesPath(projectRoot), line, 'utf8');
233
+ }
234
+
235
+ /**
236
+ * Read the per-session ask ledger (`state.json`). Missing file returns
237
+ * the empty ledger. The shape is `{ asked: Array<{ sessionId, askedAt }>, queueStateAt: string | null }`;
238
+ * slice 5 fills it, slice 1 keeps the reader here so the whole store's
239
+ * shape lives in one file.
240
+ *
241
+ * @param {string} projectRoot
242
+ * @returns {Promise<{ asked: Array<{ sessionId: string, askedAt: string }>, queueStateAt: string | null }>}
243
+ */
244
+ export async function readAskLedger(projectRoot) {
245
+ try {
246
+ const text = await readFile(statePath(projectRoot), 'utf8');
247
+ const parsed = JSON.parse(text);
248
+ return {
249
+ asked: Array.isArray(parsed?.asked) ? parsed.asked : [],
250
+ queueStateAt: typeof parsed?.queueStateAt === 'string' ? parsed.queueStateAt : null,
251
+ };
252
+ } catch (err) {
253
+ if (/** @type {NodeJS.ErrnoException} */ (err).code === 'ENOENT') {
254
+ return { asked: [], queueStateAt: null };
255
+ }
256
+ throw err;
257
+ }
258
+ }
259
+
260
+ /**
261
+ * Overwrite the ask ledger. Only slice 5 needs to write this; slice 1
262
+ * exports the writer so tests can seed a ledger without a private
263
+ * import path.
264
+ *
265
+ * @param {string} projectRoot
266
+ * @param {{ asked: Array<{ sessionId: string, askedAt: string }>, queueStateAt: string | null }} ledger
267
+ * @returns {Promise<void>}
268
+ */
269
+ export async function writeAskLedger(projectRoot, ledger) {
270
+ await mkdir(feedbackDir(projectRoot), { recursive: true });
271
+ await writeFile(statePath(projectRoot), `${JSON.stringify(ledger, null, 2)}\n`, 'utf8');
272
+ }
273
+
274
+ /**
275
+ * Pre-write gitignore check. Returns `{ ok: true }` when git itself
276
+ * would ignore the feedback store path we are about to write; returns
277
+ * `{ ok: false, reason }` otherwise. Callers with `--force` bypass the
278
+ * check.
279
+ *
280
+ * F-slice-1-01 regression fix: the previous implementation walked
281
+ * `.gitignore` as a literal state machine and only recognised a small
282
+ * covers-set (`.rcf/feedback/`, `.rcf/`, ...) plus a hand-coded
283
+ * negation shortlist. That both missed valid wildcard shapes (`.rcf/*`
284
+ * covers the dir, but was rejected) and mis-judged the ignored-parent
285
+ * case (`.rcf/feedback/` + `!.rcf/feedback/*`: git cannot re-include a
286
+ * file whose parent is ignored, so the store is still safe, but the
287
+ * literal walker set `ignored=false` and refused). Delegating to
288
+ * `git check-ignore` means we judge the path the way git will judge it
289
+ * on the next `git add .`, which is the guarantee we actually need.
290
+ *
291
+ * When git is not installed or the project is not a git repo, we fall
292
+ * back to a conservative textual read of `.gitignore`: any line that
293
+ * folds one of `.rcf/feedback/`, `.rcf/feedback`, `.rcf/`, `.rcf`,
294
+ * `.rcf/*`, `.rcf/**`, or `.rcf/feedback/*` into the ignore set is
295
+ * enough. The fallback is deliberately generous because a machine
296
+ * without git cannot mis-publish through `git add`.
297
+ *
298
+ * @param {string} projectRoot
299
+ * @returns {Promise<{ ok: true } | { ok: false, reason: string }>}
300
+ */
301
+ export async function ensureGitignore(projectRoot) {
302
+ const probeRelative = join('.rcf', 'feedback', 'entries.jsonl');
303
+ const git = await runGitCheckIgnore(projectRoot, probeRelative);
304
+ if (git.ok !== null) {
305
+ if (git.ok) return { ok: true };
306
+ return { ok: false, reason: `git check-ignore says ${probeRelative} would be committed by git add` };
307
+ }
308
+ // Fallback (no git, or not a repo): permissive textual scan.
309
+ let text;
310
+ try {
311
+ text = await readFile(join(projectRoot, '.gitignore'), 'utf8');
312
+ } catch (err) {
313
+ if (/** @type {NodeJS.ErrnoException} */ (err).code === 'ENOENT') {
314
+ return { ok: false, reason: 'no .gitignore in project root' };
315
+ }
316
+ throw err;
317
+ }
318
+ // Walk .gitignore in order; toggle the ignored state whenever a
319
+ // line (positive or `!` negation) covers the feedback store. The
320
+ // last-word wins, which mirrors git's own last-match-wins semantics
321
+ // for a file whose parent chain is not itself excluded through a
322
+ // pattern the negation cannot re-include (which we cannot judge
323
+ // without git; the check-ignore path above does).
324
+ //
325
+ // Round 3 (fallback-negation regression): a `!` line whose pattern
326
+ // is NOT in the coversFeedback vocabulary might still re-include
327
+ // entries.jsonl under real git (e.g. `.rcf/feedback/*` paired with
328
+ // `!*.jsonl`). The fallback cannot judge safely, so remember the
329
+ // unrecognised negation and refuse ok:true when one appears
330
+ // alongside a positive ignore. The known-vocabulary case still
331
+ // toggles as before, preserving the last-word-wins semantics that
332
+ // the round-2 tests pinned.
333
+ let ignored = false;
334
+ let unknownNegation = null;
335
+ for (const rawLine of text.split('\n')) {
336
+ const line = rawLine.trim();
337
+ if (line === '' || line.startsWith('#')) continue;
338
+ const isNeg = line.startsWith('!');
339
+ const pattern = (isNeg ? line.slice(1) : line).replace(/\/+$/, '').replace(/^\.\//, '');
340
+ const covers = coversFeedback(pattern);
341
+ if (covers) {
342
+ ignored = !isNeg;
343
+ } else if (isNeg) {
344
+ unknownNegation = line;
345
+ }
346
+ }
347
+ if (ignored && unknownNegation) {
348
+ return {
349
+ ok: false,
350
+ reason: `.gitignore contains a negation the fallback cannot evaluate ('${unknownNegation}') and git is not available for check-ignore; install git (or 'git init' the project) so the check can decide safely`,
351
+ };
352
+ }
353
+ if (ignored) return { ok: true };
354
+ return { ok: false, reason: 'no .gitignore rule covers .rcf/feedback/' };
355
+ }
356
+
357
+ /**
358
+ * Does a gitignore pattern (leading `!` already stripped, trailing
359
+ * slash normalised) cover the feedback store directory or a file
360
+ * inside it? Recognises the literal directory / file paths plus the
361
+ * common wildcard shapes callers write (`.rcf/*`, `.rcf/**`,
362
+ * `.rcf/feedback/*`, `.rcf/feedback/**`).
363
+ *
364
+ * @param {string} pattern
365
+ * @returns {boolean}
366
+ */
367
+ function coversFeedback(pattern) {
368
+ const set = new Set([
369
+ '.rcf',
370
+ '.rcf/feedback',
371
+ '.rcf/feedback/entries.jsonl',
372
+ '.rcf/*',
373
+ '.rcf/**',
374
+ '.rcf/feedback/*',
375
+ '.rcf/feedback/**',
376
+ ]);
377
+ return set.has(pattern);
378
+ }
379
+
380
+ /**
381
+ * Run `git check-ignore -q <path>` in `projectRoot`. Returns `ok`
382
+ * true when git says the path would be ignored (exit 0), false when
383
+ * git says it would be committed (exit 1), and null when git could
384
+ * not answer (no git, not a repo, or any other error) so the caller
385
+ * knows to fall back.
386
+ *
387
+ * @param {string} projectRoot
388
+ * @param {string} relativePath
389
+ * @returns {Promise<{ ok: true | false | null, reason: string | null }>}
390
+ */
391
+ async function runGitCheckIgnore(projectRoot, relativePath) {
392
+ return new Promise((resolvePromise) => {
393
+ let child;
394
+ try {
395
+ child = spawn('git', ['check-ignore', '-q', relativePath], {
396
+ cwd: projectRoot,
397
+ env: process.env,
398
+ stdio: ['ignore', 'ignore', 'ignore'],
399
+ });
400
+ } catch {
401
+ resolvePromise({ ok: null, reason: 'git not spawnable' });
402
+ return;
403
+ }
404
+ let done = false;
405
+ const finish = (payload) => {
406
+ if (done) return;
407
+ done = true;
408
+ resolvePromise(payload);
409
+ };
410
+ child.on('error', () => finish({ ok: null, reason: 'git spawn error' }));
411
+ child.on('close', (code) => {
412
+ if (code === 0) finish({ ok: true, reason: null });
413
+ else if (code === 1) finish({ ok: false, reason: null });
414
+ else finish({ ok: null, reason: `git check-ignore exit ${code}` });
415
+ });
416
+ });
417
+ }
418
+
419
+ /**
420
+ * Generate a fresh entry id: `fb-<yyyymmdd>-<12-hex>`. Ruling R2
421
+ * (Dave 2026-09-16): 12-hex tail with a uniqueness probe on append
422
+ * so a busy day's 100+ findings do not collide (a 16-bit tail had a
423
+ * ~7.6% collision at 100 finds/day, which converted a distinct
424
+ * finding into a state transition on the old one via the fold-by-id
425
+ * reader). Callers should use `mintUniqueEntryId` when they can
426
+ * afford one read of the entries log; `newEntryId` remains the raw
427
+ * generator for tests that inject an rng.
428
+ *
429
+ * @param {Date} [now]
430
+ * @param {() => number} [rng] - 0..1; injectable for tests
431
+ * @returns {string}
432
+ */
433
+ export function newEntryId(now = new Date(), rng = Math.random) {
434
+ const yyyy = now.getUTCFullYear().toString().padStart(4, '0');
435
+ const mm = (now.getUTCMonth() + 1).toString().padStart(2, '0');
436
+ const dd = now.getUTCDate().toString().padStart(2, '0');
437
+ // 48 bits split into three 16-bit words so we never rely on 32-bit
438
+ // integer coercion and every call has full 48-bit entropy.
439
+ const words = [];
440
+ for (let i = 0; i < 3; i += 1) {
441
+ words.push(Math.floor(rng() * 0x10000).toString(16).padStart(4, '0'));
442
+ }
443
+ return `fb-${yyyy}${mm}${dd}-${words.join('')}`;
444
+ }
445
+
446
+ /**
447
+ * Mint an entry id and re-generate on collision. F-slice-1-03 /
448
+ * ruling R2: append is preceded by a uniqueness probe over the read
449
+ * entries so no two rows share an id. The retry budget is 32; if
450
+ * every generated id still collides (astronomically unlikely with
451
+ * 48 bits of entropy) the last generated id is returned so the caller
452
+ * can decide how to escalate.
453
+ *
454
+ * @param {string} projectRoot
455
+ * @param {Date} [now]
456
+ * @param {() => number} [rng]
457
+ * @returns {Promise<string>}
458
+ */
459
+ export async function mintUniqueEntryId(projectRoot, now = new Date(), rng = Math.random) {
460
+ const existing = new Set((await readEntries(projectRoot)).map((e) => e.id));
461
+ for (let i = 0; i < 32; i += 1) {
462
+ const id = newEntryId(now, rng);
463
+ if (!existing.has(id)) return id;
464
+ }
465
+ // F-slice-1-03 (fix round 2): fail closed rather than return a
466
+ // colliding id the caller would blindly append. R2's contract says
467
+ // "no two rows share an id"; returning the last colliding id would
468
+ // violate the shape even if the collision is astronomically
469
+ // unlikely (48 bits of entropy). handleAdd catches this and refuses
470
+ // the write with a usage-shaped error so the operator sees it.
471
+ const err = new Error(
472
+ 'entry-id retry exhausted: 32 mint attempts all collided with existing ids. '
473
+ + 'This is astronomically unlikely with 48 bits of entropy - suspect a corrupted '
474
+ + '.rcf/feedback/entries.jsonl or a broken rng seed.',
475
+ );
476
+ /** @type {any} */ (err).code = 'FEEDBACK_ID_EXHAUSTED';
477
+ throw err;
478
+ }
479
+
480
+ /**
481
+ * Read `rcf/feedback-settings.json` and fold onto the defaults. A
482
+ * missing file returns the defaults verbatim (design section 8: a
483
+ * project without the file is still an opted-in project); an
484
+ * unparseable file returns `{ settings: defaults, parseError }` so
485
+ * the caller can surface the fault without crashing the hook.
486
+ *
487
+ * @param {string} projectRoot
488
+ * @returns {Promise<{ settings: { settingsVersion: number, ask: boolean, quietMinutes: number, redaction: { allowHosts: string[] } }, parseError: string | null, present: boolean }>}
489
+ */
490
+ export async function readFeedbackSettings(projectRoot) {
491
+ const path = join(projectRoot, FEEDBACK_SETTINGS_PATH);
492
+ let text;
493
+ try {
494
+ text = await readFile(path, 'utf8');
495
+ } catch (err) {
496
+ if (/** @type {NodeJS.ErrnoException} */ (err).code === 'ENOENT') {
497
+ return {
498
+ settings: { ...DEFAULT_FEEDBACK_SETTINGS, redaction: { allowHosts: [] } },
499
+ parseError: null,
500
+ present: false,
501
+ };
502
+ }
503
+ throw err;
504
+ }
505
+ let parsed;
506
+ try {
507
+ parsed = JSON.parse(text);
508
+ } catch (err) {
509
+ return {
510
+ settings: { ...DEFAULT_FEEDBACK_SETTINGS, redaction: { allowHosts: [] } },
511
+ parseError: err.message,
512
+ present: true,
513
+ };
514
+ }
515
+ if (parsed === null || typeof parsed !== 'object' || Array.isArray(parsed)) {
516
+ return {
517
+ settings: { ...DEFAULT_FEEDBACK_SETTINGS, redaction: { allowHosts: [] } },
518
+ parseError: 'not a JSON object',
519
+ present: true,
520
+ };
521
+ }
522
+ const ask = typeof parsed.ask === 'boolean' ? parsed.ask : DEFAULT_FEEDBACK_SETTINGS.ask;
523
+ const quietMinutes = Number.isFinite(parsed.quietMinutes) && parsed.quietMinutes >= 0
524
+ ? parsed.quietMinutes
525
+ : DEFAULT_FEEDBACK_SETTINGS.quietMinutes;
526
+ const settingsVersion = Number.isFinite(parsed.settingsVersion)
527
+ ? parsed.settingsVersion
528
+ : DEFAULT_FEEDBACK_SETTINGS.settingsVersion;
529
+ const allowHosts = Array.isArray(parsed?.redaction?.allowHosts)
530
+ ? parsed.redaction.allowHosts.filter((v) => typeof v === 'string')
531
+ : [];
532
+ return {
533
+ settings: { settingsVersion, ask, quietMinutes, redaction: { allowHosts } },
534
+ parseError: null,
535
+ present: true,
536
+ };
537
+ }
538
+
539
+ /**
540
+ * Overwrite `rcf/feedback-settings.json`, merging over the current
541
+ * on-disk file (or the defaults, if absent). Callers pass the delta
542
+ * they want applied; other fields survive verbatim.
543
+ *
544
+ * @param {string} projectRoot
545
+ * @param {Partial<{ settingsVersion: number, ask: boolean, quietMinutes: number, redaction: { allowHosts: string[] } }>} delta
546
+ * @returns {Promise<{ path: string, action: 'created' | 'updated' | 'noop', settings: object }>}
547
+ */
548
+ export async function writeFeedbackSettings(projectRoot, delta) {
549
+ const path = join(projectRoot, FEEDBACK_SETTINGS_PATH);
550
+ let existed = true;
551
+ let currentText;
552
+ try {
553
+ currentText = await readFile(path, 'utf8');
554
+ } catch (err) {
555
+ if (/** @type {NodeJS.ErrnoException} */ (err).code === 'ENOENT') {
556
+ existed = false;
557
+ currentText = null;
558
+ } else {
559
+ throw err;
560
+ }
561
+ }
562
+ let base = { ...DEFAULT_FEEDBACK_SETTINGS, redaction: { allowHosts: [] } };
563
+ if (existed) {
564
+ try {
565
+ const parsed = JSON.parse(currentText);
566
+ if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {
567
+ base = { ...base, ...parsed };
568
+ if (parsed.redaction && typeof parsed.redaction === 'object' && !Array.isArray(parsed.redaction)) {
569
+ base.redaction = { allowHosts: Array.isArray(parsed.redaction.allowHosts) ? [...parsed.redaction.allowHosts] : [] };
570
+ }
571
+ }
572
+ } catch { /* fall through with defaults */ }
573
+ }
574
+ const next = {
575
+ ...base,
576
+ ...delta,
577
+ redaction: delta?.redaction ? { ...base.redaction, ...delta.redaction } : base.redaction,
578
+ };
579
+ const serialized = `${JSON.stringify(next, null, 2)}\n`;
580
+ if (existed && serialized === currentText) {
581
+ return { path, action: 'noop', settings: next };
582
+ }
583
+ await mkdir(dirname(path), { recursive: true });
584
+ await writeFile(path, serialized, 'utf8');
585
+ return { path, action: existed ? 'updated' : 'created', settings: next };
586
+ }
587
+
588
+ /**
589
+ * Existence probe used by `rcf feedback status` to decide whether the
590
+ * store has ever been written to. Not a truth-source for entries; use
591
+ * `readEntries` for that.
592
+ *
593
+ * @param {string} projectRoot
594
+ * @returns {Promise<boolean>}
595
+ */
596
+ export async function storeExists(projectRoot) {
597
+ try {
598
+ await stat(entriesPath(projectRoot));
599
+ return true;
600
+ } catch (err) {
601
+ if (/** @type {NodeJS.ErrnoException} */ (err).code === 'ENOENT') return false;
602
+ throw err;
603
+ }
604
+ }
@@ -25,6 +25,10 @@ export {
25
25
  // rcf-eval-node spec 2026-09-04 sections 5.2 + 8: EVAL-MISSING and
26
26
  // EVAL-BELOW-THRESHOLD refusal on `rcf finalise`.
27
27
  findEvalRefusalAcs, reportHasEvalRefusal,
28
+ // Referee-guarantee train (REQ-165, docs claims C-28 / C-29 / C-36):
29
+ // finalise refuses on UI-BASELINE-UNMET and BROWSER-VERIFICATION-MISSING.
30
+ findUiBaselineUnmetAcs, reportHasUiBaselineUnmet,
31
+ findBrowserVerificationMissingAcs, reportHasBrowserVerificationMissing,
28
32
  } from './ingest.js';
29
33
  export {
30
34
  composeShipWithoutVerifiedRecord,
@@ -185,3 +185,64 @@ export function findEvalRefusalAcs(report) {
185
185
  export function reportHasEvalRefusal(report) {
186
186
  return findEvalRefusalAcs(report).length > 0;
187
187
  }
188
+
189
+ /**
190
+ * Referee-guarantee train (REQ-165 / US-16501, docs claims C-28 / C-36).
191
+ * Extract per-AC verdicts in {UI-BASELINE-UNMET} from a verify report.
192
+ * The verdict is emitted by `uiPerAcVerdict` when a UI-bearing FBS has
193
+ * a bound `browserVerification[]` record whose `verdict` came back
194
+ * `block`; a block-severity probe-pack failure aggregates into the same
195
+ * verdict (docs claim C-36). Earlier reports carry no perAcVerdicts
196
+ * field; this returns an empty array in that case.
197
+ *
198
+ * @param {object} report
199
+ * @returns {Array<{ acId: string, verdict: string, reason?: string }>}
200
+ */
201
+ export function findUiBaselineUnmetAcs(report) {
202
+ const perAc = Array.isArray(report?.perAcVerdicts) ? report.perAcVerdicts : [];
203
+ return perAc
204
+ .filter((e) => e && e.verdict === 'UI-BASELINE-UNMET')
205
+ .map((e) => ({ acId: e.acId, verdict: e.verdict, reason: e.reason }));
206
+ }
207
+
208
+ /**
209
+ * True when a verify report carries at least one UI-BASELINE-UNMET verdict.
210
+ * Consumed by the finalise gate to refuse promotion to `verified` on a
211
+ * failed UI baseline check (referee-guarantee C-28 / C-36).
212
+ *
213
+ * @param {object} report
214
+ * @returns {boolean}
215
+ */
216
+ export function reportHasUiBaselineUnmet(report) {
217
+ return findUiBaselineUnmetAcs(report).length > 0;
218
+ }
219
+
220
+ /**
221
+ * Referee-guarantee train (REQ-165 / US-16501, docs claim C-29).
222
+ * Extract per-AC verdicts in {BROWSER-VERIFICATION-MISSING} from a
223
+ * verify report. Emitted by `uiPerAcVerdict` when a UI-bearing FBS has
224
+ * no `browserVerification[]` record on the manifest (verify has nothing
225
+ * to read for the baseline check).
226
+ *
227
+ * @param {object} report
228
+ * @returns {Array<{ acId: string, verdict: string, reason?: string }>}
229
+ */
230
+ export function findBrowserVerificationMissingAcs(report) {
231
+ const perAc = Array.isArray(report?.perAcVerdicts) ? report.perAcVerdicts : [];
232
+ return perAc
233
+ .filter((e) => e && e.verdict === 'BROWSER-VERIFICATION-MISSING')
234
+ .map((e) => ({ acId: e.acId, verdict: e.verdict, reason: e.reason }));
235
+ }
236
+
237
+ /**
238
+ * True when a verify report carries at least one
239
+ * BROWSER-VERIFICATION-MISSING verdict. Consumed by the finalise gate
240
+ * to refuse promotion to `verified` on a UI-bearing FBS whose bound
241
+ * browser-verification record is absent (referee-guarantee C-29).
242
+ *
243
+ * @param {object} report
244
+ * @returns {boolean}
245
+ */
246
+ export function reportHasBrowserVerificationMissing(report) {
247
+ return findBrowserVerificationMissingAcs(report).length > 0;
248
+ }