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.
Files changed (1525) hide show
  1. package/CHANGELOG.md +43 -0
  2. package/README.md +10 -0
  3. package/bin/rcf.js +2 -0
  4. package/blueprints/application-account-settings/CHANGELOG.md +64 -2
  5. package/blueprints/application-account-settings/README.md +10 -10
  6. package/blueprints/application-account-settings/blueprint.json +26 -4
  7. package/blueprints/application-account-settings/contributions/adrs/adr-2601-application-account-settings-capability-vocabulary.json +1 -1
  8. package/blueprints/application-account-settings/contributions/adrs/adr-2602-application-account-settings-security-surface-shape.json +1 -1
  9. package/blueprints/application-account-settings/contributions/adrs/adr-2604-application-account-settings-reauth-window.json +5 -5
  10. package/blueprints/application-account-settings/contributions/probes/probe-utils.mjs +177 -0
  11. package/blueprints/application-account-settings/contributions/probes/profile-form-autocomplete.mjs +67 -0
  12. package/blueprints/application-account-settings/contributions/probes/run-profile-form-autocomplete.mjs +5 -0
  13. package/blueprints/application-account-settings/contributions/probes/run-sessions-adapter-uniform.mjs +5 -0
  14. package/blueprints/application-account-settings/contributions/probes/run-sessions-surface-shape.mjs +5 -0
  15. package/blueprints/application-account-settings/contributions/probes/run-shell-tablist-per-capability.mjs +5 -0
  16. package/blueprints/application-account-settings/contributions/probes/run-theme-radiogroup.mjs +5 -0
  17. package/blueprints/application-account-settings/contributions/probes/sessions-adapter-uniform.mjs +130 -0
  18. package/blueprints/application-account-settings/contributions/probes/sessions-surface-shape.mjs +70 -0
  19. package/blueprints/application-account-settings/contributions/probes/shell-tablist-per-capability.mjs +60 -0
  20. package/blueprints/application-account-settings/contributions/probes/theme-radiogroup.mjs +126 -0
  21. package/blueprints/application-account-settings/contributions/requirements/application-account-settings-req-001.json +6 -2
  22. package/blueprints/application-account-settings/contributions/requirements/application-account-settings-req-002.json +4 -0
  23. package/blueprints/application-account-settings/contributions/requirements/application-account-settings-req-003.json +7 -3
  24. package/blueprints/application-account-settings/contributions/requirements/application-account-settings-req-004.json +4 -0
  25. package/blueprints/application-account-settings/contributions/requirements/application-account-settings-req-005.json +4 -0
  26. package/blueprints/application-account-settings/contributions/requirements/application-account-settings-req-006.json +6 -2
  27. package/blueprints/application-account-settings/contributions/requirements/application-account-settings-req-007.json +22 -0
  28. package/blueprints/application-account-settings/contributions/requirements/application-account-settings-req-009.json +21 -0
  29. package/blueprints/application-account-settings/contributions/tacs/tac-2601-application-account-settings-shell.json +8 -4
  30. package/blueprints/application-account-settings/contributions/tacs/tac-2602-application-account-settings-capability-discovery.json +3 -3
  31. package/blueprints/application-account-settings/contributions/tacs/tac-2604-application-account-settings-session-store.json +13 -7
  32. package/blueprints/application-account-settings/contributions/user-stories/application-account-settings-us-25101.json +19 -3
  33. package/blueprints/application-account-settings/contributions/user-stories/application-account-settings-us-25102.json +27 -2
  34. package/blueprints/application-account-settings/contributions/user-stories/application-account-settings-us-25103.json +13 -2
  35. package/blueprints/application-account-settings/contributions/user-stories/application-account-settings-us-25104.json +23 -2
  36. package/blueprints/application-account-settings/contributions/user-stories/application-account-settings-us-25105.json +51 -3
  37. package/blueprints/application-account-settings/contributions/user-stories/application-account-settings-us-25106.json +25 -6
  38. package/blueprints/application-account-settings/contributions/user-stories/application-account-settings-us-25107.json +13 -2
  39. package/blueprints/application-account-settings/contributions/user-stories/application-account-settings-us-25108.json +27 -2
  40. package/blueprints/application-account-settings/contributions/user-stories/application-account-settings-us-25109.json +4 -2
  41. package/blueprints/application-account-settings/contributions/user-stories/application-account-settings-us-25110.json +13 -2
  42. package/blueprints/application-account-settings/contributions/user-stories/application-account-settings-us-25111.json +71 -0
  43. package/blueprints/application-account-settings/contributions/user-stories/application-account-settings-us-25112.json +77 -0
  44. package/blueprints/application-account-settings/docs/topics.md +4 -4
  45. package/blueprints/application-account-settings/guide/application-account-settings.md +1 -1
  46. package/blueprints/application-account-settings/probe-packs/application-account-settings.pack.mjs +2 -2
  47. package/blueprints/application-admin-console/CHANGELOG.md +69 -7
  48. package/blueprints/application-admin-console/README.md +4 -4
  49. package/blueprints/application-admin-console/blueprint.json +34 -2
  50. package/blueprints/application-admin-console/contributions/adrs/adr-2201-application-admin-console-capability-vocabulary.json +2 -2
  51. package/blueprints/application-admin-console/contributions/adrs/adr-2203-application-admin-console-invite-transport.json +5 -5
  52. package/blueprints/application-admin-console/contributions/adrs/adr-2204-application-admin-console-audit-retention.json +7 -7
  53. package/blueprints/application-admin-console/contributions/adrs/adr-2214-application-admin-console-consume-zero-trust-gate.json +3 -3
  54. package/blueprints/application-admin-console/contributions/probes/audit-log-surface.mjs +79 -0
  55. package/blueprints/application-admin-console/contributions/probes/org-switcher-surface.mjs +83 -0
  56. package/blueprints/application-admin-console/contributions/probes/permission-matrix-grid.mjs +67 -0
  57. package/blueprints/application-admin-console/contributions/probes/probe-utils.mjs +177 -0
  58. package/blueprints/application-admin-console/contributions/probes/run-audit-log-surface.mjs +5 -0
  59. package/blueprints/application-admin-console/contributions/probes/run-org-switcher-surface.mjs +5 -0
  60. package/blueprints/application-admin-console/contributions/probes/run-permission-matrix-grid.mjs +5 -0
  61. package/blueprints/application-admin-console/contributions/probes/run-sign-in-access-gated-surface.mjs +5 -0
  62. package/blueprints/application-admin-console/contributions/probes/run-users-directory-surface.mjs +5 -0
  63. package/blueprints/application-admin-console/contributions/probes/sign-in-access-gated-surface.mjs +117 -0
  64. package/blueprints/application-admin-console/contributions/probes/users-directory-surface.mjs +145 -0
  65. package/blueprints/application-admin-console/contributions/requirements/application-admin-console-req-001.json +4 -0
  66. package/blueprints/application-admin-console/contributions/requirements/application-admin-console-req-002.json +5 -1
  67. package/blueprints/application-admin-console/contributions/requirements/application-admin-console-req-003.json +4 -0
  68. package/blueprints/application-admin-console/contributions/requirements/application-admin-console-req-004.json +4 -0
  69. package/blueprints/application-admin-console/contributions/requirements/application-admin-console-req-005.json +6 -2
  70. package/blueprints/application-admin-console/contributions/requirements/application-admin-console-req-006.json +4 -0
  71. package/blueprints/application-admin-console/contributions/requirements/application-admin-console-req-007.json +22 -0
  72. package/blueprints/application-admin-console/contributions/requirements/application-admin-console-req-008.json +22 -0
  73. package/blueprints/application-admin-console/contributions/requirements/application-admin-console-req-009.json +21 -0
  74. package/blueprints/application-admin-console/contributions/requirements/application-admin-console-req-014.json +6 -2
  75. package/blueprints/application-admin-console/contributions/tacs/tac-2201-application-admin-console-shell.json +9 -7
  76. package/blueprints/application-admin-console/contributions/tacs/tac-2202-application-admin-console-capability-discovery.json +6 -6
  77. package/blueprints/application-admin-console/contributions/tacs/tac-2204-application-admin-console-audit-view.json +1 -1
  78. package/blueprints/application-admin-console/contributions/tacs/tac-2214-application-admin-console-access-gated-signin-surface.json +5 -5
  79. package/blueprints/application-admin-console/contributions/user-stories/application-admin-console-us-21101.json +4 -2
  80. package/blueprints/application-admin-console/contributions/user-stories/application-admin-console-us-21102.json +4 -2
  81. package/blueprints/application-admin-console/contributions/user-stories/application-admin-console-us-21103.json +10 -4
  82. package/blueprints/application-admin-console/contributions/user-stories/application-admin-console-us-21104.json +13 -2
  83. package/blueprints/application-admin-console/contributions/user-stories/application-admin-console-us-21105.json +15 -3
  84. package/blueprints/application-admin-console/contributions/user-stories/application-admin-console-us-21106.json +35 -2
  85. package/blueprints/application-admin-console/contributions/user-stories/application-admin-console-us-21107.json +22 -3
  86. package/blueprints/application-admin-console/contributions/user-stories/application-admin-console-us-21108.json +4 -2
  87. package/blueprints/application-admin-console/contributions/user-stories/application-admin-console-us-21109.json +4 -2
  88. package/blueprints/application-admin-console/contributions/user-stories/application-admin-console-us-21110.json +68 -0
  89. package/blueprints/application-admin-console/contributions/user-stories/application-admin-console-us-21111.json +76 -0
  90. package/blueprints/application-admin-console/contributions/user-stories/application-admin-console-us-21112.json +77 -0
  91. package/blueprints/application-admin-console/contributions/user-stories/application-admin-console-us-21815.json +21 -2
  92. package/blueprints/application-admin-console/contributions/user-stories/application-admin-console-us-21816.json +21 -2
  93. package/blueprints/application-admin-console/guide/application-admin-console.md +3 -3
  94. package/blueprints/application-admin-console/probe-packs/application-admin-console.pack.mjs +2 -2
  95. package/blueprints/application-api-rest/CHANGELOG.md +34 -0
  96. package/blueprints/application-api-rest/README.md +3 -3
  97. package/blueprints/application-api-rest/assets/samples/request-response-pairs.md +2 -0
  98. package/blueprints/application-api-rest/blueprint.json +3 -2
  99. package/blueprints/application-api-rest/contributions/adrs/adr-301-application-api-rest-error-envelope.json +1 -1
  100. package/blueprints/application-api-rest/contributions/adrs/adr-302-application-api-rest-auth-model.json +2 -2
  101. package/blueprints/application-api-rest/contributions/adrs/adr-303-application-api-rest-api-versioning.json +1 -1
  102. package/blueprints/application-api-rest/contributions/adrs/adr-304-application-api-rest-logging.json +1 -1
  103. package/blueprints/application-api-rest/contributions/adrs/adr-305-application-api-rest-pagination.json +1 -1
  104. package/blueprints/application-api-rest/contributions/adrs/adr-306-application-api-rest-idempotency.json +3 -3
  105. package/blueprints/application-api-rest/contributions/adrs/adr-307-application-api-rest-openapi-generation.json +1 -1
  106. package/blueprints/application-api-rest/contributions/adrs/adr-308-application-api-rest-rate-limiting.json +1 -1
  107. package/blueprints/application-api-rest/contributions/probes/cursor-pagination-round-trip.mjs +154 -0
  108. package/blueprints/application-api-rest/contributions/probes/health-probes-distinct.mjs +124 -0
  109. package/blueprints/application-api-rest/contributions/probes/probe-utils.mjs +177 -0
  110. package/blueprints/application-api-rest/contributions/probes/problem-details-on-error.mjs +77 -0
  111. package/blueprints/application-api-rest/contributions/probes/request-id-echoed.mjs +76 -0
  112. package/blueprints/application-api-rest/contributions/probes/run-cursor-pagination-round-trip.mjs +5 -0
  113. package/blueprints/application-api-rest/contributions/probes/run-health-probes-distinct.mjs +5 -0
  114. package/blueprints/application-api-rest/contributions/probes/run-problem-details-on-error.mjs +5 -0
  115. package/blueprints/application-api-rest/contributions/probes/run-request-id-echoed.mjs +5 -0
  116. package/blueprints/application-api-rest/contributions/requirements/application-api-rest-req-001.json +6 -2
  117. package/blueprints/application-api-rest/contributions/requirements/application-api-rest-req-002.json +7 -3
  118. package/blueprints/application-api-rest/contributions/requirements/application-api-rest-req-003.json +6 -2
  119. package/blueprints/application-api-rest/contributions/requirements/application-api-rest-req-004.json +6 -2
  120. package/blueprints/application-api-rest/contributions/requirements/application-api-rest-req-005.json +6 -2
  121. package/blueprints/application-api-rest/contributions/requirements/application-api-rest-req-006.json +6 -2
  122. package/blueprints/application-api-rest/contributions/requirements/application-api-rest-req-007.json +6 -2
  123. package/blueprints/application-api-rest/contributions/requirements/application-api-rest-req-008.json +6 -2
  124. package/blueprints/application-api-rest/contributions/requirements/application-api-rest-req-009.json +6 -2
  125. package/blueprints/application-api-rest/contributions/requirements/application-api-rest-req-010.json +8 -4
  126. package/blueprints/application-api-rest/contributions/requirements/application-api-rest-req-011.json +6 -2
  127. package/blueprints/application-api-rest/contributions/requirements/application-api-rest-req-012.json +6 -2
  128. package/blueprints/application-api-rest/contributions/requirements/application-api-rest-req-013.json +7 -3
  129. package/blueprints/application-api-rest/contributions/requirements/application-api-rest-req-014.json +6 -2
  130. package/blueprints/application-api-rest/contributions/requirements/application-api-rest-req-015.json +6 -2
  131. package/blueprints/application-api-rest/contributions/requirements/application-api-rest-req-016.json +6 -2
  132. package/blueprints/application-api-rest/contributions/tacs/tac-301-application-api-rest-request-pipeline.json +1 -1
  133. package/blueprints/application-api-rest/contributions/tacs/tac-302-application-api-rest-auth-middleware.json +1 -1
  134. package/blueprints/application-api-rest/contributions/tacs/tac-303-application-api-rest-contract-surface.json +2 -2
  135. package/blueprints/application-api-rest/contributions/tacs/tac-304-application-api-rest-resource-layer.json +1 -1
  136. package/blueprints/application-api-rest/contributions/tacs/tac-305-application-api-rest-observability.json +1 -1
  137. package/blueprints/application-api-rest/contributions/tacs/tac-306-application-api-rest-operability.json +1 -1
  138. package/blueprints/application-api-rest/contributions/user-stories/application-api-rest-us-2101.json +13 -7
  139. package/blueprints/application-api-rest/contributions/user-stories/application-api-rest-us-2102.json +27 -13
  140. package/blueprints/application-api-rest/contributions/user-stories/application-api-rest-us-2103.json +18 -9
  141. package/blueprints/application-api-rest/contributions/user-stories/application-api-rest-us-2104.json +32 -10
  142. package/blueprints/application-api-rest/contributions/user-stories/application-api-rest-us-2105.json +19 -6
  143. package/blueprints/application-api-rest/contributions/user-stories/application-api-rest-us-2106.json +14 -8
  144. package/blueprints/application-api-rest/contributions/user-stories/application-api-rest-us-2107.json +20 -12
  145. package/blueprints/application-api-rest/contributions/user-stories/application-api-rest-us-2108.json +37 -15
  146. package/blueprints/application-api-rest/contributions/user-stories/application-api-rest-us-2109.json +15 -9
  147. package/blueprints/application-api-rest/contributions/user-stories/application-api-rest-us-2110.json +21 -11
  148. package/blueprints/application-api-rest/contributions/user-stories/application-api-rest-us-2111.json +42 -8
  149. package/blueprints/application-api-rest/contributions/user-stories/application-api-rest-us-2112.json +23 -13
  150. package/blueprints/application-api-rest/contributions/user-stories/application-api-rest-us-2113.json +17 -11
  151. package/blueprints/application-api-rest/contributions/user-stories/application-api-rest-us-2114.json +13 -8
  152. package/blueprints/application-api-rest/contributions/user-stories/application-api-rest-us-2115.json +13 -8
  153. package/blueprints/application-api-rest/contributions/user-stories/application-api-rest-us-2116.json +11 -6
  154. package/blueprints/application-api-rest/contributions/user-stories/application-api-rest-us-2117.json +19 -14
  155. package/blueprints/application-api-rest/contributions/user-stories/application-api-rest-us-2118.json +20 -10
  156. package/blueprints/application-api-rest/contributions/user-stories/application-api-rest-us-2119.json +20 -7
  157. package/blueprints/application-api-rest/contributions/user-stories/application-api-rest-us-2120.json +16 -10
  158. package/blueprints/application-api-rest/docs/topics.md +1 -1
  159. package/blueprints/application-charts/CHANGELOG.md +53 -6
  160. package/blueprints/application-charts/README.md +10 -10
  161. package/blueprints/application-charts/blueprint.json +115 -19
  162. package/blueprints/application-charts/contributions/adrs/adr-1901-application-charts-engine-choice.json +2 -2
  163. package/blueprints/application-charts/contributions/adrs/adr-1902-application-charts-accessible-palette.json +1 -1
  164. package/blueprints/application-charts/contributions/adrs/adr-1903-application-charts-motion.json +1 -1
  165. package/blueprints/application-charts/contributions/probes/keyboard-traversal.mjs +151 -0
  166. package/blueprints/application-charts/contributions/probes/non-colour-distinction.mjs +67 -0
  167. package/blueprints/application-charts/contributions/probes/probe-utils.mjs +177 -0
  168. package/blueprints/application-charts/contributions/probes/run-keyboard-traversal.mjs +5 -0
  169. package/blueprints/application-charts/contributions/probes/run-non-colour-distinction.mjs +5 -0
  170. package/blueprints/application-charts/contributions/probes/run-text-alternative-table.mjs +5 -0
  171. package/blueprints/application-charts/contributions/probes/text-alternative-table.mjs +139 -0
  172. package/blueprints/application-charts/contributions/requirements/application-charts-req-001.json +11 -4
  173. package/blueprints/application-charts/contributions/requirements/application-charts-req-002.json +11 -4
  174. package/blueprints/application-charts/contributions/requirements/application-charts-req-003.json +10 -3
  175. package/blueprints/application-charts/contributions/requirements/application-charts-req-004.json +10 -3
  176. package/blueprints/application-charts/contributions/tacs/tac-1901-application-charts-render-shell.json +3 -2
  177. package/blueprints/application-charts/contributions/tacs/tac-1902-application-charts-keyboard-traversal.json +1 -1
  178. package/blueprints/application-charts/contributions/user-stories/application-charts-us-18101.json +52 -8
  179. package/blueprints/application-charts/contributions/user-stories/application-charts-us-18102.json +58 -6
  180. package/blueprints/application-charts/contributions/user-stories/application-charts-us-18103.json +54 -6
  181. package/blueprints/application-charts/contributions/user-stories/application-charts-us-18104.json +55 -6
  182. package/blueprints/application-charts/contributions/user-stories/application-charts-us-18105.json +64 -8
  183. package/blueprints/application-charts/contributions/user-stories/application-charts-us-18106.json +45 -7
  184. package/blueprints/application-charts/docs/topics.md +2 -2
  185. package/blueprints/application-charts/guide/application-charts.md +3 -3
  186. package/blueprints/application-charts/probe-packs/application-charts.pack.mjs +2 -2
  187. package/blueprints/application-dashboard/CHANGELOG.md +39 -8
  188. package/blueprints/application-dashboard/README.md +13 -13
  189. package/blueprints/application-dashboard/assets/guidance/dashboard-design.md +2 -2
  190. package/blueprints/application-dashboard/blueprint.json +149 -22
  191. package/blueprints/application-dashboard/contributions/adrs/adr-2001-application-dashboard-primary-kpi-enum.json +4 -4
  192. package/blueprints/application-dashboard/contributions/adrs/adr-2002-application-dashboard-timeframe-presets.json +2 -2
  193. package/blueprints/application-dashboard/contributions/adrs/adr-2003-application-dashboard-export-formats.json +1 -1
  194. package/blueprints/application-dashboard/contributions/probes/export-handle-formats.mjs +75 -0
  195. package/blueprints/application-dashboard/contributions/probes/four-tile-states.mjs +75 -0
  196. package/blueprints/application-dashboard/contributions/probes/primary-kpi-top-left.mjs +58 -0
  197. package/blueprints/application-dashboard/contributions/probes/probe-utils.mjs +177 -0
  198. package/blueprints/application-dashboard/contributions/probes/run-export-handle-formats.mjs +4 -0
  199. package/blueprints/application-dashboard/contributions/probes/run-four-tile-states.mjs +4 -0
  200. package/blueprints/application-dashboard/contributions/probes/run-primary-kpi-top-left.mjs +4 -0
  201. package/blueprints/application-dashboard/contributions/probes/run-shell-five-regions.mjs +4 -0
  202. package/blueprints/application-dashboard/contributions/probes/shell-five-regions.mjs +93 -0
  203. package/blueprints/application-dashboard/contributions/requirements/application-dashboard-req-001.json +10 -3
  204. package/blueprints/application-dashboard/contributions/requirements/application-dashboard-req-002.json +11 -4
  205. package/blueprints/application-dashboard/contributions/requirements/application-dashboard-req-003.json +11 -4
  206. package/blueprints/application-dashboard/contributions/requirements/application-dashboard-req-004.json +11 -4
  207. package/blueprints/application-dashboard/contributions/requirements/application-dashboard-req-005.json +11 -4
  208. package/blueprints/application-dashboard/contributions/tacs/tac-2001-application-dashboard-tile-grid.json +1 -1
  209. package/blueprints/application-dashboard/contributions/tacs/tac-2002-application-dashboard-filter-chrome.json +2 -2
  210. package/blueprints/application-dashboard/contributions/tacs/tac-2003-application-dashboard-export-handle.json +3 -3
  211. package/blueprints/application-dashboard/contributions/user-stories/application-dashboard-us-19101.json +55 -7
  212. package/blueprints/application-dashboard/contributions/user-stories/application-dashboard-us-19102.json +56 -8
  213. package/blueprints/application-dashboard/contributions/user-stories/application-dashboard-us-19103.json +59 -7
  214. package/blueprints/application-dashboard/contributions/user-stories/application-dashboard-us-19104.json +55 -7
  215. package/blueprints/application-dashboard/contributions/user-stories/application-dashboard-us-19105.json +55 -7
  216. package/blueprints/application-dashboard/contributions/user-stories/application-dashboard-us-19106.json +60 -8
  217. package/blueprints/application-dashboard/contributions/user-stories/application-dashboard-us-19107.json +57 -9
  218. package/blueprints/application-dashboard/docs/topics.md +3 -3
  219. package/blueprints/application-dashboard/guide/application-dashboard.md +5 -5
  220. package/blueprints/application-dashboard/probe-packs/application-dashboard.pack.mjs +4 -4
  221. package/blueprints/application-datatable/CHANGELOG.md +36 -5
  222. package/blueprints/application-datatable/README.md +4 -4
  223. package/blueprints/application-datatable/blueprint.json +169 -26
  224. package/blueprints/application-datatable/contributions/adrs/adr-1801-application-datatable-pattern-choice.json +1 -1
  225. package/blueprints/application-datatable/contributions/adrs/adr-1802-application-datatable-url-state.json +1 -1
  226. package/blueprints/application-datatable/contributions/adrs/adr-1803-application-datatable-page-size.json +1 -1
  227. package/blueprints/application-datatable/contributions/adrs/adr-1804-application-datatable-selection-persistence.json +1 -1
  228. package/blueprints/application-datatable/contributions/probes/apg-table-shape.mjs +57 -0
  229. package/blueprints/application-datatable/contributions/probes/four-states-regions.mjs +80 -0
  230. package/blueprints/application-datatable/contributions/probes/probe-utils.mjs +177 -0
  231. package/blueprints/application-datatable/contributions/probes/run-apg-table-shape.mjs +4 -0
  232. package/blueprints/application-datatable/contributions/probes/run-four-states-regions.mjs +4 -0
  233. package/blueprints/application-datatable/contributions/probes/run-search-adapter-round-trip.mjs +4 -0
  234. package/blueprints/application-datatable/contributions/probes/run-sort-adapter-round-trip.mjs +4 -0
  235. package/blueprints/application-datatable/contributions/probes/search-adapter-round-trip.mjs +58 -0
  236. package/blueprints/application-datatable/contributions/probes/sort-adapter-round-trip.mjs +60 -0
  237. package/blueprints/application-datatable/contributions/requirements/application-datatable-req-001.json +11 -4
  238. package/blueprints/application-datatable/contributions/requirements/application-datatable-req-002.json +11 -4
  239. package/blueprints/application-datatable/contributions/requirements/application-datatable-req-003.json +10 -3
  240. package/blueprints/application-datatable/contributions/requirements/application-datatable-req-004.json +11 -4
  241. package/blueprints/application-datatable/contributions/requirements/application-datatable-req-005.json +10 -3
  242. package/blueprints/application-datatable/contributions/requirements/application-datatable-req-006.json +11 -4
  243. package/blueprints/application-datatable/contributions/tacs/tac-1801-application-datatable-shell.json +1 -1
  244. package/blueprints/application-datatable/contributions/tacs/tac-1802-application-datatable-query-adapter.json +1 -1
  245. package/blueprints/application-datatable/contributions/tacs/tac-1803-application-datatable-selection-model.json +2 -2
  246. package/blueprints/application-datatable/contributions/user-stories/application-datatable-us-17101.json +29 -7
  247. package/blueprints/application-datatable/contributions/user-stories/application-datatable-us-17102.json +29 -7
  248. package/blueprints/application-datatable/contributions/user-stories/application-datatable-us-17103.json +28 -6
  249. package/blueprints/application-datatable/contributions/user-stories/application-datatable-us-17104.json +65 -7
  250. package/blueprints/application-datatable/contributions/user-stories/application-datatable-us-17105.json +32 -7
  251. package/blueprints/application-datatable/contributions/user-stories/application-datatable-us-17106.json +60 -7
  252. package/blueprints/application-datatable/contributions/user-stories/application-datatable-us-17107.json +72 -7
  253. package/blueprints/application-datatable/contributions/user-stories/application-datatable-us-17108.json +59 -9
  254. package/blueprints/application-datatable/contributions/user-stories/application-datatable-us-17109.json +58 -9
  255. package/blueprints/application-datatable/docs/topics.md +1 -1
  256. package/blueprints/application-datatable/guide/application-datatable.md +1 -1
  257. package/blueprints/application-empty-error-states/CHANGELOG.md +64 -4
  258. package/blueprints/application-empty-error-states/README.md +3 -3
  259. package/blueprints/application-empty-error-states/blueprint.json +38 -2
  260. package/blueprints/application-empty-error-states/contributions/probes/empty-list-and-no-search.mjs +66 -0
  261. package/blueprints/application-empty-error-states/contributions/probes/error-boundary-alert.mjs +65 -0
  262. package/blueprints/application-empty-error-states/contributions/probes/forbidden-and-server-error.mjs +167 -0
  263. package/blueprints/application-empty-error-states/contributions/probes/not-found-and-recovery.mjs +61 -0
  264. package/blueprints/application-empty-error-states/contributions/probes/permission-denied-and-offline.mjs +155 -0
  265. package/blueprints/application-empty-error-states/contributions/probes/probe-utils.mjs +177 -0
  266. package/blueprints/application-empty-error-states/contributions/probes/run-empty-list-and-no-search.mjs +5 -0
  267. package/blueprints/application-empty-error-states/contributions/probes/run-error-boundary-alert.mjs +5 -0
  268. package/blueprints/application-empty-error-states/contributions/probes/run-forbidden-and-server-error.mjs +5 -0
  269. package/blueprints/application-empty-error-states/contributions/probes/run-not-found-and-recovery.mjs +5 -0
  270. package/blueprints/application-empty-error-states/contributions/probes/run-permission-denied-and-offline.mjs +5 -0
  271. package/blueprints/application-empty-error-states/contributions/requirements/application-empty-error-states-req-001.json +4 -0
  272. package/blueprints/application-empty-error-states/contributions/requirements/application-empty-error-states-req-002.json +7 -3
  273. package/blueprints/application-empty-error-states/contributions/requirements/application-empty-error-states-req-003.json +4 -0
  274. package/blueprints/application-empty-error-states/contributions/requirements/application-empty-error-states-req-004.json +6 -2
  275. package/blueprints/application-empty-error-states/contributions/requirements/application-empty-error-states-req-005.json +7 -3
  276. package/blueprints/application-empty-error-states/contributions/requirements/application-empty-error-states-req-006.json +21 -0
  277. package/blueprints/application-empty-error-states/contributions/requirements/application-empty-error-states-req-007.json +21 -0
  278. package/blueprints/application-empty-error-states/contributions/tacs/tac-2301-application-empty-error-states-state-machine.json +7 -4
  279. package/blueprints/application-empty-error-states/contributions/tacs/tac-2303-application-empty-error-states-offline-buffer.json +3 -2
  280. package/blueprints/application-empty-error-states/contributions/user-stories/application-empty-error-states-us-22101.json +17 -2
  281. package/blueprints/application-empty-error-states/contributions/user-stories/application-empty-error-states-us-22102.json +31 -2
  282. package/blueprints/application-empty-error-states/contributions/user-stories/application-empty-error-states-us-22103.json +27 -2
  283. package/blueprints/application-empty-error-states/contributions/user-stories/application-empty-error-states-us-22104.json +13 -2
  284. package/blueprints/application-empty-error-states/contributions/user-stories/application-empty-error-states-us-22105.json +33 -2
  285. package/blueprints/application-empty-error-states/contributions/user-stories/application-empty-error-states-us-22106.json +13 -2
  286. package/blueprints/application-empty-error-states/contributions/user-stories/application-empty-error-states-us-22107.json +23 -2
  287. package/blueprints/application-empty-error-states/contributions/user-stories/application-empty-error-states-us-22108.json +27 -2
  288. package/blueprints/application-empty-error-states/probe-packs/application-empty-error-states.pack.mjs +93 -9
  289. package/blueprints/application-error-handling/CHANGELOG.md +56 -0
  290. package/blueprints/application-error-handling/blueprint.json +106 -20
  291. package/blueprints/application-error-handling/contributions/adrs/adr-1701-application-error-handling-record-shape.json +1 -1
  292. package/blueprints/application-error-handling/contributions/adrs/adr-1702-application-error-handling-classification-vocabulary.json +1 -1
  293. package/blueprints/application-error-handling/contributions/adrs/adr-1703-application-error-handling-transport-mapping.json +1 -1
  294. package/blueprints/application-error-handling/contributions/probes/category-vocabulary.mjs +90 -0
  295. package/blueprints/application-error-handling/contributions/probes/probe-utils.mjs +177 -0
  296. package/blueprints/application-error-handling/contributions/probes/record-shape-adr-1701.mjs +78 -0
  297. package/blueprints/application-error-handling/contributions/probes/run-category-vocabulary.mjs +5 -0
  298. package/blueprints/application-error-handling/contributions/probes/run-record-shape-adr-1701.mjs +5 -0
  299. package/blueprints/application-error-handling/contributions/probes/run-two-boundaries-registered.mjs +5 -0
  300. package/blueprints/application-error-handling/contributions/probes/two-boundaries-registered.mjs +343 -0
  301. package/blueprints/application-error-handling/contributions/requirements/application-error-handling-req-001.json +10 -3
  302. package/blueprints/application-error-handling/contributions/requirements/application-error-handling-req-002.json +10 -3
  303. package/blueprints/application-error-handling/contributions/requirements/application-error-handling-req-003.json +10 -3
  304. package/blueprints/application-error-handling/contributions/requirements/application-error-handling-req-004.json +10 -3
  305. package/blueprints/application-error-handling/contributions/tacs/tac-1701-application-error-handling-boundary.json +1 -1
  306. package/blueprints/application-error-handling/contributions/tacs/tac-1702-application-error-handling-record-factory.json +1 -1
  307. package/blueprints/application-error-handling/contributions/user-stories/application-error-handling-us-16101.json +63 -4
  308. package/blueprints/application-error-handling/contributions/user-stories/application-error-handling-us-16102.json +49 -4
  309. package/blueprints/application-error-handling/contributions/user-stories/application-error-handling-us-16103.json +51 -5
  310. package/blueprints/application-error-handling/contributions/user-stories/application-error-handling-us-16104.json +49 -4
  311. package/blueprints/application-error-handling/contributions/user-stories/application-error-handling-us-16105.json +49 -4
  312. package/blueprints/application-error-handling/contributions/user-stories/application-error-handling-us-16106.json +49 -4
  313. package/blueprints/application-error-handling/contributions/user-stories/application-error-handling-us-16107.json +53 -4
  314. package/blueprints/application-file-upload/CHANGELOG.md +60 -5
  315. package/blueprints/application-file-upload/README.md +1 -1
  316. package/blueprints/application-file-upload/blueprint.json +58 -2
  317. package/blueprints/application-file-upload/contributions/adrs/adr-2402-application-file-upload-accepted-set.json +3 -3
  318. package/blueprints/application-file-upload/contributions/probes/assertive-completion-slot.mjs +78 -0
  319. package/blueprints/application-file-upload/contributions/probes/chunked-transport-endpoints.mjs +173 -0
  320. package/blueprints/application-file-upload/contributions/probes/per-file-progressbar.mjs +124 -0
  321. package/blueprints/application-file-upload/contributions/probes/probe-utils.mjs +177 -0
  322. package/blueprints/application-file-upload/contributions/probes/run-assertive-completion-slot.mjs +4 -0
  323. package/blueprints/application-file-upload/contributions/probes/run-chunked-transport-endpoints.mjs +4 -0
  324. package/blueprints/application-file-upload/contributions/probes/run-per-file-progressbar.mjs +4 -0
  325. package/blueprints/application-file-upload/contributions/probes/run-upload-surface-shape.mjs +4 -0
  326. package/blueprints/application-file-upload/contributions/probes/upload-surface-shape.mjs +55 -0
  327. package/blueprints/application-file-upload/contributions/requirements/application-file-upload-req-001.json +5 -1
  328. package/blueprints/application-file-upload/contributions/requirements/application-file-upload-req-002.json +8 -4
  329. package/blueprints/application-file-upload/contributions/requirements/application-file-upload-req-003.json +7 -3
  330. package/blueprints/application-file-upload/contributions/requirements/application-file-upload-req-004.json +7 -3
  331. package/blueprints/application-file-upload/contributions/requirements/application-file-upload-req-005.json +5 -1
  332. package/blueprints/application-file-upload/contributions/requirements/application-file-upload-req-006.json +21 -0
  333. package/blueprints/application-file-upload/contributions/requirements/application-file-upload-req-007.json +21 -0
  334. package/blueprints/application-file-upload/contributions/tacs/tac-2401-application-file-upload-input.json +4 -2
  335. package/blueprints/application-file-upload/contributions/tacs/tac-2402-application-file-upload-transport.json +7 -2
  336. package/blueprints/application-file-upload/contributions/tacs/tac-2403-application-file-upload-progress-announcer.json +16 -6
  337. package/blueprints/application-file-upload/contributions/user-stories/application-file-upload-us-23101.json +23 -2
  338. package/blueprints/application-file-upload/contributions/user-stories/application-file-upload-us-23102.json +29 -4
  339. package/blueprints/application-file-upload/contributions/user-stories/application-file-upload-us-23103.json +13 -2
  340. package/blueprints/application-file-upload/contributions/user-stories/application-file-upload-us-23104.json +45 -2
  341. package/blueprints/application-file-upload/contributions/user-stories/application-file-upload-us-23105.json +37 -2
  342. package/blueprints/application-file-upload/contributions/user-stories/application-file-upload-us-23106.json +13 -2
  343. package/blueprints/application-file-upload/contributions/user-stories/application-file-upload-us-23107.json +17 -2
  344. package/blueprints/application-file-upload/probe-packs/application-file-upload.pack.mjs +14 -5
  345. package/blueprints/application-forms-wizard/CHANGELOG.md +50 -5
  346. package/blueprints/application-forms-wizard/README.md +3 -3
  347. package/blueprints/application-forms-wizard/blueprint.json +59 -2
  348. package/blueprints/application-forms-wizard/contributions/probes/draft-persistence-round-trip.mjs +110 -0
  349. package/blueprints/application-forms-wizard/contributions/probes/probe-utils.mjs +177 -0
  350. package/blueprints/application-forms-wizard/contributions/probes/run-draft-persistence-round-trip.mjs +4 -0
  351. package/blueprints/application-forms-wizard/contributions/probes/run-step-page-shape.mjs +4 -0
  352. package/blueprints/application-forms-wizard/contributions/probes/run-task-list-surface.mjs +4 -0
  353. package/blueprints/application-forms-wizard/contributions/probes/step-page-shape.mjs +61 -0
  354. package/blueprints/application-forms-wizard/contributions/probes/task-list-surface.mjs +109 -0
  355. package/blueprints/application-forms-wizard/contributions/requirements/application-forms-wizard-req-001.json +5 -1
  356. package/blueprints/application-forms-wizard/contributions/requirements/application-forms-wizard-req-002.json +7 -3
  357. package/blueprints/application-forms-wizard/contributions/requirements/application-forms-wizard-req-003.json +7 -3
  358. package/blueprints/application-forms-wizard/contributions/requirements/application-forms-wizard-req-004.json +7 -3
  359. package/blueprints/application-forms-wizard/contributions/requirements/application-forms-wizard-req-005.json +5 -1
  360. package/blueprints/application-forms-wizard/contributions/requirements/application-forms-wizard-req-006.json +21 -0
  361. package/blueprints/application-forms-wizard/contributions/tacs/tac-2501-application-forms-wizard-task-list.json +6 -4
  362. package/blueprints/application-forms-wizard/contributions/tacs/tac-2502-application-forms-wizard-error-summary.json +4 -3
  363. package/blueprints/application-forms-wizard/contributions/user-stories/application-forms-wizard-us-24101.json +35 -2
  364. package/blueprints/application-forms-wizard/contributions/user-stories/application-forms-wizard-us-24102.json +27 -2
  365. package/blueprints/application-forms-wizard/contributions/user-stories/application-forms-wizard-us-24103.json +21 -2
  366. package/blueprints/application-forms-wizard/contributions/user-stories/application-forms-wizard-us-24104.json +13 -2
  367. package/blueprints/application-forms-wizard/contributions/user-stories/application-forms-wizard-us-24105.json +33 -2
  368. package/blueprints/application-forms-wizard/contributions/user-stories/application-forms-wizard-us-24106.json +18 -3
  369. package/blueprints/application-forms-wizard/contributions/user-stories/application-forms-wizard-us-24107.json +23 -2
  370. package/blueprints/application-forms-wizard/contributions/user-stories/application-forms-wizard-us-24108.json +13 -2
  371. package/blueprints/application-forms-wizard/probe-packs/application-forms-wizard.pack.mjs +3 -3
  372. package/blueprints/application-notifications-in-app/CHANGELOG.md +70 -5
  373. package/blueprints/application-notifications-in-app/README.md +9 -9
  374. package/blueprints/application-notifications-in-app/blueprint.json +153 -23
  375. package/blueprints/application-notifications-in-app/contributions/adrs/adr-2101-application-notifications-in-app-live-region-role-mapping.json +1 -1
  376. package/blueprints/application-notifications-in-app/contributions/probes/centre-acknowledge-round-trip.mjs +210 -0
  377. package/blueprints/application-notifications-in-app/contributions/probes/live-region-preseeding.mjs +93 -0
  378. package/blueprints/application-notifications-in-app/contributions/probes/probe-utils.mjs +177 -0
  379. package/blueprints/application-notifications-in-app/contributions/probes/run-centre-acknowledge-round-trip.mjs +5 -0
  380. package/blueprints/application-notifications-in-app/contributions/probes/run-live-region-preseeding.mjs +5 -0
  381. package/blueprints/application-notifications-in-app/contributions/probes/run-toast-contract.mjs +5 -0
  382. package/blueprints/application-notifications-in-app/contributions/probes/toast-contract.mjs +92 -0
  383. package/blueprints/application-notifications-in-app/contributions/requirements/application-notifications-in-app-req-001.json +11 -4
  384. package/blueprints/application-notifications-in-app/contributions/requirements/application-notifications-in-app-req-002.json +8 -1
  385. package/blueprints/application-notifications-in-app/contributions/requirements/application-notifications-in-app-req-003.json +10 -3
  386. package/blueprints/application-notifications-in-app/contributions/requirements/application-notifications-in-app-req-004.json +11 -4
  387. package/blueprints/application-notifications-in-app/contributions/requirements/application-notifications-in-app-req-005.json +12 -5
  388. package/blueprints/application-notifications-in-app/contributions/requirements/application-notifications-in-app-req-006.json +21 -0
  389. package/blueprints/application-notifications-in-app/contributions/tacs/tac-2101-application-notifications-in-app-live-region.json +3 -3
  390. package/blueprints/application-notifications-in-app/contributions/tacs/tac-2102-application-notifications-in-app-centre.json +15 -9
  391. package/blueprints/application-notifications-in-app/contributions/tacs/tac-2103-application-notifications-in-app-preferences.json +2 -2
  392. package/blueprints/application-notifications-in-app/contributions/user-stories/application-notifications-in-app-us-20101.json +30 -6
  393. package/blueprints/application-notifications-in-app/contributions/user-stories/application-notifications-in-app-us-20102.json +44 -6
  394. package/blueprints/application-notifications-in-app/contributions/user-stories/application-notifications-in-app-us-20103.json +40 -6
  395. package/blueprints/application-notifications-in-app/contributions/user-stories/application-notifications-in-app-us-20104.json +31 -5
  396. package/blueprints/application-notifications-in-app/contributions/user-stories/application-notifications-in-app-us-20105.json +51 -9
  397. package/blueprints/application-notifications-in-app/contributions/user-stories/application-notifications-in-app-us-20106.json +19 -4
  398. package/blueprints/application-notifications-in-app/contributions/user-stories/application-notifications-in-app-us-20107.json +19 -4
  399. package/blueprints/application-notifications-in-app/contributions/user-stories/application-notifications-in-app-us-20108.json +19 -4
  400. package/blueprints/application-notifications-in-app/guide/application-notifications-in-app.md +4 -4
  401. package/blueprints/application-notifications-in-app/probe-packs/application-notifications-in-app.pack.mjs +4 -4
  402. package/blueprints/application-onboarding-tour/CHANGELOG.md +59 -2
  403. package/blueprints/application-onboarding-tour/README.md +3 -3
  404. package/blueprints/application-onboarding-tour/blueprint.json +24 -2
  405. package/blueprints/application-onboarding-tour/contributions/adrs/adr-2702-application-onboarding-tour-completion-store-shape.json +4 -4
  406. package/blueprints/application-onboarding-tour/contributions/probes/checklist-anchor-open.mjs +81 -0
  407. package/blueprints/application-onboarding-tour/contributions/probes/completion-persistence.mjs +159 -0
  408. package/blueprints/application-onboarding-tour/contributions/probes/first-run-detection.mjs +67 -0
  409. package/blueprints/application-onboarding-tour/contributions/probes/probe-utils.mjs +177 -0
  410. package/blueprints/application-onboarding-tour/contributions/probes/run-checklist-anchor-open.mjs +5 -0
  411. package/blueprints/application-onboarding-tour/contributions/probes/run-completion-persistence.mjs +5 -0
  412. package/blueprints/application-onboarding-tour/contributions/probes/run-first-run-detection.mjs +5 -0
  413. package/blueprints/application-onboarding-tour/contributions/probes/run-stepper-role-dialog.mjs +5 -0
  414. package/blueprints/application-onboarding-tour/contributions/probes/stepper-role-dialog.mjs +45 -0
  415. package/blueprints/application-onboarding-tour/contributions/requirements/application-onboarding-tour-req-001.json +6 -2
  416. package/blueprints/application-onboarding-tour/contributions/requirements/application-onboarding-tour-req-002.json +6 -2
  417. package/blueprints/application-onboarding-tour/contributions/requirements/application-onboarding-tour-req-003.json +4 -0
  418. package/blueprints/application-onboarding-tour/contributions/requirements/application-onboarding-tour-req-004.json +4 -0
  419. package/blueprints/application-onboarding-tour/contributions/requirements/application-onboarding-tour-req-005.json +22 -0
  420. package/blueprints/application-onboarding-tour/contributions/requirements/application-onboarding-tour-req-006.json +22 -0
  421. package/blueprints/application-onboarding-tour/contributions/tacs/tac-2702-application-onboarding-tour-checklist-slot.json +2 -1
  422. package/blueprints/application-onboarding-tour/contributions/tacs/tac-2703-application-onboarding-tour-completion-store.json +7 -7
  423. package/blueprints/application-onboarding-tour/contributions/user-stories/application-onboarding-tour-us-26101.json +67 -2
  424. package/blueprints/application-onboarding-tour/contributions/user-stories/application-onboarding-tour-us-26102.json +35 -2
  425. package/blueprints/application-onboarding-tour/contributions/user-stories/application-onboarding-tour-us-26103.json +13 -2
  426. package/blueprints/application-onboarding-tour/contributions/user-stories/application-onboarding-tour-us-26104.json +33 -2
  427. package/blueprints/application-onboarding-tour/contributions/user-stories/application-onboarding-tour-us-26105.json +13 -2
  428. package/blueprints/application-onboarding-tour/contributions/user-stories/application-onboarding-tour-us-26106.json +13 -2
  429. package/blueprints/application-onboarding-tour/contributions/user-stories/application-onboarding-tour-us-26107.json +17 -2
  430. package/blueprints/application-onboarding-tour/contributions/user-stories/application-onboarding-tour-us-26108.json +62 -0
  431. package/blueprints/application-onboarding-tour/contributions/user-stories/application-onboarding-tour-us-26109.json +72 -0
  432. package/blueprints/application-onboarding-tour/docs/topics.md +2 -2
  433. package/blueprints/application-onboarding-tour/guide/application-onboarding-tour.md +1 -1
  434. package/blueprints/application-onboarding-tour/probe-packs/application-onboarding-tour.pack.mjs +2 -2
  435. package/blueprints/application-spa/CHANGELOG.md +39 -0
  436. package/blueprints/application-spa/README.md +11 -12
  437. package/blueprints/application-spa/blueprint.json +3 -2
  438. package/blueprints/application-spa/contributions/adrs/adr-201-application-spa-routing.json +1 -1
  439. package/blueprints/application-spa/contributions/adrs/adr-202-application-spa-theming.json +2 -2
  440. package/blueprints/application-spa/contributions/adrs/adr-203-application-spa-client-state.json +1 -1
  441. package/blueprints/application-spa/contributions/adrs/adr-204-application-spa-error-envelope.json +1 -1
  442. package/blueprints/application-spa/contributions/adrs/adr-205-application-spa-auth-model.json +1 -1
  443. package/blueprints/application-spa/contributions/adrs/adr-206-application-spa-iconography.json +2 -2
  444. package/blueprints/application-spa/contributions/adrs/adr-207-application-spa-motion.json +1 -1
  445. package/blueprints/application-spa/contributions/adrs/adr-208-application-spa-i18n.json +1 -1
  446. package/blueprints/application-spa/contributions/adrs/adr-209-application-spa-telemetry-naming.json +1 -1
  447. package/blueprints/application-spa/contributions/probes/designed-empty-state.mjs +72 -0
  448. package/blueprints/application-spa/contributions/probes/probe-utils.mjs +177 -0
  449. package/blueprints/application-spa/contributions/probes/route-inventory-published.mjs +185 -0
  450. package/blueprints/application-spa/contributions/probes/run-designed-empty-state.mjs +5 -0
  451. package/blueprints/application-spa/contributions/probes/run-route-inventory-published.mjs +5 -0
  452. package/blueprints/application-spa/contributions/probes/run-shell-nav-present.mjs +5 -0
  453. package/blueprints/application-spa/contributions/probes/shell-nav-present.mjs +69 -0
  454. package/blueprints/application-spa/contributions/requirements/application-spa-req-001.json +6 -2
  455. package/blueprints/application-spa/contributions/requirements/application-spa-req-002.json +6 -2
  456. package/blueprints/application-spa/contributions/requirements/application-spa-req-003.json +6 -2
  457. package/blueprints/application-spa/contributions/requirements/application-spa-req-004.json +6 -2
  458. package/blueprints/application-spa/contributions/requirements/application-spa-req-005.json +6 -2
  459. package/blueprints/application-spa/contributions/requirements/application-spa-req-006.json +6 -2
  460. package/blueprints/application-spa/contributions/requirements/application-spa-req-007.json +6 -2
  461. package/blueprints/application-spa/contributions/requirements/application-spa-req-008.json +6 -2
  462. package/blueprints/application-spa/contributions/requirements/application-spa-req-009.json +7 -3
  463. package/blueprints/application-spa/contributions/requirements/application-spa-req-010.json +6 -2
  464. package/blueprints/application-spa/contributions/requirements/application-spa-req-011.json +6 -2
  465. package/blueprints/application-spa/contributions/requirements/application-spa-req-012.json +6 -2
  466. package/blueprints/application-spa/contributions/requirements/application-spa-req-013.json +6 -2
  467. package/blueprints/application-spa/contributions/requirements/application-spa-req-014.json +6 -2
  468. package/blueprints/application-spa/contributions/requirements/application-spa-req-015.json +6 -2
  469. package/blueprints/application-spa/contributions/requirements/application-spa-req-016.json +6 -2
  470. package/blueprints/application-spa/contributions/requirements/application-spa-req-017.json +6 -2
  471. package/blueprints/application-spa/contributions/requirements/application-spa-req-018.json +7 -3
  472. package/blueprints/application-spa/contributions/requirements/application-spa-req-019.json +6 -2
  473. package/blueprints/application-spa/contributions/requirements/application-spa-req-020.json +6 -2
  474. package/blueprints/application-spa/contributions/requirements/application-spa-req-021.json +6 -2
  475. package/blueprints/application-spa/contributions/tacs/tac-201-application-spa-app-shell.json +4 -3
  476. package/blueprints/application-spa/contributions/tacs/tac-202-application-spa-theme-system.json +1 -1
  477. package/blueprints/application-spa/contributions/tacs/tac-203-application-spa-component-library.json +1 -1
  478. package/blueprints/application-spa/contributions/tacs/tac-204-application-spa-client-data-layer.json +1 -1
  479. package/blueprints/application-spa/contributions/tacs/tac-205-application-spa-forms-engine.json +1 -1
  480. package/blueprints/application-spa/contributions/tacs/tac-206-application-spa-telemetry.json +1 -1
  481. package/blueprints/application-spa/contributions/tacs/tac-207-application-spa-token-adherence-probe.json +2 -2
  482. package/blueprints/application-spa/contributions/tacs/tac-208-application-spa-icon-adherence-probe.json +3 -3
  483. package/blueprints/application-spa/contributions/tacs/tac-209-application-spa-csp-styled-adherence-probe.json +4 -4
  484. package/blueprints/application-spa/contributions/tacs/tac-210-application-spa-external-dependency-provisioning-probe.json +3 -3
  485. package/blueprints/application-spa/contributions/tacs/tac-211-application-spa-core-flow-e2e-probe.json +3 -3
  486. package/blueprints/application-spa/contributions/user-stories/application-spa-us-1101.json +22 -8
  487. package/blueprints/application-spa/contributions/user-stories/application-spa-us-1102.json +18 -9
  488. package/blueprints/application-spa/contributions/user-stories/application-spa-us-1103.json +13 -7
  489. package/blueprints/application-spa/contributions/user-stories/application-spa-us-1104.json +15 -10
  490. package/blueprints/application-spa/contributions/user-stories/application-spa-us-1105.json +13 -7
  491. package/blueprints/application-spa/contributions/user-stories/application-spa-us-1106.json +12 -7
  492. package/blueprints/application-spa/contributions/user-stories/application-spa-us-1107.json +25 -6
  493. package/blueprints/application-spa/contributions/user-stories/application-spa-us-1108.json +17 -9
  494. package/blueprints/application-spa/contributions/user-stories/application-spa-us-1109.json +17 -9
  495. package/blueprints/application-spa/contributions/user-stories/application-spa-us-1110.json +19 -10
  496. package/blueprints/application-spa/contributions/user-stories/application-spa-us-1111.json +19 -11
  497. package/blueprints/application-spa/contributions/user-stories/application-spa-us-1112.json +15 -8
  498. package/blueprints/application-spa/contributions/user-stories/application-spa-us-1113.json +15 -8
  499. package/blueprints/application-spa/contributions/user-stories/application-spa-us-1114.json +15 -10
  500. package/blueprints/application-spa/contributions/user-stories/application-spa-us-1115.json +13 -7
  501. package/blueprints/application-spa/contributions/user-stories/application-spa-us-1116.json +15 -9
  502. package/blueprints/application-spa/contributions/user-stories/application-spa-us-1117.json +20 -10
  503. package/blueprints/application-spa/contributions/user-stories/application-spa-us-1118.json +9 -5
  504. package/blueprints/application-spa/contributions/user-stories/application-spa-us-1119.json +11 -6
  505. package/blueprints/application-spa/contributions/user-stories/application-spa-us-1120.json +16 -10
  506. package/blueprints/application-spa/contributions/user-stories/application-spa-us-1121.json +13 -7
  507. package/blueprints/application-spa/contributions/user-stories/application-spa-us-1122.json +13 -7
  508. package/blueprints/application-spa/contributions/user-stories/application-spa-us-1123.json +28 -9
  509. package/blueprints/application-spa/contributions/user-stories/application-spa-us-1124.json +11 -6
  510. package/blueprints/application-spa/contributions/user-stories/application-spa-us-1125.json +14 -8
  511. package/blueprints/application-spa/contributions/user-stories/application-spa-us-1126.json +24 -9
  512. package/blueprints/application-spa/contributions/user-stories/application-spa-us-1127.json +11 -6
  513. package/blueprints/application-spa/contributions/user-stories/application-spa-us-1128.json +11 -7
  514. package/blueprints/application-spa/contributions/user-stories/application-spa-us-1129.json +25 -5
  515. package/blueprints/application-spa/contributions/user-stories/application-spa-us-1130.json +25 -5
  516. package/blueprints/application-spa/contributions/user-stories/application-spa-us-1131.json +19 -9
  517. package/blueprints/application-spa/contributions/user-stories/application-spa-us-1132.json +40 -10
  518. package/blueprints/application-spa/contributions/user-stories/application-spa-us-1133.json +35 -9
  519. package/blueprints/application-spa/contributions/user-stories/application-spa-us-1134.json +23 -3
  520. package/blueprints/application-spa/contributions/user-stories/application-spa-us-1135.json +19 -3
  521. package/blueprints/application-spa/docs/topics.md +1 -1
  522. package/blueprints/application-spa/guide/application-spa.md +2 -2
  523. package/blueprints/delivery-ci-workflows/CHANGELOG.md +40 -2
  524. package/blueprints/delivery-ci-workflows/README.md +4 -4
  525. package/blueprints/delivery-ci-workflows/blueprint.json +64 -2
  526. package/blueprints/delivery-ci-workflows/contributions/adrs/adr-702-delivery-ci-workflows-strict-coverage-gate.json +2 -2
  527. package/blueprints/delivery-ci-workflows/contributions/probes/node-gate-entrypoint.mjs +76 -0
  528. package/blueprints/delivery-ci-workflows/contributions/probes/probe-utils.mjs +56 -0
  529. package/blueprints/delivery-ci-workflows/contributions/probes/real-account-github-actions-run-record.mjs +139 -0
  530. package/blueprints/delivery-ci-workflows/contributions/probes/run-node-gate-entrypoint.mjs +3 -0
  531. package/blueprints/delivery-ci-workflows/contributions/probes/run-real-account-github-actions-run-record.mjs +3 -0
  532. package/blueprints/delivery-ci-workflows/contributions/probes/run-workflow-template-shape.mjs +3 -0
  533. package/blueprints/delivery-ci-workflows/contributions/probes/workflow-template-shape.mjs +94 -0
  534. package/blueprints/delivery-ci-workflows/contributions/requirements/delivery-ci-workflows-req-001.json +4 -0
  535. package/blueprints/delivery-ci-workflows/contributions/requirements/delivery-ci-workflows-req-002.json +4 -0
  536. package/blueprints/delivery-ci-workflows/contributions/requirements/delivery-ci-workflows-req-003.json +4 -0
  537. package/blueprints/delivery-ci-workflows/contributions/requirements/delivery-ci-workflows-req-004.json +5 -1
  538. package/blueprints/delivery-ci-workflows/contributions/requirements/delivery-ci-workflows-req-005.json +4 -0
  539. package/blueprints/delivery-ci-workflows/contributions/requirements/delivery-ci-workflows-req-006.json +4 -0
  540. package/blueprints/delivery-ci-workflows/contributions/requirements/delivery-ci-workflows-req-007.json +4 -0
  541. package/blueprints/delivery-ci-workflows/contributions/requirements/delivery-ci-workflows-req-008.json +4 -0
  542. package/blueprints/delivery-ci-workflows/contributions/requirements/delivery-ci-workflows-req-009.json +4 -0
  543. package/blueprints/delivery-ci-workflows/contributions/requirements/delivery-ci-workflows-req-010.json +4 -0
  544. package/blueprints/delivery-ci-workflows/contributions/requirements/delivery-ci-workflows-req-011.json +6 -2
  545. package/blueprints/delivery-ci-workflows/contributions/requirements/delivery-ci-workflows-req-012.json +4 -0
  546. package/blueprints/delivery-ci-workflows/contributions/requirements/delivery-ci-workflows-req-013.json +4 -0
  547. package/blueprints/delivery-ci-workflows/contributions/requirements/delivery-ci-workflows-req-014.json +4 -0
  548. package/blueprints/delivery-ci-workflows/contributions/requirements/delivery-ci-workflows-req-015.json +4 -0
  549. package/blueprints/delivery-ci-workflows/contributions/requirements/delivery-ci-workflows-req-016.json +4 -0
  550. package/blueprints/delivery-ci-workflows/contributions/requirements/delivery-ci-workflows-req-017.json +4 -0
  551. package/blueprints/delivery-ci-workflows/contributions/requirements/delivery-ci-workflows-req-018.json +4 -0
  552. package/blueprints/delivery-ci-workflows/contributions/requirements/delivery-ci-workflows-req-019.json +4 -0
  553. package/blueprints/delivery-ci-workflows/contributions/requirements/delivery-ci-workflows-req-020.json +4 -0
  554. package/blueprints/delivery-ci-workflows/contributions/requirements/delivery-ci-workflows-req-021.json +4 -0
  555. package/blueprints/delivery-ci-workflows/contributions/requirements/delivery-ci-workflows-req-022.json +4 -0
  556. package/blueprints/delivery-ci-workflows/contributions/requirements/delivery-ci-workflows-req-023.json +4 -0
  557. package/blueprints/delivery-ci-workflows/contributions/user-stories/delivery-ci-workflows-us-6101.json +20 -4
  558. package/blueprints/delivery-ci-workflows/contributions/user-stories/delivery-ci-workflows-us-6102.json +19 -3
  559. package/blueprints/delivery-ci-workflows/contributions/user-stories/delivery-ci-workflows-us-6103.json +20 -4
  560. package/blueprints/delivery-ci-workflows/contributions/user-stories/delivery-ci-workflows-us-6104.json +20 -4
  561. package/blueprints/delivery-ci-workflows/contributions/user-stories/delivery-ci-workflows-us-6105.json +20 -4
  562. package/blueprints/delivery-ci-workflows/contributions/user-stories/delivery-ci-workflows-us-6106.json +20 -4
  563. package/blueprints/delivery-ci-workflows/contributions/user-stories/delivery-ci-workflows-us-6107.json +20 -4
  564. package/blueprints/delivery-ci-workflows/contributions/user-stories/delivery-ci-workflows-us-6108.json +20 -4
  565. package/blueprints/delivery-ci-workflows/contributions/user-stories/delivery-ci-workflows-us-6109.json +12 -5
  566. package/blueprints/delivery-ci-workflows/contributions/user-stories/delivery-ci-workflows-us-6110.json +21 -5
  567. package/blueprints/delivery-ci-workflows/contributions/user-stories/delivery-ci-workflows-us-6111.json +21 -5
  568. package/blueprints/delivery-ci-workflows/contributions/user-stories/delivery-ci-workflows-us-6112.json +35 -5
  569. package/blueprints/delivery-ci-workflows/contributions/user-stories/delivery-ci-workflows-us-6113.json +21 -5
  570. package/blueprints/delivery-ci-workflows/contributions/user-stories/delivery-ci-workflows-us-6114.json +8 -5
  571. package/blueprints/delivery-ci-workflows/contributions/user-stories/delivery-ci-workflows-us-6115.json +21 -5
  572. package/blueprints/delivery-ci-workflows/contributions/user-stories/delivery-ci-workflows-us-6116.json +19 -3
  573. package/blueprints/delivery-ci-workflows/contributions/user-stories/delivery-ci-workflows-us-6117.json +19 -3
  574. package/blueprints/delivery-ci-workflows/contributions/user-stories/delivery-ci-workflows-us-6118.json +21 -5
  575. package/blueprints/delivery-ci-workflows/contributions/user-stories/delivery-ci-workflows-us-6119.json +19 -3
  576. package/blueprints/delivery-ci-workflows/contributions/user-stories/delivery-ci-workflows-us-6120.json +19 -3
  577. package/blueprints/delivery-ci-workflows/contributions/user-stories/delivery-ci-workflows-us-6121.json +23 -6
  578. package/blueprints/delivery-ci-workflows/contributions/user-stories/delivery-ci-workflows-us-6122.json +24 -7
  579. package/blueprints/delivery-ci-workflows/contributions/user-stories/delivery-ci-workflows-us-6123.json +21 -5
  580. package/blueprints/delivery-ci-workflows/contributions/user-stories/delivery-ci-workflows-us-6124.json +19 -3
  581. package/blueprints/delivery-ci-workflows/docs/topics.md +2 -3
  582. package/blueprints/deploy-cloudflare-workers/CHANGELOG.md +19 -4
  583. package/blueprints/deploy-cloudflare-workers/README.md +5 -5
  584. package/blueprints/deploy-cloudflare-workers/blueprint.json +4 -4
  585. package/blueprints/deploy-cloudflare-workers/contributions/adrs/adr-1303-deploy-cloudflare-workers-preview-vs-production.json +1 -1
  586. package/blueprints/deploy-cloudflare-workers/contributions/adrs/adr-1306-deploy-cloudflare-workers-spa-shape.json +4 -4
  587. package/blueprints/deploy-cloudflare-workers/contributions/probes/assets-manifest-scan.mjs +25 -7
  588. package/blueprints/deploy-cloudflare-workers/contributions/requirements/deploy-cloudflare-workers-req-001.json +5 -1
  589. package/blueprints/deploy-cloudflare-workers/contributions/requirements/deploy-cloudflare-workers-req-002.json +6 -2
  590. package/blueprints/deploy-cloudflare-workers/contributions/requirements/deploy-cloudflare-workers-req-003.json +5 -1
  591. package/blueprints/deploy-cloudflare-workers/contributions/requirements/deploy-cloudflare-workers-req-004.json +5 -1
  592. package/blueprints/deploy-cloudflare-workers/contributions/requirements/deploy-cloudflare-workers-req-005.json +5 -1
  593. package/blueprints/deploy-cloudflare-workers/contributions/requirements/deploy-cloudflare-workers-req-006.json +5 -1
  594. package/blueprints/deploy-cloudflare-workers/contributions/requirements/deploy-cloudflare-workers-req-007.json +5 -1
  595. package/blueprints/deploy-cloudflare-workers/contributions/requirements/deploy-cloudflare-workers-req-008.json +5 -1
  596. package/blueprints/deploy-cloudflare-workers/contributions/requirements/deploy-cloudflare-workers-req-009.json +5 -1
  597. package/blueprints/deploy-cloudflare-workers/contributions/requirements/deploy-cloudflare-workers-req-010.json +5 -1
  598. package/blueprints/deploy-cloudflare-workers/contributions/requirements/deploy-cloudflare-workers-req-011.json +5 -1
  599. package/blueprints/deploy-cloudflare-workers/contributions/requirements/deploy-cloudflare-workers-req-012.json +5 -1
  600. package/blueprints/deploy-cloudflare-workers/contributions/requirements/deploy-cloudflare-workers-req-013.json +5 -1
  601. package/blueprints/deploy-cloudflare-workers/contributions/requirements/deploy-cloudflare-workers-req-014.json +7 -3
  602. package/blueprints/deploy-cloudflare-workers/contributions/tacs/tac-1301-deploy-cloudflare-workers-deploy-adapter.json +3 -2
  603. package/blueprints/deploy-cloudflare-workers/contributions/tacs/tac-1302-deploy-cloudflare-workers-wrangler-manifest.json +5 -2
  604. package/blueprints/deploy-cloudflare-workers/contributions/user-stories/deploy-cloudflare-workers-us-12101.json +21 -9
  605. package/blueprints/deploy-cloudflare-workers/contributions/user-stories/deploy-cloudflare-workers-us-12102.json +23 -4
  606. package/blueprints/deploy-cloudflare-workers/contributions/user-stories/deploy-cloudflare-workers-us-12103.json +7 -4
  607. package/blueprints/deploy-cloudflare-workers/contributions/user-stories/deploy-cloudflare-workers-us-12104.json +7 -4
  608. package/blueprints/deploy-cloudflare-workers/contributions/user-stories/deploy-cloudflare-workers-us-12105.json +11 -4
  609. package/blueprints/deploy-cloudflare-workers/contributions/user-stories/deploy-cloudflare-workers-us-12106.json +7 -4
  610. package/blueprints/deploy-cloudflare-workers/contributions/user-stories/deploy-cloudflare-workers-us-12107.json +7 -4
  611. package/blueprints/deploy-cloudflare-workers/contributions/user-stories/deploy-cloudflare-workers-us-12108.json +15 -4
  612. package/blueprints/deploy-cloudflare-workers/contributions/user-stories/deploy-cloudflare-workers-us-12109.json +11 -4
  613. package/blueprints/deploy-cloudflare-workers/contributions/user-stories/deploy-cloudflare-workers-us-12110.json +7 -4
  614. package/blueprints/deploy-cloudflare-workers/contributions/user-stories/deploy-cloudflare-workers-us-12111.json +11 -4
  615. package/blueprints/deploy-cloudflare-workers/contributions/user-stories/deploy-cloudflare-workers-us-12112.json +11 -4
  616. package/blueprints/deploy-cloudflare-workers/contributions/user-stories/deploy-cloudflare-workers-us-12113.json +41 -3
  617. package/blueprints/deploy-cloudflare-workers/contributions/user-stories/deploy-cloudflare-workers-us-12114.json +17 -2
  618. package/blueprints/deploy-cloudflare-workers/contributions/user-stories/deploy-cloudflare-workers-us-12115.json +18 -3
  619. package/blueprints/deploy-cloudflare-workers/docs/topics.md +2 -2
  620. package/blueprints/deploy-cloudflare-workers/guide/deploy-cloudflare-workers.md +7 -2
  621. package/blueprints/deploy-hetzner-server/CHANGELOG.md +115 -8
  622. package/blueprints/deploy-hetzner-server/README.md +12 -12
  623. package/blueprints/deploy-hetzner-server/blueprint.json +8 -7
  624. package/blueprints/deploy-hetzner-server/contributions/adrs/adr-3801-deploy-hetzner-server-cloud-host-contract.json +2 -2
  625. package/blueprints/deploy-hetzner-server/contributions/adrs/adr-3803-deploy-hetzner-server-provisioning-tool.json +2 -2
  626. package/blueprints/deploy-hetzner-server/contributions/probes/cloud-init-render-lint.mjs +46 -21
  627. package/blueprints/deploy-hetzner-server/contributions/probes/hcloud-dry-run-mock.mjs +344 -83
  628. package/blueprints/deploy-hetzner-server/contributions/probes/manifest-schema-validate.mjs +211 -42
  629. package/blueprints/deploy-hetzner-server/contributions/probes/probe-utils.mjs +140 -22
  630. package/blueprints/deploy-hetzner-server/contributions/probes/real-account-cloud-init-hardened.mjs +111 -30
  631. package/blueprints/deploy-hetzner-server/contributions/probes/real-account-snapshot-on-demand.mjs +158 -30
  632. package/blueprints/deploy-hetzner-server/contributions/probes/real-account-throwaway-server-provision.mjs +154 -32
  633. package/blueprints/deploy-hetzner-server/contributions/requirements/deploy-hetzner-server-req-001.json +6 -2
  634. package/blueprints/deploy-hetzner-server/contributions/requirements/deploy-hetzner-server-req-002.json +6 -2
  635. package/blueprints/deploy-hetzner-server/contributions/requirements/deploy-hetzner-server-req-003.json +5 -1
  636. package/blueprints/deploy-hetzner-server/contributions/requirements/deploy-hetzner-server-req-004.json +5 -1
  637. package/blueprints/deploy-hetzner-server/contributions/requirements/deploy-hetzner-server-req-005.json +6 -2
  638. package/blueprints/deploy-hetzner-server/contributions/requirements/deploy-hetzner-server-req-006.json +5 -1
  639. package/blueprints/deploy-hetzner-server/contributions/schemas/hetzner-server.schema.json +1 -1
  640. package/blueprints/deploy-hetzner-server/contributions/templates/cloud-init.yaml.tmpl +1 -1
  641. package/blueprints/deploy-hetzner-server/contributions/user-stories/deploy-hetzner-server-us-37101.json +63 -2
  642. package/blueprints/deploy-hetzner-server/contributions/user-stories/deploy-hetzner-server-us-37102.json +35 -2
  643. package/blueprints/deploy-hetzner-server/contributions/user-stories/deploy-hetzner-server-us-37103.json +59 -2
  644. package/blueprints/deploy-hetzner-server/contributions/user-stories/deploy-hetzner-server-us-37104.json +31 -2
  645. package/blueprints/deploy-hetzner-server/contributions/user-stories/deploy-hetzner-server-us-37105.json +25 -2
  646. package/blueprints/deploy-hetzner-server/contributions/user-stories/deploy-hetzner-server-us-37106.json +35 -2
  647. package/blueprints/deploy-hetzner-server/contributions/user-stories/deploy-hetzner-server-us-37107.json +31 -2
  648. package/blueprints/deploy-hetzner-server/contributions/user-stories/deploy-hetzner-server-us-37108.json +43 -2
  649. package/blueprints/deploy-hetzner-server/contributions/user-stories/deploy-hetzner-server-us-37109.json +31 -2
  650. package/blueprints/deploy-hetzner-server/docs/topics.md +2 -2
  651. package/blueprints/deploy-hetzner-server/guide/deploy-hetzner-server.md +12 -11
  652. package/blueprints/edge-cloudflare-access/CHANGELOG.md +36 -3
  653. package/blueprints/edge-cloudflare-access/README.md +2 -2
  654. package/blueprints/edge-cloudflare-access/blueprint.json +12 -2
  655. package/blueprints/edge-cloudflare-access/contributions/probes/admin-console-gate-surface.mjs +9 -1
  656. package/blueprints/edge-cloudflare-access/contributions/probes/real-account-gated-url.mjs +10 -2
  657. package/blueprints/edge-cloudflare-access/contributions/probes/wrangler-seam.mjs +1 -1
  658. package/blueprints/edge-cloudflare-access/contributions/requirements/edge-cloudflare-access-req-001.json +5 -1
  659. package/blueprints/edge-cloudflare-access/contributions/requirements/edge-cloudflare-access-req-002.json +5 -1
  660. package/blueprints/edge-cloudflare-access/contributions/requirements/edge-cloudflare-access-req-003.json +5 -1
  661. package/blueprints/edge-cloudflare-access/contributions/requirements/edge-cloudflare-access-req-004.json +6 -2
  662. package/blueprints/edge-cloudflare-access/contributions/requirements/edge-cloudflare-access-req-005.json +5 -1
  663. package/blueprints/edge-cloudflare-access/contributions/requirements/edge-cloudflare-access-req-006.json +7 -3
  664. package/blueprints/edge-cloudflare-access/contributions/requirements/edge-cloudflare-access-req-007.json +22 -0
  665. package/blueprints/edge-cloudflare-access/contributions/user-stories/edge-cloudflare-access-us-34101.json +13 -3
  666. package/blueprints/edge-cloudflare-access/contributions/user-stories/edge-cloudflare-access-us-34102.json +63 -2
  667. package/blueprints/edge-cloudflare-access/contributions/user-stories/edge-cloudflare-access-us-34103.json +18 -3
  668. package/blueprints/edge-cloudflare-access/contributions/user-stories/edge-cloudflare-access-us-34104.json +36 -3
  669. package/blueprints/edge-cloudflare-access/contributions/user-stories/edge-cloudflare-access-us-34105.json +13 -3
  670. package/blueprints/edge-cloudflare-access/contributions/user-stories/edge-cloudflare-access-us-34106.json +9 -3
  671. package/blueprints/edge-cloudflare-access/contributions/user-stories/edge-cloudflare-access-us-34107.json +68 -3
  672. package/blueprints/edge-cloudflare-access/contributions/user-stories/edge-cloudflare-access-us-34108.json +5 -3
  673. package/blueprints/edge-cloudflare-access/contributions/user-stories/edge-cloudflare-access-us-34109.json +10 -4
  674. package/blueprints/edge-cloudflare-access/contributions/user-stories/edge-cloudflare-access-us-34110.json +33 -0
  675. package/blueprints/edge-cloudflare-access/docs/topics.md +2 -2
  676. package/blueprints/edge-cloudflare-rate-limiting/CHANGELOG.md +33 -2
  677. package/blueprints/edge-cloudflare-rate-limiting/README.md +3 -3
  678. package/blueprints/edge-cloudflare-rate-limiting/blueprint.json +1 -1
  679. package/blueprints/edge-cloudflare-rate-limiting/contributions/probes/real-account-burst-and-429.mjs +10 -2
  680. package/blueprints/edge-cloudflare-rate-limiting/contributions/requirements/edge-cloudflare-rate-limiting-req-001.json +6 -2
  681. package/blueprints/edge-cloudflare-rate-limiting/contributions/requirements/edge-cloudflare-rate-limiting-req-002.json +5 -1
  682. package/blueprints/edge-cloudflare-rate-limiting/contributions/requirements/edge-cloudflare-rate-limiting-req-003.json +5 -1
  683. package/blueprints/edge-cloudflare-rate-limiting/contributions/requirements/edge-cloudflare-rate-limiting-req-004.json +6 -2
  684. package/blueprints/edge-cloudflare-rate-limiting/contributions/requirements/edge-cloudflare-rate-limiting-req-005.json +5 -1
  685. package/blueprints/edge-cloudflare-rate-limiting/contributions/tacs/tac-3701-edge-cloudflare-rate-limiting-manifest-schema.json +2 -2
  686. package/blueprints/edge-cloudflare-rate-limiting/contributions/tacs/tac-3703-edge-cloudflare-rate-limiting-drift-audit-runner.json +2 -2
  687. package/blueprints/edge-cloudflare-rate-limiting/contributions/user-stories/edge-cloudflare-rate-limiting-us-36101.json +27 -3
  688. package/blueprints/edge-cloudflare-rate-limiting/contributions/user-stories/edge-cloudflare-rate-limiting-us-36102.json +9 -3
  689. package/blueprints/edge-cloudflare-rate-limiting/contributions/user-stories/edge-cloudflare-rate-limiting-us-36103.json +24 -5
  690. package/blueprints/edge-cloudflare-rate-limiting/contributions/user-stories/edge-cloudflare-rate-limiting-us-36104.json +88 -3
  691. package/blueprints/edge-cloudflare-rate-limiting/contributions/user-stories/edge-cloudflare-rate-limiting-us-36105.json +5 -3
  692. package/blueprints/edge-cloudflare-rate-limiting/contributions/user-stories/edge-cloudflare-rate-limiting-us-36106.json +22 -3
  693. package/blueprints/edge-cloudflare-rate-limiting/contributions/user-stories/edge-cloudflare-rate-limiting-us-36107.json +16 -5
  694. package/blueprints/edge-cloudflare-rate-limiting/contributions/user-stories/edge-cloudflare-rate-limiting-us-36108.json +14 -3
  695. package/blueprints/edge-cloudflare-rate-limiting/docs/topics.md +1 -1
  696. package/blueprints/edge-cloudflare-rate-limiting/guide/edge-cloudflare-rate-limiting.md +2 -2
  697. package/blueprints/edge-cloudflare-tunnel/CHANGELOG.md +40 -7
  698. package/blueprints/edge-cloudflare-tunnel/README.md +21 -23
  699. package/blueprints/edge-cloudflare-tunnel/blueprint.json +29 -4
  700. package/blueprints/edge-cloudflare-tunnel/contributions/adrs/adr-4001-edge-cloudflare-tunnel-ingress-bridge-contract.json +4 -4
  701. package/blueprints/edge-cloudflare-tunnel/contributions/adrs/adr-4002-edge-cloudflare-tunnel-connector-runtime.json +1 -1
  702. package/blueprints/edge-cloudflare-tunnel/contributions/probes/manifest-schema-validate.mjs +3 -3
  703. package/blueprints/edge-cloudflare-tunnel/contributions/probes/probe-utils.mjs +13 -2
  704. package/blueprints/edge-cloudflare-tunnel/contributions/probes/real-account-connector-healthy.mjs +8 -9
  705. package/blueprints/edge-cloudflare-tunnel/contributions/probes/real-account-tunnel-hostname-routes.mjs +2 -2
  706. package/blueprints/edge-cloudflare-tunnel/contributions/requirements/edge-cloudflare-tunnel-req-001.json +6 -2
  707. package/blueprints/edge-cloudflare-tunnel/contributions/requirements/edge-cloudflare-tunnel-req-002.json +5 -1
  708. package/blueprints/edge-cloudflare-tunnel/contributions/requirements/edge-cloudflare-tunnel-req-003.json +7 -3
  709. package/blueprints/edge-cloudflare-tunnel/contributions/requirements/edge-cloudflare-tunnel-req-004.json +5 -1
  710. package/blueprints/edge-cloudflare-tunnel/contributions/requirements/edge-cloudflare-tunnel-req-005.json +5 -1
  711. package/blueprints/edge-cloudflare-tunnel/contributions/requirements/edge-cloudflare-tunnel-req-006.json +22 -0
  712. package/blueprints/edge-cloudflare-tunnel/contributions/requirements/edge-cloudflare-tunnel-req-007.json +22 -0
  713. package/blueprints/edge-cloudflare-tunnel/contributions/tacs/tac-4001-edge-cloudflare-tunnel-connector-shape.json +1 -1
  714. package/blueprints/edge-cloudflare-tunnel/contributions/tacs/tac-4004-edge-cloudflare-tunnel-zone-and-hostname-apply.json +29 -0
  715. package/blueprints/edge-cloudflare-tunnel/contributions/user-stories/edge-cloudflare-tunnel-us-39101.json +39 -3
  716. package/blueprints/edge-cloudflare-tunnel/contributions/user-stories/edge-cloudflare-tunnel-us-39102.json +23 -4
  717. package/blueprints/edge-cloudflare-tunnel/contributions/user-stories/edge-cloudflare-tunnel-us-39103.json +53 -3
  718. package/blueprints/edge-cloudflare-tunnel/contributions/user-stories/edge-cloudflare-tunnel-us-39104.json +33 -3
  719. package/blueprints/edge-cloudflare-tunnel/contributions/user-stories/edge-cloudflare-tunnel-us-39105.json +25 -3
  720. package/blueprints/edge-cloudflare-tunnel/contributions/user-stories/edge-cloudflare-tunnel-us-39106.json +86 -2
  721. package/blueprints/edge-cloudflare-tunnel/contributions/user-stories/edge-cloudflare-tunnel-us-39107.json +25 -3
  722. package/blueprints/edge-cloudflare-tunnel/contributions/user-stories/edge-cloudflare-tunnel-us-39108.json +35 -2
  723. package/blueprints/edge-cloudflare-tunnel/contributions/user-stories/edge-cloudflare-tunnel-us-39109.json +74 -0
  724. package/blueprints/edge-cloudflare-tunnel/contributions/user-stories/edge-cloudflare-tunnel-us-39110.json +60 -0
  725. package/blueprints/edge-cloudflare-tunnel/docs/topics.md +2 -2
  726. package/blueprints/edge-cloudflare-tunnel/guide/edge-cloudflare-tunnel.md +60 -13
  727. package/blueprints/edge-cloudflare-turnstile/CHANGELOG.md +32 -1
  728. package/blueprints/edge-cloudflare-turnstile/README.md +2 -2
  729. package/blueprints/edge-cloudflare-turnstile/blueprint.json +1 -1
  730. package/blueprints/edge-cloudflare-turnstile/contributions/requirements/edge-cloudflare-turnstile-req-001.json +6 -2
  731. package/blueprints/edge-cloudflare-turnstile/contributions/requirements/edge-cloudflare-turnstile-req-002.json +5 -1
  732. package/blueprints/edge-cloudflare-turnstile/contributions/requirements/edge-cloudflare-turnstile-req-003.json +6 -2
  733. package/blueprints/edge-cloudflare-turnstile/contributions/requirements/edge-cloudflare-turnstile-req-004.json +5 -1
  734. package/blueprints/edge-cloudflare-turnstile/contributions/requirements/edge-cloudflare-turnstile-req-005.json +5 -1
  735. package/blueprints/edge-cloudflare-turnstile/contributions/tacs/tac-3601-edge-cloudflare-turnstile-widget-mount.json +2 -2
  736. package/blueprints/edge-cloudflare-turnstile/contributions/tacs/tac-3602-edge-cloudflare-turnstile-server-verifier.json +2 -2
  737. package/blueprints/edge-cloudflare-turnstile/contributions/user-stories/edge-cloudflare-turnstile-us-35101.json +46 -5
  738. package/blueprints/edge-cloudflare-turnstile/contributions/user-stories/edge-cloudflare-turnstile-us-35102.json +53 -2
  739. package/blueprints/edge-cloudflare-turnstile/contributions/user-stories/edge-cloudflare-turnstile-us-35103.json +81 -2
  740. package/blueprints/edge-cloudflare-turnstile/contributions/user-stories/edge-cloudflare-turnstile-us-35104.json +29 -6
  741. package/blueprints/edge-cloudflare-turnstile/contributions/user-stories/edge-cloudflare-turnstile-us-35105.json +14 -4
  742. package/blueprints/edge-cloudflare-turnstile/contributions/user-stories/edge-cloudflare-turnstile-us-35106.json +9 -3
  743. package/blueprints/edge-cloudflare-turnstile/contributions/user-stories/edge-cloudflare-turnstile-us-35107.json +5 -3
  744. package/blueprints/edge-cloudflare-turnstile/contributions/user-stories/edge-cloudflare-turnstile-us-35108.json +5 -3
  745. package/blueprints/edge-cloudflare-turnstile/docs/topics.md +1 -1
  746. package/blueprints/edge-cloudflare-turnstile/probe-packs/edge-cloudflare-turnstile.pack.mjs +27 -5
  747. package/blueprints/email-smtp-resend/CHANGELOG.md +40 -0
  748. package/blueprints/email-smtp-resend/README.md +4 -4
  749. package/blueprints/email-smtp-resend/assets/stub-adapter.md +2 -0
  750. package/blueprints/email-smtp-resend/blueprint.json +121 -18
  751. package/blueprints/email-smtp-resend/contributions/probes/probe-utils.mjs +50 -0
  752. package/blueprints/email-smtp-resend/contributions/probes/real-account-resend-send.mjs +50 -0
  753. package/blueprints/email-smtp-resend/contributions/probes/run-real-account-resend-send.mjs +3 -0
  754. package/blueprints/email-smtp-resend/contributions/probes/run-smtp-round-trip.mjs +3 -0
  755. package/blueprints/email-smtp-resend/contributions/probes/run-unverified-sender-refusal.mjs +3 -0
  756. package/blueprints/email-smtp-resend/contributions/probes/smtp-round-trip.mjs +43 -0
  757. package/blueprints/email-smtp-resend/contributions/probes/unverified-sender-refusal.mjs +99 -0
  758. package/blueprints/email-smtp-resend/contributions/requirements/email-smtp-resend-req-001.json +7 -3
  759. package/blueprints/email-smtp-resend/contributions/requirements/email-smtp-resend-req-002.json +4 -0
  760. package/blueprints/email-smtp-resend/contributions/requirements/email-smtp-resend-req-003.json +4 -0
  761. package/blueprints/email-smtp-resend/contributions/requirements/email-smtp-resend-req-004.json +4 -0
  762. package/blueprints/email-smtp-resend/contributions/requirements/email-smtp-resend-req-005.json +4 -0
  763. package/blueprints/email-smtp-resend/contributions/requirements/email-smtp-resend-req-006.json +4 -0
  764. package/blueprints/email-smtp-resend/contributions/tacs/tac-401-email-smtp-resend-send-adapter.json +3 -3
  765. package/blueprints/email-smtp-resend/contributions/tacs/tac-402-email-smtp-resend-webhook-verifier.json +7 -2
  766. package/blueprints/email-smtp-resend/contributions/user-stories/email-smtp-resend-us-4101.json +15 -8
  767. package/blueprints/email-smtp-resend/contributions/user-stories/email-smtp-resend-us-4102.json +27 -7
  768. package/blueprints/email-smtp-resend/contributions/user-stories/email-smtp-resend-us-4103.json +49 -4
  769. package/blueprints/email-smtp-resend/contributions/user-stories/email-smtp-resend-us-4104.json +6 -3
  770. package/blueprints/email-smtp-resend/contributions/user-stories/email-smtp-resend-us-4105.json +21 -5
  771. package/blueprints/email-smtp-resend/contributions/user-stories/email-smtp-resend-us-4106.json +27 -7
  772. package/blueprints/email-smtp-resend/docs/topics.md +2 -3
  773. package/blueprints/email-smtp-resend/guide/email-smtp-resend.md +2 -2
  774. package/blueprints/jobs-background/CHANGELOG.md +91 -6
  775. package/blueprints/jobs-background/README.md +8 -8
  776. package/blueprints/jobs-background/blueprint.json +57 -3
  777. package/blueprints/jobs-background/contributions/adrs/adr-3102-jobs-background-scheduler-mode.json +1 -1
  778. package/blueprints/jobs-background/contributions/adrs/adr-3103-jobs-background-requires-applied-capabilities.json +6 -6
  779. package/blueprints/jobs-background/contributions/probes/apply-time-override.mjs +38 -10
  780. package/blueprints/jobs-background/contributions/probes/apply-time-refusal.mjs +28 -6
  781. package/blueprints/jobs-background/contributions/probes/event-secrecy.mjs +16 -2
  782. package/blueprints/jobs-background/contributions/probes/fake-clock-cron.mjs +102 -21
  783. package/blueprints/jobs-background/contributions/probes/probe-utils.mjs +14 -6
  784. package/blueprints/jobs-background/contributions/probes/retry-and-fail-real-account.mjs +355 -0
  785. package/blueprints/jobs-background/contributions/probes/retry-and-fail.mjs +33 -2
  786. package/blueprints/jobs-background/contributions/probes/run-retry-and-fail-real-account.mjs +12 -0
  787. package/blueprints/jobs-background/contributions/requirements/jobs-background-req-001.json +7 -3
  788. package/blueprints/jobs-background/contributions/requirements/jobs-background-req-002.json +7 -3
  789. package/blueprints/jobs-background/contributions/requirements/jobs-background-req-003.json +5 -1
  790. package/blueprints/jobs-background/contributions/requirements/jobs-background-req-004.json +5 -1
  791. package/blueprints/jobs-background/contributions/requirements/jobs-background-req-005.json +5 -1
  792. package/blueprints/jobs-background/contributions/requirements/jobs-background-req-006.json +5 -1
  793. package/blueprints/jobs-background/contributions/tacs/tac-3101-jobs-background-job-definition.json +5 -5
  794. package/blueprints/jobs-background/contributions/user-stories/jobs-background-us-30101.json +20 -3
  795. package/blueprints/jobs-background/contributions/user-stories/jobs-background-us-30102.json +44 -9
  796. package/blueprints/jobs-background/contributions/user-stories/jobs-background-us-30103.json +48 -3
  797. package/blueprints/jobs-background/contributions/user-stories/jobs-background-us-30104.json +63 -3
  798. package/blueprints/jobs-background/contributions/user-stories/jobs-background-us-30105.json +20 -3
  799. package/blueprints/jobs-background/contributions/user-stories/jobs-background-us-30106.json +20 -3
  800. package/blueprints/jobs-background/contributions/user-stories/jobs-background-us-30107.json +20 -3
  801. package/blueprints/jobs-background/contributions/user-stories/jobs-background-us-30108.json +21 -3
  802. package/blueprints/jobs-background/contributions/user-stories/jobs-background-us-30109.json +23 -6
  803. package/blueprints/jobs-background/docs/topics.md +3 -3
  804. package/blueprints/jobs-background/guide/jobs-background.md +6 -6
  805. package/blueprints/messaging-queue-cloudflare/CHANGELOG.md +41 -19
  806. package/blueprints/messaging-queue-cloudflare/README.md +14 -14
  807. package/blueprints/messaging-queue-cloudflare/blueprint.json +127 -19
  808. package/blueprints/messaging-queue-cloudflare/contributions/adrs/adr-3001-messaging-queue-cloudflare-adapter.json +3 -3
  809. package/blueprints/messaging-queue-cloudflare/contributions/adrs/adr-3002-messaging-queue-cloudflare-delivery-semantics.json +1 -1
  810. package/blueprints/messaging-queue-cloudflare/contributions/probes/real-account-concurrency-smoke.mjs +183 -15
  811. package/blueprints/messaging-queue-cloudflare/contributions/requirements/messaging-queue-cloudflare-req-001.json +6 -2
  812. package/blueprints/messaging-queue-cloudflare/contributions/requirements/messaging-queue-cloudflare-req-002.json +6 -2
  813. package/blueprints/messaging-queue-cloudflare/contributions/requirements/messaging-queue-cloudflare-req-003.json +5 -1
  814. package/blueprints/messaging-queue-cloudflare/contributions/requirements/messaging-queue-cloudflare-req-004.json +6 -2
  815. package/blueprints/messaging-queue-cloudflare/contributions/requirements/messaging-queue-cloudflare-req-005.json +6 -2
  816. package/blueprints/messaging-queue-cloudflare/contributions/requirements/messaging-queue-cloudflare-req-006.json +6 -2
  817. package/blueprints/messaging-queue-cloudflare/contributions/user-stories/messaging-queue-cloudflare-us-29101.json +22 -4
  818. package/blueprints/messaging-queue-cloudflare/contributions/user-stories/messaging-queue-cloudflare-us-29102.json +23 -4
  819. package/blueprints/messaging-queue-cloudflare/contributions/user-stories/messaging-queue-cloudflare-us-29103.json +20 -3
  820. package/blueprints/messaging-queue-cloudflare/contributions/user-stories/messaging-queue-cloudflare-us-29104.json +29 -7
  821. package/blueprints/messaging-queue-cloudflare/contributions/user-stories/messaging-queue-cloudflare-us-29105.json +20 -3
  822. package/blueprints/messaging-queue-cloudflare/contributions/user-stories/messaging-queue-cloudflare-us-29106.json +25 -4
  823. package/blueprints/messaging-queue-cloudflare/contributions/user-stories/messaging-queue-cloudflare-us-29107.json +25 -3
  824. package/blueprints/messaging-queue-cloudflare/contributions/user-stories/messaging-queue-cloudflare-us-29108.json +28 -6
  825. package/blueprints/messaging-queue-cloudflare/docs/topics.md +3 -3
  826. package/blueprints/messaging-queue-cloudflare/guide/messaging-queue-cloudflare.md +8 -6
  827. package/blueprints/object-storage-s3/CHANGELOG.md +94 -6
  828. package/blueprints/object-storage-s3/README.md +2 -2
  829. package/blueprints/object-storage-s3/blueprint.json +156 -24
  830. package/blueprints/object-storage-s3/contributions/probes/event-secrecy.mjs +73 -12
  831. package/blueprints/object-storage-s3/contributions/probes/facade-round-trip.mjs +55 -7
  832. package/blueprints/object-storage-s3/contributions/probes/hetzner-object-storage-round-trip.mjs +103 -19
  833. package/blueprints/object-storage-s3/contributions/probes/multipart-upload.mjs +105 -36
  834. package/blueprints/object-storage-s3/contributions/probes/presigned-url.mjs +104 -55
  835. package/blueprints/object-storage-s3/contributions/probes/probe-utils.mjs +129 -7
  836. package/blueprints/object-storage-s3/contributions/probes/put-get-round-trip.mjs +80 -18
  837. package/blueprints/object-storage-s3/contributions/probes/r2-real-account-smoke.mjs +291 -37
  838. package/blueprints/object-storage-s3/contributions/probes/run-event-secrecy.mjs +8 -2
  839. package/blueprints/object-storage-s3/contributions/probes/run-facade-round-trip.mjs +5 -5
  840. package/blueprints/object-storage-s3/contributions/probes/run-hetzner-object-storage-round-trip.mjs +8 -5
  841. package/blueprints/object-storage-s3/contributions/probes/run-multipart-upload.mjs +8 -2
  842. package/blueprints/object-storage-s3/contributions/probes/run-presigned-url.mjs +8 -2
  843. package/blueprints/object-storage-s3/contributions/probes/run-put-get-round-trip.mjs +6 -3
  844. package/blueprints/object-storage-s3/contributions/probes/run-r2-real-account-smoke.mjs +10 -2
  845. package/blueprints/object-storage-s3/contributions/requirements/object-storage-s3-req-001.json +6 -2
  846. package/blueprints/object-storage-s3/contributions/requirements/object-storage-s3-req-002.json +6 -2
  847. package/blueprints/object-storage-s3/contributions/requirements/object-storage-s3-req-003.json +5 -1
  848. package/blueprints/object-storage-s3/contributions/requirements/object-storage-s3-req-004.json +6 -2
  849. package/blueprints/object-storage-s3/contributions/requirements/object-storage-s3-req-005.json +6 -2
  850. package/blueprints/object-storage-s3/contributions/requirements/object-storage-s3-req-006.json +6 -2
  851. package/blueprints/object-storage-s3/contributions/requirements/object-storage-s3-req-101.json +5 -1
  852. package/blueprints/object-storage-s3/contributions/user-stories/object-storage-s3-us-28101.json +36 -4
  853. package/blueprints/object-storage-s3/contributions/user-stories/object-storage-s3-us-28102.json +32 -5
  854. package/blueprints/object-storage-s3/contributions/user-stories/object-storage-s3-us-28103.json +42 -3
  855. package/blueprints/object-storage-s3/contributions/user-stories/object-storage-s3-us-28104.json +22 -4
  856. package/blueprints/object-storage-s3/contributions/user-stories/object-storage-s3-us-28105.json +25 -4
  857. package/blueprints/object-storage-s3/contributions/user-stories/object-storage-s3-us-28106.json +13 -5
  858. package/blueprints/object-storage-s3/contributions/user-stories/object-storage-s3-us-28107.json +10 -4
  859. package/blueprints/object-storage-s3/contributions/user-stories/object-storage-s3-us-28108.json +12 -4
  860. package/blueprints/object-storage-s3/contributions/user-stories/object-storage-s3-us-28110.json +20 -3
  861. package/blueprints/object-storage-s3/docs/topics.md +1 -1
  862. package/blueprints/object-storage-s3/guide/object-storage-s3.md +3 -3
  863. package/blueprints/observability-essentials/CHANGELOG.md +37 -0
  864. package/blueprints/observability-essentials/README.md +3 -3
  865. package/blueprints/observability-essentials/assets/probe-samples/probe-response-baseline.v2.json +17 -0
  866. package/blueprints/observability-essentials/blueprint.json +34 -2
  867. package/blueprints/observability-essentials/contributions/adrs/adr-801-observability-essentials-health-probes.json +1 -1
  868. package/blueprints/observability-essentials/contributions/probes/liveness-probe.mjs +84 -0
  869. package/blueprints/observability-essentials/contributions/probes/metrics-endpoint.mjs +96 -0
  870. package/blueprints/observability-essentials/contributions/probes/probe-utils.mjs +52 -0
  871. package/blueprints/observability-essentials/contributions/probes/readiness-probe.mjs +171 -0
  872. package/blueprints/observability-essentials/contributions/probes/run-liveness-probe.mjs +3 -0
  873. package/blueprints/observability-essentials/contributions/probes/run-metrics-endpoint.mjs +3 -0
  874. package/blueprints/observability-essentials/contributions/probes/run-readiness-probe.mjs +3 -0
  875. package/blueprints/observability-essentials/contributions/requirements/observability-essentials-req-001.json +4 -0
  876. package/blueprints/observability-essentials/contributions/requirements/observability-essentials-req-002.json +4 -0
  877. package/blueprints/observability-essentials/contributions/requirements/observability-essentials-req-003.json +4 -0
  878. package/blueprints/observability-essentials/contributions/requirements/observability-essentials-req-004.json +4 -0
  879. package/blueprints/observability-essentials/contributions/requirements/observability-essentials-req-005.json +4 -0
  880. package/blueprints/observability-essentials/contributions/requirements/observability-essentials-req-006.json +6 -2
  881. package/blueprints/observability-essentials/contributions/requirements/observability-essentials-req-007.json +7 -3
  882. package/blueprints/observability-essentials/contributions/requirements/observability-essentials-req-008.json +4 -0
  883. package/blueprints/observability-essentials/contributions/requirements/observability-essentials-req-009.json +4 -0
  884. package/blueprints/observability-essentials/contributions/requirements/observability-essentials-req-010.json +4 -0
  885. package/blueprints/observability-essentials/contributions/tacs/tac-802-observability-essentials-readiness-probe.json +6 -1
  886. package/blueprints/observability-essentials/contributions/tacs/tac-803-observability-essentials-status-page.json +1 -1
  887. package/blueprints/observability-essentials/contributions/user-stories/observability-essentials-us-7101.json +25 -7
  888. package/blueprints/observability-essentials/contributions/user-stories/observability-essentials-us-7102.json +9 -5
  889. package/blueprints/observability-essentials/contributions/user-stories/observability-essentials-us-7103.json +51 -6
  890. package/blueprints/observability-essentials/contributions/user-stories/observability-essentials-us-7104.json +7 -4
  891. package/blueprints/observability-essentials/contributions/user-stories/observability-essentials-us-7105.json +6 -3
  892. package/blueprints/observability-essentials/contributions/user-stories/observability-essentials-us-7106.json +37 -6
  893. package/blueprints/observability-essentials/contributions/user-stories/observability-essentials-us-7107.json +18 -11
  894. package/blueprints/observability-essentials/contributions/user-stories/observability-essentials-us-7108.json +6 -3
  895. package/blueprints/observability-essentials/contributions/user-stories/observability-essentials-us-7109.json +7 -4
  896. package/blueprints/observability-essentials/contributions/user-stories/observability-essentials-us-7110.json +8 -5
  897. package/blueprints/observability-essentials/docs/topics.md +3 -4
  898. package/blueprints/observability-essentials/guide/observability-essentials.md +1 -1
  899. package/blueprints/observability-logging/CHANGELOG.md +44 -4
  900. package/blueprints/observability-logging/README.md +2 -2
  901. package/blueprints/observability-logging/blueprint.json +78 -29
  902. package/blueprints/observability-logging/contributions/adrs/adr-1605-observability-logging-serialisation-refusal.json +25 -0
  903. package/blueprints/observability-logging/contributions/probes/correlation-id-flow.mjs +173 -0
  904. package/blueprints/observability-logging/contributions/probes/line-shape-and-fields.mjs +82 -0
  905. package/blueprints/observability-logging/contributions/probes/probe-utils.mjs +47 -0
  906. package/blueprints/observability-logging/contributions/probes/redaction-boundary.mjs +130 -0
  907. package/blueprints/observability-logging/contributions/probes/run-correlation-id-flow.mjs +3 -0
  908. package/blueprints/observability-logging/contributions/probes/run-line-shape-and-fields.mjs +3 -0
  909. package/blueprints/observability-logging/contributions/probes/run-redaction-boundary.mjs +3 -0
  910. package/blueprints/observability-logging/contributions/requirements/observability-logging-req-001.json +10 -3
  911. package/blueprints/observability-logging/contributions/requirements/observability-logging-req-002.json +8 -1
  912. package/blueprints/observability-logging/contributions/requirements/observability-logging-req-003.json +8 -1
  913. package/blueprints/observability-logging/contributions/requirements/observability-logging-req-004.json +8 -1
  914. package/blueprints/observability-logging/contributions/requirements/observability-logging-req-005.json +8 -1
  915. package/blueprints/observability-logging/contributions/requirements/observability-logging-req-006.json +16 -0
  916. package/blueprints/observability-logging/contributions/tacs/tac-1601-observability-logging-logger-factory.json +4 -4
  917. package/blueprints/observability-logging/contributions/user-stories/observability-logging-us-15101.json +62 -8
  918. package/blueprints/observability-logging/contributions/user-stories/observability-logging-us-15102.json +11 -6
  919. package/blueprints/observability-logging/contributions/user-stories/observability-logging-us-15103.json +37 -5
  920. package/blueprints/observability-logging/contributions/user-stories/observability-logging-us-15104.json +35 -4
  921. package/blueprints/observability-logging/contributions/user-stories/observability-logging-us-15105.json +24 -6
  922. package/blueprints/observability-logging/contributions/user-stories/observability-logging-us-15106.json +22 -4
  923. package/blueprints/observability-logging/contributions/user-stories/observability-logging-us-15107.json +34 -3
  924. package/blueprints/observability-logging/contributions/user-stories/observability-logging-us-15108.json +21 -3
  925. package/blueprints/observability-logging/contributions/user-stories/observability-logging-us-15109.json +71 -0
  926. package/blueprints/observability-probe-endpoints/CHANGELOG.md +32 -0
  927. package/blueprints/observability-probe-endpoints/README.md +4 -4
  928. package/blueprints/observability-probe-endpoints/blueprint.json +42 -2
  929. package/blueprints/observability-probe-endpoints/contributions/probes/kubernetes-startup-enabled.mjs +80 -0
  930. package/blueprints/observability-probe-endpoints/contributions/probes/partial-profile-refusal.mjs +101 -0
  931. package/blueprints/observability-probe-endpoints/contributions/probes/probe-utils.mjs +49 -0
  932. package/blueprints/observability-probe-endpoints/contributions/probes/profile-boot-materialisation.mjs +69 -0
  933. package/blueprints/observability-probe-endpoints/contributions/probes/run-kubernetes-startup-enabled.mjs +3 -0
  934. package/blueprints/observability-probe-endpoints/contributions/probes/run-partial-profile-refusal.mjs +3 -0
  935. package/blueprints/observability-probe-endpoints/contributions/probes/run-profile-boot-materialisation.mjs +3 -0
  936. package/blueprints/observability-probe-endpoints/contributions/requirements/observability-probe-endpoints-req-001.json +6 -2
  937. package/blueprints/observability-probe-endpoints/contributions/requirements/observability-probe-endpoints-req-002.json +4 -0
  938. package/blueprints/observability-probe-endpoints/contributions/requirements/observability-probe-endpoints-req-003.json +4 -0
  939. package/blueprints/observability-probe-endpoints/contributions/requirements/observability-probe-endpoints-req-004.json +4 -0
  940. package/blueprints/observability-probe-endpoints/contributions/requirements/observability-probe-endpoints-req-005.json +4 -0
  941. package/blueprints/observability-probe-endpoints/contributions/requirements/observability-probe-endpoints-req-006.json +4 -0
  942. package/blueprints/observability-probe-endpoints/contributions/requirements/observability-probe-endpoints-req-007.json +4 -0
  943. package/blueprints/observability-probe-endpoints/contributions/requirements/observability-probe-endpoints-req-008.json +4 -0
  944. package/blueprints/observability-probe-endpoints/contributions/user-stories/observability-probe-endpoints-us-14101.json +30 -9
  945. package/blueprints/observability-probe-endpoints/contributions/user-stories/observability-probe-endpoints-us-14102.json +24 -6
  946. package/blueprints/observability-probe-endpoints/contributions/user-stories/observability-probe-endpoints-us-14103.json +6 -3
  947. package/blueprints/observability-probe-endpoints/contributions/user-stories/observability-probe-endpoints-us-14104.json +9 -6
  948. package/blueprints/observability-probe-endpoints/contributions/user-stories/observability-probe-endpoints-us-14105.json +49 -4
  949. package/blueprints/observability-probe-endpoints/contributions/user-stories/observability-probe-endpoints-us-14106.json +9 -6
  950. package/blueprints/observability-probe-endpoints/contributions/user-stories/observability-probe-endpoints-us-14107.json +12 -8
  951. package/blueprints/observability-probe-endpoints/contributions/user-stories/observability-probe-endpoints-us-14108.json +6 -3
  952. package/blueprints/observability-probe-endpoints/docs/topics.md +2 -2
  953. package/blueprints/observability-probe-endpoints/guide/observability-probe-endpoints.md +3 -6
  954. package/blueprints/persistence-data-d1/CHANGELOG.md +32 -0
  955. package/blueprints/persistence-data-d1/README.md +3 -3
  956. package/blueprints/persistence-data-d1/assets/batch-usage/batch-atomicity-example.md +2 -0
  957. package/blueprints/persistence-data-d1/assets/facade-shape/facade-module-shape.md +2 -0
  958. package/blueprints/persistence-data-d1/blueprint.json +108 -23
  959. package/blueprints/persistence-data-d1/contributions/adrs/adr-1404-persistence-data-d1-store-boundary.json +4 -4
  960. package/blueprints/persistence-data-d1/contributions/probes/facade-round-trip.mjs +140 -0
  961. package/blueprints/persistence-data-d1/contributions/probes/migrations-forward-only.mjs +66 -0
  962. package/blueprints/persistence-data-d1/contributions/probes/probe-utils.mjs +51 -0
  963. package/blueprints/persistence-data-d1/contributions/probes/real-account-d1-round-trip.mjs +133 -0
  964. package/blueprints/persistence-data-d1/contributions/probes/run-facade-round-trip.mjs +3 -0
  965. package/blueprints/persistence-data-d1/contributions/probes/run-migrations-forward-only.mjs +3 -0
  966. package/blueprints/persistence-data-d1/contributions/probes/run-real-account-d1-round-trip.mjs +3 -0
  967. package/blueprints/persistence-data-d1/contributions/requirements/persistence-data-d1-req-001.json +5 -1
  968. package/blueprints/persistence-data-d1/contributions/requirements/persistence-data-d1-req-002.json +5 -1
  969. package/blueprints/persistence-data-d1/contributions/requirements/persistence-data-d1-req-003.json +5 -1
  970. package/blueprints/persistence-data-d1/contributions/requirements/persistence-data-d1-req-004.json +7 -3
  971. package/blueprints/persistence-data-d1/contributions/requirements/persistence-data-d1-req-005.json +5 -1
  972. package/blueprints/persistence-data-d1/contributions/requirements/persistence-data-d1-req-006.json +5 -1
  973. package/blueprints/persistence-data-d1/contributions/requirements/persistence-data-d1-req-007.json +5 -1
  974. package/blueprints/persistence-data-d1/contributions/user-stories/persistence-data-d1-us-13101.json +35 -4
  975. package/blueprints/persistence-data-d1/contributions/user-stories/persistence-data-d1-us-13102.json +25 -4
  976. package/blueprints/persistence-data-d1/contributions/user-stories/persistence-data-d1-us-13103.json +11 -4
  977. package/blueprints/persistence-data-d1/contributions/user-stories/persistence-data-d1-us-13104.json +13 -6
  978. package/blueprints/persistence-data-d1/contributions/user-stories/persistence-data-d1-us-13105.json +11 -4
  979. package/blueprints/persistence-data-d1/contributions/user-stories/persistence-data-d1-us-13106.json +7 -4
  980. package/blueprints/persistence-data-d1/contributions/user-stories/persistence-data-d1-us-13107.json +23 -3
  981. package/blueprints/persistence-data-d1/docs/topics.md +2 -3
  982. package/blueprints/persistence-data-postgres/CHANGELOG.md +99 -3
  983. package/blueprints/persistence-data-postgres/README.md +2 -2
  984. package/blueprints/persistence-data-postgres/blueprint.json +203 -24
  985. package/blueprints/persistence-data-postgres/contributions/adrs/adr-2801-persistence-data-postgres-driver.json +1 -1
  986. package/blueprints/persistence-data-postgres/contributions/adrs/adr-2805-persistence-data-postgres-connection-pool-posture.json +1 -1
  987. package/blueprints/persistence-data-postgres/contributions/probes/facade-round-trip.mjs +87 -12
  988. package/blueprints/persistence-data-postgres/contributions/probes/migration-apply.mjs +245 -19
  989. package/blueprints/persistence-data-postgres/contributions/probes/pool-posture-smoke.mjs +109 -26
  990. package/blueprints/persistence-data-postgres/contributions/probes/prepared-statement-scan.mjs +151 -38
  991. package/blueprints/persistence-data-postgres/contributions/probes/probe-utils.mjs +24 -6
  992. package/blueprints/persistence-data-postgres/contributions/probes/recovery-restore-round-trip.mjs +261 -48
  993. package/blueprints/persistence-data-postgres/contributions/probes/transaction-atomicity.mjs +76 -20
  994. package/blueprints/persistence-data-postgres/contributions/requirements/persistence-data-postgres-req-001.json +6 -2
  995. package/blueprints/persistence-data-postgres/contributions/requirements/persistence-data-postgres-req-002.json +6 -2
  996. package/blueprints/persistence-data-postgres/contributions/requirements/persistence-data-postgres-req-003.json +6 -2
  997. package/blueprints/persistence-data-postgres/contributions/requirements/persistence-data-postgres-req-004.json +7 -3
  998. package/blueprints/persistence-data-postgres/contributions/requirements/persistence-data-postgres-req-005.json +6 -2
  999. package/blueprints/persistence-data-postgres/contributions/requirements/persistence-data-postgres-req-006.json +6 -2
  1000. package/blueprints/persistence-data-postgres/contributions/requirements/persistence-data-postgres-req-007.json +7 -3
  1001. package/blueprints/persistence-data-postgres/contributions/tacs/tac-2802-persistence-data-postgres-migration-runner.json +2 -2
  1002. package/blueprints/persistence-data-postgres/contributions/tacs/tac-2803-persistence-data-postgres-transaction-helper.json +5 -5
  1003. package/blueprints/persistence-data-postgres/contributions/user-stories/persistence-data-postgres-us-27101.json +22 -4
  1004. package/blueprints/persistence-data-postgres/contributions/user-stories/persistence-data-postgres-us-27102.json +118 -3
  1005. package/blueprints/persistence-data-postgres/contributions/user-stories/persistence-data-postgres-us-27103.json +20 -3
  1006. package/blueprints/persistence-data-postgres/contributions/user-stories/persistence-data-postgres-us-27104.json +26 -5
  1007. package/blueprints/persistence-data-postgres/contributions/user-stories/persistence-data-postgres-us-27105.json +62 -3
  1008. package/blueprints/persistence-data-postgres/contributions/user-stories/persistence-data-postgres-us-27106.json +20 -3
  1009. package/blueprints/persistence-data-postgres/contributions/user-stories/persistence-data-postgres-us-27107.json +20 -3
  1010. package/blueprints/persistence-data-postgres/contributions/user-stories/persistence-data-postgres-us-27108.json +20 -3
  1011. package/blueprints/persistence-data-postgres/contributions/user-stories/persistence-data-postgres-us-27109.json +20 -3
  1012. package/blueprints/persistence-data-postgres/contributions/user-stories/persistence-data-postgres-us-27110.json +48 -3
  1013. package/blueprints/persistence-data-postgres/docs/topics.md +1 -1
  1014. package/blueprints/persistence-data-sqlite/CHANGELOG.md +28 -0
  1015. package/blueprints/persistence-data-sqlite/README.md +2 -2
  1016. package/blueprints/persistence-data-sqlite/blueprint.json +148 -31
  1017. package/blueprints/persistence-data-sqlite/contributions/probes/boot-open-migrate.mjs +90 -0
  1018. package/blueprints/persistence-data-sqlite/contributions/probes/facade-round-trip.mjs +82 -0
  1019. package/blueprints/persistence-data-sqlite/contributions/probes/probe-utils.mjs +83 -0
  1020. package/blueprints/persistence-data-sqlite/contributions/probes/run-boot-open-migrate.mjs +5 -0
  1021. package/blueprints/persistence-data-sqlite/contributions/probes/run-facade-round-trip.mjs +5 -0
  1022. package/blueprints/persistence-data-sqlite/contributions/probes/run-wal-checkpoint.mjs +5 -0
  1023. package/blueprints/persistence-data-sqlite/contributions/probes/wal-checkpoint.mjs +137 -0
  1024. package/blueprints/persistence-data-sqlite/contributions/requirements/persistence-data-sqlite-req-001.json +5 -1
  1025. package/blueprints/persistence-data-sqlite/contributions/requirements/persistence-data-sqlite-req-002.json +5 -1
  1026. package/blueprints/persistence-data-sqlite/contributions/requirements/persistence-data-sqlite-req-003.json +5 -1
  1027. package/blueprints/persistence-data-sqlite/contributions/requirements/persistence-data-sqlite-req-004.json +5 -1
  1028. package/blueprints/persistence-data-sqlite/contributions/requirements/persistence-data-sqlite-req-005.json +5 -1
  1029. package/blueprints/persistence-data-sqlite/contributions/requirements/persistence-data-sqlite-req-006.json +5 -1
  1030. package/blueprints/persistence-data-sqlite/contributions/requirements/persistence-data-sqlite-req-007.json +5 -1
  1031. package/blueprints/persistence-data-sqlite/contributions/requirements/persistence-data-sqlite-req-008.json +5 -1
  1032. package/blueprints/persistence-data-sqlite/contributions/requirements/persistence-data-sqlite-req-009.json +5 -1
  1033. package/blueprints/persistence-data-sqlite/contributions/requirements/persistence-data-sqlite-req-010.json +5 -1
  1034. package/blueprints/persistence-data-sqlite/contributions/requirements/persistence-data-sqlite-req-011.json +5 -1
  1035. package/blueprints/persistence-data-sqlite/contributions/user-stories/persistence-data-sqlite-us-5101.json +35 -4
  1036. package/blueprints/persistence-data-sqlite/contributions/user-stories/persistence-data-sqlite-us-5102.json +7 -4
  1037. package/blueprints/persistence-data-sqlite/contributions/user-stories/persistence-data-sqlite-us-5103.json +19 -3
  1038. package/blueprints/persistence-data-sqlite/contributions/user-stories/persistence-data-sqlite-us-5104.json +21 -4
  1039. package/blueprints/persistence-data-sqlite/contributions/user-stories/persistence-data-sqlite-us-5105.json +7 -4
  1040. package/blueprints/persistence-data-sqlite/contributions/user-stories/persistence-data-sqlite-us-5106.json +11 -4
  1041. package/blueprints/persistence-data-sqlite/contributions/user-stories/persistence-data-sqlite-us-5107.json +7 -4
  1042. package/blueprints/persistence-data-sqlite/contributions/user-stories/persistence-data-sqlite-us-5108.json +7 -4
  1043. package/blueprints/persistence-data-sqlite/contributions/user-stories/persistence-data-sqlite-us-5109.json +11 -8
  1044. package/blueprints/persistence-data-sqlite/contributions/user-stories/persistence-data-sqlite-us-5110.json +23 -3
  1045. package/blueprints/persistence-data-sqlite/contributions/user-stories/persistence-data-sqlite-us-5111.json +19 -3
  1046. package/blueprints/persistence-data-sqlite/docs/topics.md +2 -3
  1047. package/blueprints/persistence-data-sqlite/guide/persistence-data-sqlite.md +1 -1
  1048. package/blueprints/platform-cloudflare-cron-triggers/CHANGELOG.md +40 -2
  1049. package/blueprints/platform-cloudflare-cron-triggers/README.md +2 -3
  1050. package/blueprints/platform-cloudflare-cron-triggers/blueprint.json +78 -17
  1051. package/blueprints/platform-cloudflare-cron-triggers/contributions/adrs/adr-3301-platform-cloudflare-cron-triggers-scheduled-trigger-contract.json +2 -2
  1052. package/blueprints/platform-cloudflare-cron-triggers/contributions/probes/real-account-scheduled-smoke.mjs +24 -3
  1053. package/blueprints/platform-cloudflare-cron-triggers/contributions/probes/skew-tolerance.mjs +1 -1
  1054. package/blueprints/platform-cloudflare-cron-triggers/contributions/requirements/platform-cloudflare-cron-triggers-req-001.json +6 -2
  1055. package/blueprints/platform-cloudflare-cron-triggers/contributions/requirements/platform-cloudflare-cron-triggers-req-002.json +5 -1
  1056. package/blueprints/platform-cloudflare-cron-triggers/contributions/requirements/platform-cloudflare-cron-triggers-req-003.json +5 -1
  1057. package/blueprints/platform-cloudflare-cron-triggers/contributions/requirements/platform-cloudflare-cron-triggers-req-004.json +6 -2
  1058. package/blueprints/platform-cloudflare-cron-triggers/contributions/tacs/tac-3301-platform-cloudflare-cron-triggers-scheduled-handler.json +1 -1
  1059. package/blueprints/platform-cloudflare-cron-triggers/contributions/user-stories/platform-cloudflare-cron-triggers-us-32101.json +86 -5
  1060. package/blueprints/platform-cloudflare-cron-triggers/contributions/user-stories/platform-cloudflare-cron-triggers-us-32102.json +69 -5
  1061. package/blueprints/platform-cloudflare-cron-triggers/contributions/user-stories/platform-cloudflare-cron-triggers-us-32103.json +51 -4
  1062. package/blueprints/platform-cloudflare-cron-triggers/contributions/user-stories/platform-cloudflare-cron-triggers-us-32104.json +65 -4
  1063. package/blueprints/platform-cloudflare-cron-triggers/contributions/user-stories/platform-cloudflare-cron-triggers-us-32105.json +68 -5
  1064. package/blueprints/platform-cloudflare-cron-triggers/contributions/user-stories/platform-cloudflare-cron-triggers-us-32106.json +62 -3
  1065. package/blueprints/platform-cloudflare-cron-triggers/contributions/user-stories/platform-cloudflare-cron-triggers-us-32107.json +56 -3
  1066. package/blueprints/platform-cloudflare-cron-triggers/docs/topics.md +4 -4
  1067. package/blueprints/platform-cloudflare-durable-objects/CHANGELOG.md +40 -4
  1068. package/blueprints/platform-cloudflare-durable-objects/README.md +6 -6
  1069. package/blueprints/platform-cloudflare-durable-objects/blueprint.json +3 -2
  1070. package/blueprints/platform-cloudflare-durable-objects/contributions/adrs/adr-3401-platform-cloudflare-durable-objects-single-cell-contract.json +1 -1
  1071. package/blueprints/platform-cloudflare-durable-objects/contributions/adrs/adr-3402-platform-cloudflare-durable-objects-websocket-hub-contract.json +1 -1
  1072. package/blueprints/platform-cloudflare-durable-objects/contributions/probes/probe-utils.mjs +2 -2
  1073. package/blueprints/platform-cloudflare-durable-objects/contributions/probes/real-account-storage-smoke.mjs +41 -35
  1074. package/blueprints/platform-cloudflare-durable-objects/contributions/probes/sole-reader-scan.mjs +1 -1
  1075. package/blueprints/platform-cloudflare-durable-objects/contributions/probes/storage-round-trip.mjs +1 -1
  1076. package/blueprints/platform-cloudflare-durable-objects/contributions/probes/websocket-hub-broadcast.mjs +1 -1
  1077. package/blueprints/platform-cloudflare-durable-objects/contributions/probes/wrangler-seam.mjs +11 -5
  1078. package/blueprints/platform-cloudflare-durable-objects/contributions/requirements/platform-cloudflare-durable-objects-req-001.json +5 -1
  1079. package/blueprints/platform-cloudflare-durable-objects/contributions/requirements/platform-cloudflare-durable-objects-req-002.json +6 -2
  1080. package/blueprints/platform-cloudflare-durable-objects/contributions/requirements/platform-cloudflare-durable-objects-req-003.json +5 -1
  1081. package/blueprints/platform-cloudflare-durable-objects/contributions/requirements/platform-cloudflare-durable-objects-req-004.json +5 -1
  1082. package/blueprints/platform-cloudflare-durable-objects/contributions/requirements/platform-cloudflare-durable-objects-req-005.json +6 -2
  1083. package/blueprints/platform-cloudflare-durable-objects/contributions/requirements/platform-cloudflare-durable-objects-req-006.json +6 -2
  1084. package/blueprints/platform-cloudflare-durable-objects/contributions/requirements/platform-cloudflare-durable-objects-req-007.json +5 -1
  1085. package/blueprints/platform-cloudflare-durable-objects/contributions/requirements/platform-cloudflare-durable-objects-req-008.json +5 -1
  1086. package/blueprints/platform-cloudflare-durable-objects/contributions/user-stories/platform-cloudflare-durable-objects-us-33101.json +73 -2
  1087. package/blueprints/platform-cloudflare-durable-objects/contributions/user-stories/platform-cloudflare-durable-objects-us-33102.json +59 -2
  1088. package/blueprints/platform-cloudflare-durable-objects/contributions/user-stories/platform-cloudflare-durable-objects-us-33103.json +77 -2
  1089. package/blueprints/platform-cloudflare-durable-objects/contributions/user-stories/platform-cloudflare-durable-objects-us-33104.json +75 -6
  1090. package/blueprints/platform-cloudflare-durable-objects/contributions/user-stories/platform-cloudflare-durable-objects-us-33105.json +73 -2
  1091. package/blueprints/platform-cloudflare-durable-objects/contributions/user-stories/platform-cloudflare-durable-objects-us-33106.json +49 -2
  1092. package/blueprints/platform-cloudflare-durable-objects/contributions/user-stories/platform-cloudflare-durable-objects-us-33107.json +45 -2
  1093. package/blueprints/platform-cloudflare-durable-objects/contributions/user-stories/platform-cloudflare-durable-objects-us-33108.json +84 -3
  1094. package/blueprints/platform-cloudflare-durable-objects/contributions/user-stories/platform-cloudflare-durable-objects-us-33109.json +45 -2
  1095. package/blueprints/platform-cloudflare-durable-objects/contributions/user-stories/platform-cloudflare-durable-objects-us-33110.json +59 -2
  1096. package/blueprints/platform-cloudflare-durable-objects/contributions/user-stories/platform-cloudflare-durable-objects-us-33111.json +45 -2
  1097. package/blueprints/platform-cloudflare-durable-objects/contributions/user-stories/platform-cloudflare-durable-objects-us-33112.json +53 -2
  1098. package/blueprints/platform-cloudflare-durable-objects/contributions/user-stories/platform-cloudflare-durable-objects-us-33113.json +68 -5
  1099. package/blueprints/platform-cloudflare-durable-objects/docs/topics.md +2 -2
  1100. package/blueprints/platform-cloudflare-durable-objects/guide/platform-cloudflare-durable-objects.md +9 -9
  1101. package/blueprints/platform-cloudflare-kv/CHANGELOG.md +58 -12
  1102. package/blueprints/platform-cloudflare-kv/README.md +7 -11
  1103. package/blueprints/platform-cloudflare-kv/blueprint.json +115 -20
  1104. package/blueprints/platform-cloudflare-kv/contributions/adrs/adr-3201-platform-cloudflare-kv-key-value-store-contract.json +3 -3
  1105. package/blueprints/platform-cloudflare-kv/contributions/probes/cache-aside-hit-then-miss.mjs +1 -1
  1106. package/blueprints/platform-cloudflare-kv/contributions/probes/event-secrecy.mjs +1 -1
  1107. package/blueprints/platform-cloudflare-kv/contributions/probes/real-account-eventual-consistency-smoke.mjs +53 -18
  1108. package/blueprints/platform-cloudflare-kv/contributions/requirements/platform-cloudflare-kv-req-001.json +6 -2
  1109. package/blueprints/platform-cloudflare-kv/contributions/requirements/platform-cloudflare-kv-req-002.json +5 -1
  1110. package/blueprints/platform-cloudflare-kv/contributions/requirements/platform-cloudflare-kv-req-003.json +5 -1
  1111. package/blueprints/platform-cloudflare-kv/contributions/requirements/platform-cloudflare-kv-req-004.json +6 -2
  1112. package/blueprints/platform-cloudflare-kv/contributions/requirements/platform-cloudflare-kv-req-005.json +7 -3
  1113. package/blueprints/platform-cloudflare-kv/contributions/requirements/platform-cloudflare-kv-req-006.json +22 -0
  1114. package/blueprints/platform-cloudflare-kv/contributions/requirements/platform-cloudflare-kv-req-007.json +22 -0
  1115. package/blueprints/platform-cloudflare-kv/contributions/user-stories/platform-cloudflare-kv-us-31101.json +59 -2
  1116. package/blueprints/platform-cloudflare-kv/contributions/user-stories/platform-cloudflare-kv-us-31102.json +45 -2
  1117. package/blueprints/platform-cloudflare-kv/contributions/user-stories/platform-cloudflare-kv-us-31103.json +73 -3
  1118. package/blueprints/platform-cloudflare-kv/contributions/user-stories/platform-cloudflare-kv-us-31104.json +67 -2
  1119. package/blueprints/platform-cloudflare-kv/contributions/user-stories/platform-cloudflare-kv-us-31105.json +59 -2
  1120. package/blueprints/platform-cloudflare-kv/contributions/user-stories/platform-cloudflare-kv-us-31106.json +45 -2
  1121. package/blueprints/platform-cloudflare-kv/contributions/user-stories/platform-cloudflare-kv-us-31107.json +45 -2
  1122. package/blueprints/platform-cloudflare-kv/contributions/user-stories/platform-cloudflare-kv-us-31108.json +45 -2
  1123. package/blueprints/platform-cloudflare-kv/contributions/user-stories/platform-cloudflare-kv-us-31109.json +92 -0
  1124. package/blueprints/platform-cloudflare-kv/contributions/user-stories/platform-cloudflare-kv-us-31110.json +88 -0
  1125. package/blueprints/platform-cloudflare-kv/contributions/user-stories/platform-cloudflare-kv-us-31111.json +89 -0
  1126. package/blueprints/platform-cloudflare-kv/docs/topics.md +2 -2
  1127. package/blueprints/platform-cloudflare-kv/guide/platform-cloudflare-kv.md +2 -2
  1128. package/blueprints/platform-docker-compose-host/CHANGELOG.md +124 -3
  1129. package/blueprints/platform-docker-compose-host/README.md +7 -7
  1130. package/blueprints/platform-docker-compose-host/blueprint.json +23 -6
  1131. package/blueprints/platform-docker-compose-host/contributions/adrs/adr-3901-platform-docker-compose-host-contract.json +3 -3
  1132. package/blueprints/platform-docker-compose-host/contributions/adrs/adr-3902-platform-docker-compose-host-reverse-proxy.json +4 -4
  1133. package/blueprints/platform-docker-compose-host/contributions/adrs/adr-3903-platform-docker-compose-host-reject-coolify.json +2 -2
  1134. package/blueprints/platform-docker-compose-host/contributions/adrs/adr-3904-platform-docker-compose-host-log-driver.json +2 -2
  1135. package/blueprints/platform-docker-compose-host/contributions/probes/caddyfile-validate.mjs +116 -29
  1136. package/blueprints/platform-docker-compose-host/contributions/probes/compose-config-lint.mjs +181 -109
  1137. package/blueprints/platform-docker-compose-host/contributions/probes/probe-utils.mjs +146 -26
  1138. package/blueprints/platform-docker-compose-host/contributions/probes/real-account-minimal-stack-up.mjs +238 -25
  1139. package/blueprints/platform-docker-compose-host/contributions/probes/real-account-reload-burst.mjs +207 -21
  1140. package/blueprints/platform-docker-compose-host/contributions/probes/secrets-as-files-scan.mjs +246 -42
  1141. package/blueprints/platform-docker-compose-host/contributions/requirements/platform-docker-compose-host-req-001.json +6 -2
  1142. package/blueprints/platform-docker-compose-host/contributions/requirements/platform-docker-compose-host-req-002.json +5 -1
  1143. package/blueprints/platform-docker-compose-host/contributions/requirements/platform-docker-compose-host-req-003.json +6 -2
  1144. package/blueprints/platform-docker-compose-host/contributions/requirements/platform-docker-compose-host-req-004.json +5 -1
  1145. package/blueprints/platform-docker-compose-host/contributions/requirements/platform-docker-compose-host-req-005.json +6 -2
  1146. package/blueprints/platform-docker-compose-host/contributions/requirements/platform-docker-compose-host-req-006.json +6 -2
  1147. package/blueprints/platform-docker-compose-host/contributions/requirements/platform-docker-compose-host-req-007.json +22 -0
  1148. package/blueprints/platform-docker-compose-host/contributions/user-stories/platform-docker-compose-host-us-38101.json +73 -2
  1149. package/blueprints/platform-docker-compose-host/contributions/user-stories/platform-docker-compose-host-us-38102.json +67 -2
  1150. package/blueprints/platform-docker-compose-host/contributions/user-stories/platform-docker-compose-host-us-38103.json +59 -2
  1151. package/blueprints/platform-docker-compose-host/contributions/user-stories/platform-docker-compose-host-us-38104.json +75 -2
  1152. package/blueprints/platform-docker-compose-host/contributions/user-stories/platform-docker-compose-host-us-38105.json +49 -2
  1153. package/blueprints/platform-docker-compose-host/contributions/user-stories/platform-docker-compose-host-us-38106.json +45 -2
  1154. package/blueprints/platform-docker-compose-host/contributions/user-stories/platform-docker-compose-host-us-38107.json +49 -2
  1155. package/blueprints/platform-docker-compose-host/contributions/user-stories/platform-docker-compose-host-us-38108.json +49 -2
  1156. package/blueprints/platform-docker-compose-host/contributions/user-stories/platform-docker-compose-host-us-38109.json +57 -2
  1157. package/blueprints/platform-docker-compose-host/contributions/user-stories/platform-docker-compose-host-us-38110.json +92 -0
  1158. package/blueprints/platform-docker-compose-host/docs/topics.md +4 -4
  1159. package/blueprints/platform-docker-compose-host/guide/platform-docker-compose-host.md +6 -6
  1160. package/blueprints/security-auth-clerk/CHANGELOG.md +36 -4
  1161. package/blueprints/security-auth-clerk/README.md +4 -4
  1162. package/blueprints/security-auth-clerk/assets/wiring/workers-wrangler-toml-shape.md +1 -1
  1163. package/blueprints/security-auth-clerk/blueprint.json +23 -2
  1164. package/blueprints/security-auth-clerk/contributions/probes/hosted-identity-ui-config.mjs +61 -0
  1165. package/blueprints/security-auth-clerk/contributions/probes/probe-utils.mjs +188 -0
  1166. package/blueprints/security-auth-clerk/contributions/probes/real-account-principal-directory-round-trip.mjs +216 -0
  1167. package/blueprints/security-auth-clerk/contributions/probes/real-account-session-inventory.mjs +260 -0
  1168. package/blueprints/security-auth-clerk/contributions/probes/role-model-adapter.mjs +53 -0
  1169. package/blueprints/security-auth-clerk/contributions/probes/run-hosted-identity-ui-config.mjs +4 -0
  1170. package/blueprints/security-auth-clerk/contributions/probes/run-real-account-principal-directory-round-trip.mjs +4 -0
  1171. package/blueprints/security-auth-clerk/contributions/probes/run-real-account-session-inventory.mjs +4 -0
  1172. package/blueprints/security-auth-clerk/contributions/probes/run-role-model-adapter.mjs +4 -0
  1173. package/blueprints/security-auth-clerk/contributions/requirements/security-auth-clerk-req-001.json +6 -2
  1174. package/blueprints/security-auth-clerk/contributions/requirements/security-auth-clerk-req-002.json +5 -1
  1175. package/blueprints/security-auth-clerk/contributions/requirements/security-auth-clerk-req-003.json +6 -2
  1176. package/blueprints/security-auth-clerk/contributions/requirements/security-auth-clerk-req-004.json +6 -2
  1177. package/blueprints/security-auth-clerk/contributions/requirements/security-auth-clerk-req-005.json +5 -2
  1178. package/blueprints/security-auth-clerk/contributions/requirements/security-auth-clerk-req-006.json +5 -1
  1179. package/blueprints/security-auth-clerk/contributions/requirements/security-auth-clerk-req-007.json +4 -1
  1180. package/blueprints/security-auth-clerk/contributions/requirements/security-auth-clerk-req-008.json +4 -1
  1181. package/blueprints/security-auth-clerk/contributions/requirements/security-auth-clerk-req-009.json +4 -1
  1182. package/blueprints/security-auth-clerk/contributions/requirements/security-auth-clerk-req-010.json +22 -0
  1183. package/blueprints/security-auth-clerk/contributions/requirements/security-auth-clerk-req-011.json +22 -0
  1184. package/blueprints/security-auth-clerk/contributions/tacs/tac-1001-security-auth-clerk-middleware.json +14 -4
  1185. package/blueprints/security-auth-clerk/contributions/tacs/tac-1003-security-auth-clerk-session-verifier.json +7 -1
  1186. package/blueprints/security-auth-clerk/contributions/user-stories/security-auth-clerk-us-9101.json +6 -3
  1187. package/blueprints/security-auth-clerk/contributions/user-stories/security-auth-clerk-us-9102.json +19 -3
  1188. package/blueprints/security-auth-clerk/contributions/user-stories/security-auth-clerk-us-9103.json +6 -3
  1189. package/blueprints/security-auth-clerk/contributions/user-stories/security-auth-clerk-us-9104.json +6 -3
  1190. package/blueprints/security-auth-clerk/contributions/user-stories/security-auth-clerk-us-9105.json +4 -2
  1191. package/blueprints/security-auth-clerk/contributions/user-stories/security-auth-clerk-us-9106.json +4 -2
  1192. package/blueprints/security-auth-clerk/contributions/user-stories/security-auth-clerk-us-9107.json +4 -2
  1193. package/blueprints/security-auth-clerk/contributions/user-stories/security-auth-clerk-us-9108.json +13 -3
  1194. package/blueprints/security-auth-clerk/contributions/user-stories/security-auth-clerk-us-9109.json +8 -2
  1195. package/blueprints/security-auth-clerk/contributions/user-stories/security-auth-clerk-us-9110.json +4 -2
  1196. package/blueprints/security-auth-clerk/contributions/user-stories/security-auth-clerk-us-9111.json +4 -2
  1197. package/blueprints/security-auth-clerk/contributions/user-stories/security-auth-clerk-us-9112.json +102 -0
  1198. package/blueprints/security-auth-clerk/contributions/user-stories/security-auth-clerk-us-9113.json +103 -0
  1199. package/blueprints/security-auth-clerk/docs/topics.md +2 -3
  1200. package/blueprints/security-auth-keycloak/CHANGELOG.md +34 -4
  1201. package/blueprints/security-auth-keycloak/README.md +3 -3
  1202. package/blueprints/security-auth-keycloak/blueprint.json +103 -2
  1203. package/blueprints/security-auth-keycloak/contributions/probes/discovery-shape.mjs +68 -0
  1204. package/blueprints/security-auth-keycloak/contributions/probes/introspection-shape.mjs +88 -0
  1205. package/blueprints/security-auth-keycloak/contributions/probes/jwt-verifier-shape.mjs +86 -0
  1206. package/blueprints/security-auth-keycloak/contributions/probes/probe-utils.mjs +180 -0
  1207. package/blueprints/security-auth-keycloak/contributions/probes/real-account-realm-round-trip.mjs +91 -0
  1208. package/blueprints/security-auth-keycloak/contributions/probes/role-adapter-shape.mjs +69 -0
  1209. package/blueprints/security-auth-keycloak/contributions/probes/run-discovery-shape.mjs +4 -0
  1210. package/blueprints/security-auth-keycloak/contributions/probes/run-introspection-shape.mjs +4 -0
  1211. package/blueprints/security-auth-keycloak/contributions/probes/run-jwt-verifier-shape.mjs +4 -0
  1212. package/blueprints/security-auth-keycloak/contributions/probes/run-real-account-realm-round-trip.mjs +4 -0
  1213. package/blueprints/security-auth-keycloak/contributions/probes/run-role-adapter-shape.mjs +4 -0
  1214. package/blueprints/security-auth-keycloak/contributions/requirements/security-auth-keycloak-req-001.json +5 -2
  1215. package/blueprints/security-auth-keycloak/contributions/requirements/security-auth-keycloak-req-002.json +5 -1
  1216. package/blueprints/security-auth-keycloak/contributions/requirements/security-auth-keycloak-req-003.json +5 -1
  1217. package/blueprints/security-auth-keycloak/contributions/requirements/security-auth-keycloak-req-004.json +5 -1
  1218. package/blueprints/security-auth-keycloak/contributions/requirements/security-auth-keycloak-req-005.json +6 -2
  1219. package/blueprints/security-auth-keycloak/contributions/requirements/security-auth-keycloak-req-006.json +6 -2
  1220. package/blueprints/security-auth-keycloak/contributions/requirements/security-auth-keycloak-req-007.json +4 -1
  1221. package/blueprints/security-auth-keycloak/contributions/requirements/security-auth-keycloak-req-008.json +4 -1
  1222. package/blueprints/security-auth-keycloak/contributions/requirements/security-auth-keycloak-req-009.json +4 -1
  1223. package/blueprints/security-auth-keycloak/contributions/requirements/security-auth-keycloak-req-010.json +4 -1
  1224. package/blueprints/security-auth-keycloak/contributions/requirements/security-auth-keycloak-req-011.json +5 -1
  1225. package/blueprints/security-auth-keycloak/contributions/requirements/security-auth-keycloak-req-012.json +4 -1
  1226. package/blueprints/security-auth-keycloak/contributions/requirements/security-auth-keycloak-req-013.json +22 -0
  1227. package/blueprints/security-auth-keycloak/contributions/requirements/security-auth-keycloak-req-014.json +22 -0
  1228. package/blueprints/security-auth-keycloak/contributions/requirements/security-auth-keycloak-req-015.json +22 -0
  1229. package/blueprints/security-auth-keycloak/contributions/requirements/security-auth-keycloak-req-016.json +22 -0
  1230. package/blueprints/security-auth-keycloak/contributions/requirements/security-auth-keycloak-req-017.json +22 -0
  1231. package/blueprints/security-auth-keycloak/contributions/requirements/security-auth-keycloak-req-018.json +22 -0
  1232. package/blueprints/security-auth-keycloak/contributions/requirements/security-auth-keycloak-req-019.json +22 -0
  1233. package/blueprints/security-auth-keycloak/contributions/tacs/tac-1201-security-auth-keycloak-discovery-client.json +4 -2
  1234. package/blueprints/security-auth-keycloak/contributions/tacs/tac-1202-security-auth-keycloak-jwt-verifier.json +8 -2
  1235. package/blueprints/security-auth-keycloak/contributions/tacs/tac-1203-security-auth-keycloak-introspection-client.json +8 -2
  1236. package/blueprints/security-auth-keycloak/contributions/tacs/tac-1204-security-auth-keycloak-provider-router.json +3 -1
  1237. package/blueprints/security-auth-keycloak/contributions/tacs/tac-1205-security-auth-keycloak-role-adapter.json +2 -1
  1238. package/blueprints/security-auth-keycloak/contributions/user-stories/security-auth-keycloak-us-11101.json +6 -3
  1239. package/blueprints/security-auth-keycloak/contributions/user-stories/security-auth-keycloak-us-11102.json +10 -3
  1240. package/blueprints/security-auth-keycloak/contributions/user-stories/security-auth-keycloak-us-11103.json +12 -2
  1241. package/blueprints/security-auth-keycloak/contributions/user-stories/security-auth-keycloak-us-11104.json +8 -2
  1242. package/blueprints/security-auth-keycloak/contributions/user-stories/security-auth-keycloak-us-11105.json +6 -3
  1243. package/blueprints/security-auth-keycloak/contributions/user-stories/security-auth-keycloak-us-11106.json +18 -3
  1244. package/blueprints/security-auth-keycloak/contributions/user-stories/security-auth-keycloak-us-11107.json +6 -3
  1245. package/blueprints/security-auth-keycloak/contributions/user-stories/security-auth-keycloak-us-11108.json +6 -3
  1246. package/blueprints/security-auth-keycloak/contributions/user-stories/security-auth-keycloak-us-11109.json +4 -2
  1247. package/blueprints/security-auth-keycloak/contributions/user-stories/security-auth-keycloak-us-11110.json +6 -3
  1248. package/blueprints/security-auth-keycloak/contributions/user-stories/security-auth-keycloak-us-11111.json +14 -3
  1249. package/blueprints/security-auth-keycloak/contributions/user-stories/security-auth-keycloak-us-11112.json +4 -2
  1250. package/blueprints/security-auth-keycloak/contributions/user-stories/security-auth-keycloak-us-11113.json +4 -2
  1251. package/blueprints/security-auth-keycloak/contributions/user-stories/security-auth-keycloak-us-11114.json +72 -0
  1252. package/blueprints/security-auth-keycloak/contributions/user-stories/security-auth-keycloak-us-11115.json +88 -0
  1253. package/blueprints/security-auth-keycloak/contributions/user-stories/security-auth-keycloak-us-11116.json +117 -0
  1254. package/blueprints/security-auth-keycloak/contributions/user-stories/security-auth-keycloak-us-11117.json +117 -0
  1255. package/blueprints/security-auth-keycloak/contributions/user-stories/security-auth-keycloak-us-11118.json +117 -0
  1256. package/blueprints/security-auth-keycloak/contributions/user-stories/security-auth-keycloak-us-11119.json +117 -0
  1257. package/blueprints/security-auth-keycloak/contributions/user-stories/security-auth-keycloak-us-11120.json +103 -0
  1258. package/blueprints/security-auth-keycloak/docs/topics.md +1 -2
  1259. package/blueprints/security-auth-keycloak/guide/security-auth-keycloak.md +1 -1
  1260. package/blueprints/security-auth-magic-link/CHANGELOG.md +30 -3
  1261. package/blueprints/security-auth-magic-link/README.md +3 -3
  1262. package/blueprints/security-auth-magic-link/assets/principal-registry-samples/single-address.md +1 -1
  1263. package/blueprints/security-auth-magic-link/blueprint.json +3 -2
  1264. package/blueprints/security-auth-magic-link/contributions/probes/probe-utils.mjs +174 -0
  1265. package/blueprints/security-auth-magic-link/contributions/probes/real-account-magic-link-send.mjs +139 -0
  1266. package/blueprints/security-auth-magic-link/contributions/probes/run-real-account-magic-link-send.mjs +4 -0
  1267. package/blueprints/security-auth-magic-link/contributions/probes/run-token-entropy-shape.mjs +4 -0
  1268. package/blueprints/security-auth-magic-link/contributions/probes/run-token-issue-verify.mjs +4 -0
  1269. package/blueprints/security-auth-magic-link/contributions/probes/token-entropy-shape.mjs +60 -0
  1270. package/blueprints/security-auth-magic-link/contributions/probes/token-issue-verify.mjs +90 -0
  1271. package/blueprints/security-auth-magic-link/contributions/requirements/security-auth-magic-link-req-001.json +4 -1
  1272. package/blueprints/security-auth-magic-link/contributions/requirements/security-auth-magic-link-req-002.json +5 -1
  1273. package/blueprints/security-auth-magic-link/contributions/requirements/security-auth-magic-link-req-003.json +6 -2
  1274. package/blueprints/security-auth-magic-link/contributions/requirements/security-auth-magic-link-req-004.json +5 -1
  1275. package/blueprints/security-auth-magic-link/contributions/requirements/security-auth-magic-link-req-005.json +5 -1
  1276. package/blueprints/security-auth-magic-link/contributions/requirements/security-auth-magic-link-req-006.json +4 -1
  1277. package/blueprints/security-auth-magic-link/contributions/requirements/security-auth-magic-link-req-007.json +4 -1
  1278. package/blueprints/security-auth-magic-link/contributions/requirements/security-auth-magic-link-req-008.json +5 -1
  1279. package/blueprints/security-auth-magic-link/contributions/requirements/security-auth-magic-link-req-009.json +5 -1
  1280. package/blueprints/security-auth-magic-link/contributions/requirements/security-auth-magic-link-req-010.json +6 -2
  1281. package/blueprints/security-auth-magic-link/contributions/requirements/security-auth-magic-link-req-011.json +6 -2
  1282. package/blueprints/security-auth-magic-link/contributions/user-stories/security-auth-magic-link-us-3101.json +10 -5
  1283. package/blueprints/security-auth-magic-link/contributions/user-stories/security-auth-magic-link-us-3102.json +8 -4
  1284. package/blueprints/security-auth-magic-link/contributions/user-stories/security-auth-magic-link-us-3103.json +6 -3
  1285. package/blueprints/security-auth-magic-link/contributions/user-stories/security-auth-magic-link-us-3104.json +8 -4
  1286. package/blueprints/security-auth-magic-link/contributions/user-stories/security-auth-magic-link-us-3105.json +6 -3
  1287. package/blueprints/security-auth-magic-link/contributions/user-stories/security-auth-magic-link-us-3106.json +6 -3
  1288. package/blueprints/security-auth-magic-link/contributions/user-stories/security-auth-magic-link-us-3107.json +8 -4
  1289. package/blueprints/security-auth-magic-link/contributions/user-stories/security-auth-magic-link-us-3108.json +6 -3
  1290. package/blueprints/security-auth-magic-link/contributions/user-stories/security-auth-magic-link-us-3109.json +6 -3
  1291. package/blueprints/security-auth-magic-link/contributions/user-stories/security-auth-magic-link-us-3110.json +6 -3
  1292. package/blueprints/security-auth-magic-link/contributions/user-stories/security-auth-magic-link-us-3111.json +14 -3
  1293. package/blueprints/security-auth-magic-link/docs/topics.md +1 -1
  1294. package/blueprints/security-auth-magic-link/guide/security-auth-magic-link.md +1 -1
  1295. package/blueprints/security-auth-oauth2/CHANGELOG.md +32 -4
  1296. package/blueprints/security-auth-oauth2/README.md +3 -3
  1297. package/blueprints/security-auth-oauth2/blueprint.json +35 -3
  1298. package/blueprints/security-auth-oauth2/contributions/probes/authorisation-code-flow-shape.mjs +259 -0
  1299. package/blueprints/security-auth-oauth2/contributions/probes/pkce-challenge-shape.mjs +58 -0
  1300. package/blueprints/security-auth-oauth2/contributions/probes/probe-utils.mjs +190 -0
  1301. package/blueprints/security-auth-oauth2/contributions/probes/provider-adapter-shape.mjs +64 -0
  1302. package/blueprints/security-auth-oauth2/contributions/probes/real-account-authorisation-code-flow.mjs +93 -0
  1303. package/blueprints/security-auth-oauth2/contributions/probes/run-authorisation-code-flow-shape.mjs +4 -0
  1304. package/blueprints/security-auth-oauth2/contributions/probes/run-pkce-challenge-shape.mjs +4 -0
  1305. package/blueprints/security-auth-oauth2/contributions/probes/run-provider-adapter-shape.mjs +4 -0
  1306. package/blueprints/security-auth-oauth2/contributions/probes/run-real-account-authorisation-code-flow.mjs +4 -0
  1307. package/blueprints/security-auth-oauth2/contributions/probes/run-session-bridge-shape.mjs +4 -0
  1308. package/blueprints/security-auth-oauth2/contributions/probes/session-bridge-shape.mjs +78 -0
  1309. package/blueprints/security-auth-oauth2/contributions/requirements/security-auth-oauth2-req-001.json +5 -2
  1310. package/blueprints/security-auth-oauth2/contributions/requirements/security-auth-oauth2-req-002.json +5 -1
  1311. package/blueprints/security-auth-oauth2/contributions/requirements/security-auth-oauth2-req-003.json +5 -1
  1312. package/blueprints/security-auth-oauth2/contributions/requirements/security-auth-oauth2-req-004.json +4 -1
  1313. package/blueprints/security-auth-oauth2/contributions/requirements/security-auth-oauth2-req-005.json +5 -1
  1314. package/blueprints/security-auth-oauth2/contributions/requirements/security-auth-oauth2-req-006.json +6 -2
  1315. package/blueprints/security-auth-oauth2/contributions/requirements/security-auth-oauth2-req-007.json +4 -1
  1316. package/blueprints/security-auth-oauth2/contributions/requirements/security-auth-oauth2-req-008.json +6 -2
  1317. package/blueprints/security-auth-oauth2/contributions/requirements/security-auth-oauth2-req-009.json +5 -1
  1318. package/blueprints/security-auth-oauth2/contributions/requirements/security-auth-oauth2-req-010.json +4 -1
  1319. package/blueprints/security-auth-oauth2/contributions/requirements/security-auth-oauth2-req-011.json +22 -0
  1320. package/blueprints/security-auth-oauth2/contributions/requirements/security-auth-oauth2-req-012.json +22 -0
  1321. package/blueprints/security-auth-oauth2/contributions/requirements/security-auth-oauth2-req-013.json +22 -0
  1322. package/blueprints/security-auth-oauth2/contributions/tacs/tac-1102-security-auth-oauth2-provider-adapter.json +2 -1
  1323. package/blueprints/security-auth-oauth2/contributions/tacs/tac-1103-security-auth-oauth2-session-bridge.json +9 -2
  1324. package/blueprints/security-auth-oauth2/contributions/user-stories/security-auth-oauth2-us-10101.json +6 -3
  1325. package/blueprints/security-auth-oauth2/contributions/user-stories/security-auth-oauth2-us-10102.json +6 -3
  1326. package/blueprints/security-auth-oauth2/contributions/user-stories/security-auth-oauth2-us-10103.json +4 -2
  1327. package/blueprints/security-auth-oauth2/contributions/user-stories/security-auth-oauth2-us-10104.json +4 -2
  1328. package/blueprints/security-auth-oauth2/contributions/user-stories/security-auth-oauth2-us-10105.json +8 -4
  1329. package/blueprints/security-auth-oauth2/contributions/user-stories/security-auth-oauth2-us-10106.json +6 -3
  1330. package/blueprints/security-auth-oauth2/contributions/user-stories/security-auth-oauth2-us-10107.json +6 -3
  1331. package/blueprints/security-auth-oauth2/contributions/user-stories/security-auth-oauth2-us-10108.json +6 -3
  1332. package/blueprints/security-auth-oauth2/contributions/user-stories/security-auth-oauth2-us-10109.json +4 -2
  1333. package/blueprints/security-auth-oauth2/contributions/user-stories/security-auth-oauth2-us-10110.json +4 -2
  1334. package/blueprints/security-auth-oauth2/contributions/user-stories/security-auth-oauth2-us-10111.json +17 -2
  1335. package/blueprints/security-auth-oauth2/contributions/user-stories/security-auth-oauth2-us-10112.json +82 -0
  1336. package/blueprints/security-auth-oauth2/contributions/user-stories/security-auth-oauth2-us-10113.json +68 -0
  1337. package/blueprints/security-auth-oauth2/contributions/user-stories/security-auth-oauth2-us-10114.json +88 -0
  1338. package/blueprints/security-auth-oauth2/docs/topics.md +1 -2
  1339. package/blueprints/security-secrets-management/CHANGELOG.md +26 -3
  1340. package/blueprints/security-secrets-management/README.md +2 -2
  1341. package/blueprints/security-secrets-management/blueprint.json +170 -32
  1342. package/blueprints/security-secrets-management/contributions/probes/add-recipient-rotation.mjs +107 -0
  1343. package/blueprints/security-secrets-management/contributions/probes/encrypt-decrypt-round-trip.mjs +122 -0
  1344. package/blueprints/security-secrets-management/contributions/probes/key-rotation.mjs +93 -0
  1345. package/blueprints/security-secrets-management/contributions/probes/mismatched-key-refusal.mjs +74 -0
  1346. package/blueprints/security-secrets-management/contributions/probes/probe-utils.mjs +214 -0
  1347. package/blueprints/security-secrets-management/contributions/probes/run-add-recipient-rotation.mjs +4 -0
  1348. package/blueprints/security-secrets-management/contributions/probes/run-encrypt-decrypt-round-trip.mjs +4 -0
  1349. package/blueprints/security-secrets-management/contributions/probes/run-key-rotation.mjs +4 -0
  1350. package/blueprints/security-secrets-management/contributions/probes/run-mismatched-key-refusal.mjs +4 -0
  1351. package/blueprints/security-secrets-management/contributions/requirements/security-secrets-management-req-001.json +5 -1
  1352. package/blueprints/security-secrets-management/contributions/requirements/security-secrets-management-req-002.json +6 -2
  1353. package/blueprints/security-secrets-management/contributions/requirements/security-secrets-management-req-003.json +6 -2
  1354. package/blueprints/security-secrets-management/contributions/requirements/security-secrets-management-req-004.json +5 -1
  1355. package/blueprints/security-secrets-management/contributions/requirements/security-secrets-management-req-005.json +6 -2
  1356. package/blueprints/security-secrets-management/contributions/requirements/security-secrets-management-req-006.json +5 -1
  1357. package/blueprints/security-secrets-management/contributions/requirements/security-secrets-management-req-007.json +5 -1
  1358. package/blueprints/security-secrets-management/contributions/requirements/security-secrets-management-req-008.json +5 -1
  1359. package/blueprints/security-secrets-management/contributions/requirements/security-secrets-management-req-009.json +5 -1
  1360. package/blueprints/security-secrets-management/contributions/requirements/security-secrets-management-req-010.json +6 -3
  1361. package/blueprints/security-secrets-management/contributions/user-stories/security-secrets-management-us-8101.json +6 -3
  1362. package/blueprints/security-secrets-management/contributions/user-stories/security-secrets-management-us-8102.json +6 -3
  1363. package/blueprints/security-secrets-management/contributions/user-stories/security-secrets-management-us-8103.json +4 -2
  1364. package/blueprints/security-secrets-management/contributions/user-stories/security-secrets-management-us-8104.json +6 -3
  1365. package/blueprints/security-secrets-management/contributions/user-stories/security-secrets-management-us-8105.json +8 -4
  1366. package/blueprints/security-secrets-management/contributions/user-stories/security-secrets-management-us-8106.json +6 -3
  1367. package/blueprints/security-secrets-management/contributions/user-stories/security-secrets-management-us-8107.json +6 -3
  1368. package/blueprints/security-secrets-management/contributions/user-stories/security-secrets-management-us-8108.json +6 -3
  1369. package/blueprints/security-secrets-management/contributions/user-stories/security-secrets-management-us-8109.json +6 -3
  1370. package/blueprints/security-secrets-management/contributions/user-stories/security-secrets-management-us-8110.json +6 -3
  1371. package/blueprints/security-secrets-management/docs/topics.md +2 -3
  1372. package/fixtures/canary-manifest.json +9 -9
  1373. package/guidance/harness-template.md +25 -0
  1374. package/guidance/managed/agent-instructions-block.hash +1 -1
  1375. package/guidance/managed/agent-instructions-block.md +25 -0
  1376. package/package.json +2 -2
  1377. package/rcf/adrs/adr-4101-feedback-store-gitignored.json +20 -0
  1378. package/rcf/adrs/adr-4102-fingerprint-and-labels.json +25 -0
  1379. package/rcf/adrs/adr-4103-redaction-rule-based.json +20 -0
  1380. package/rcf/adrs/adr-4104-destination-on-library.json +25 -0
  1381. package/rcf/adrs/adr-4105-gh-ambient-auth.json +20 -0
  1382. package/rcf/adrs/adr-4106-bundled-entries-terminal.json +20 -0
  1383. package/rcf/adrs/adr-4107-stop-is-ask-event.json +30 -0
  1384. package/rcf/adrs/adr-4108-hooks-in-committed-config.json +25 -0
  1385. package/rcf/adrs/adr-4109-referee-validate-adr-crosslinks.json +25 -0
  1386. package/rcf/adrs/adr-4110-referee-coverage-strict-by-default.json +25 -0
  1387. package/rcf/adrs/adr-4111-referee-finalise-refusals.json +20 -0
  1388. package/rcf/adrs/adr-4112-referee-finalise-verified-invariant.json +30 -0
  1389. package/rcf/code-nodes/cn-600.json +45 -0
  1390. package/rcf/code-nodes/cn-601.json +18 -0
  1391. package/rcf/code-nodes/cn-602.json +15 -0
  1392. package/rcf/code-nodes/cn-603.json +12 -0
  1393. package/rcf/code-nodes/cn-604.json +14 -0
  1394. package/rcf/code-nodes/cn-605.json +17 -0
  1395. package/rcf/code-nodes/cn-606.json +12 -0
  1396. package/rcf/code-nodes/cn-607.json +12 -0
  1397. package/rcf/code-nodes/cn-608.json +14 -0
  1398. package/rcf/code-nodes/cn-609.json +17 -0
  1399. package/rcf/code-nodes/cn-620.json +18 -0
  1400. package/rcf/code-nodes/cn-621.json +14 -0
  1401. package/rcf/code-nodes/cn-622.json +15 -0
  1402. package/rcf/code-nodes/cn-623.json +16 -0
  1403. package/rcf/code-nodes/cn-624.json +14 -0
  1404. package/rcf/code-nodes/cn-625.json +15 -0
  1405. package/rcf/code-nodes/cn-626.json +13 -0
  1406. package/rcf/code-nodes/cn-627.json +13 -0
  1407. package/rcf/code-nodes/cn-628.json +14 -0
  1408. package/rcf/code-nodes/cn-629.json +12 -0
  1409. package/rcf/code-nodes/cn-630.json +12 -0
  1410. package/rcf/code-nodes/cn-631.json +13 -0
  1411. package/rcf/code-nodes/cn-632.json +13 -0
  1412. package/rcf/fbs/fbs-180.json +45 -0
  1413. package/rcf/fbs/fbs-181.json +45 -0
  1414. package/rcf/fbs/fbs-182.json +42 -0
  1415. package/rcf/fbs/fbs-183.json +50 -0
  1416. package/rcf/fbs/fbs-184.json +49 -0
  1417. package/rcf/fbs/fbs-185.json +34 -0
  1418. package/rcf/fbs/fbs-186.json +16 -0
  1419. package/rcf/fbs/fbs-187.json +17 -0
  1420. package/rcf/fbs/fbs-188.json +17 -0
  1421. package/rcf/fbs/fbs-189.json +17 -0
  1422. package/rcf/requirements/req-155.json +13 -0
  1423. package/rcf/requirements/req-156.json +13 -0
  1424. package/rcf/requirements/req-157.json +13 -0
  1425. package/rcf/requirements/req-158.json +13 -0
  1426. package/rcf/requirements/req-159.json +13 -0
  1427. package/rcf/requirements/req-160.json +13 -0
  1428. package/rcf/requirements/req-161.json +13 -0
  1429. package/rcf/requirements/req-162.json +13 -0
  1430. package/rcf/requirements/req-163.json +13 -0
  1431. package/rcf/requirements/req-164.json +13 -0
  1432. package/rcf/requirements/req-165.json +13 -0
  1433. package/rcf/tacs/tac-4101-feedback-cli.json +77 -0
  1434. package/rcf/tacs/tac-4102-feedback-store.json +50 -0
  1435. package/rcf/tacs/tac-4103-feedback-redact.json +39 -0
  1436. package/rcf/tacs/tac-4104-feedback-fingerprint.json +33 -0
  1437. package/rcf/tacs/tac-4105-feedback-render.json +45 -0
  1438. package/rcf/tacs/tac-4106-feedback-destination.json +39 -0
  1439. package/rcf/tacs/tac-4107-feedback-gh.json +43 -0
  1440. package/rcf/tacs/tac-4108-feedback-hook.json +46 -0
  1441. package/rcf/tacs/tac-4109-referee-validate-adr-crosslinks.json +20 -0
  1442. package/rcf/tacs/tac-4110-referee-coverage-mode-selector.json +21 -0
  1443. package/rcf/tacs/tac-4111-referee-finalise-per-ac-refusals.json +21 -0
  1444. package/rcf/tacs/tac-4112-referee-finalise-verified-invariant.json +22 -0
  1445. package/rcf/test-suites/ts-050.json +1 -1
  1446. package/rcf/test-suites/ts-052.json +1 -1
  1447. package/rcf/test-suites/ts-053.json +2 -2
  1448. package/rcf/test-suites/ts-054.json +2 -2
  1449. package/rcf/test-suites/ts-055.json +2 -2
  1450. package/rcf/test-suites/ts-056.json +4 -4
  1451. package/rcf/test-suites/ts-057.json +2 -2
  1452. package/rcf/test-suites/ts-140.json +9 -9
  1453. package/rcf/test-suites/ts-150.json +9 -9
  1454. package/rcf/test-suites/ts-185.json +54 -0
  1455. package/rcf/test-suites/ts-186.json +58 -0
  1456. package/rcf/test-suites/ts-187.json +44 -0
  1457. package/rcf/test-suites/ts-188.json +166 -0
  1458. package/rcf/test-suites/ts-189.json +38 -0
  1459. package/rcf/test-suites/ts-190.json +30 -0
  1460. package/rcf/test-suites/ts-191.json +51 -0
  1461. package/rcf/test-suites/ts-192.json +37 -0
  1462. package/rcf/test-suites/ts-193.json +60 -0
  1463. package/rcf/test-suites/ts-194.json +67 -0
  1464. package/rcf/test-suites/ts-195.json +52 -0
  1465. package/rcf/test-suites/ts-196.json +58 -0
  1466. package/rcf/test-suites/ts-197.json +66 -0
  1467. package/rcf/test-suites/ts-198.json +87 -0
  1468. package/rcf/test-suites/ts-199.json +51 -0
  1469. package/rcf/test-suites/ts-200.json +30 -0
  1470. package/rcf/test-suites/ts-201.json +38 -0
  1471. package/rcf/test-suites/ts-202.json +38 -0
  1472. package/rcf/test-suites/ts-203.json +38 -0
  1473. package/rcf/user-stories/us-15501.json +60 -0
  1474. package/rcf/user-stories/us-15502.json +33 -0
  1475. package/rcf/user-stories/us-15503.json +33 -0
  1476. package/rcf/user-stories/us-15601.json +51 -0
  1477. package/rcf/user-stories/us-15701.json +42 -0
  1478. package/rcf/user-stories/us-15801.json +42 -0
  1479. package/rcf/user-stories/us-15802.json +33 -0
  1480. package/rcf/user-stories/us-15901.json +33 -0
  1481. package/rcf/user-stories/us-15902.json +51 -0
  1482. package/rcf/user-stories/us-16001.json +51 -0
  1483. package/rcf/user-stories/us-16101.json +42 -0
  1484. package/rcf/user-stories/us-16102.json +33 -0
  1485. package/rcf/user-stories/us-16103.json +42 -0
  1486. package/rcf/user-stories/us-16104.json +42 -0
  1487. package/rcf/user-stories/us-16201.json +33 -0
  1488. package/rcf/user-stories/us-16301.json +36 -0
  1489. package/rcf/user-stories/us-16401.json +45 -0
  1490. package/rcf/user-stories/us-16501.json +45 -0
  1491. package/rcf/user-stories/us-16502.json +45 -0
  1492. package/rcf/user-stories/us-7701.json +3 -3
  1493. package/releases/releases.yaml +21 -1
  1494. package/src/blueprint/library-loader.js +48 -0
  1495. package/src/blueprint/library-registry.js +13 -0
  1496. package/src/browser-verify/pack-runner.js +7 -12
  1497. package/src/build/mark.js +1 -1
  1498. package/src/cli/blueprint-library.js +149 -0
  1499. package/src/cli/coverage.js +49 -24
  1500. package/src/cli/doctor.js +195 -7
  1501. package/src/cli/feedback.js +2204 -0
  1502. package/src/cli/finalise.js +158 -1
  1503. package/src/cli/help.js +6 -0
  1504. package/src/cli/init.js +63 -0
  1505. package/src/cli/update.js +21 -1
  1506. package/src/cli/view.js +22 -11
  1507. package/src/core/store/walker.js +33 -0
  1508. package/src/core/store/writer.js +23 -0
  1509. package/src/feedback/destination.js +361 -0
  1510. package/src/feedback/fingerprint.js +132 -0
  1511. package/src/feedback/gh.js +376 -0
  1512. package/src/feedback/hook.js +183 -0
  1513. package/src/feedback/labels.js +87 -0
  1514. package/src/feedback/redact-allowlist.json +14 -0
  1515. package/src/feedback/redact.js +1108 -0
  1516. package/src/feedback/render.js +267 -0
  1517. package/src/feedback/store.js +604 -0
  1518. package/src/finalise/index.js +4 -0
  1519. package/src/finalise/ingest.js +61 -0
  1520. package/src/finalise/ship-without-eval.js +19 -7
  1521. package/src/mcp/tools.js +8 -2
  1522. package/src/setup/feedback-hooks.js +397 -0
  1523. package/src/setup/managed-gitignore.js +3 -0
  1524. package/src/view/html-page.js +5 -5
  1525. 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
+ }