rcf-lite 0.20.0 → 0.22.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 (532) hide show
  1. package/CHANGELOG.md +39 -0
  2. package/blueprints/application-account-settings/CHANGELOG.md +12 -0
  3. package/blueprints/application-account-settings/README.md +114 -0
  4. package/blueprints/application-account-settings/blueprint.json +234 -0
  5. package/blueprints/application-account-settings/contributions/adrs/adr-2601-application-account-settings-capability-vocabulary.json +20 -0
  6. package/blueprints/application-account-settings/contributions/adrs/adr-2602-application-account-settings-security-surface-shape.json +20 -0
  7. package/blueprints/application-account-settings/contributions/adrs/adr-2603-application-account-settings-theme-persistence.json +20 -0
  8. package/blueprints/application-account-settings/contributions/adrs/adr-2604-application-account-settings-reauth-window.json +20 -0
  9. package/blueprints/application-account-settings/contributions/requirements/application-account-settings-req-001.json +18 -0
  10. package/blueprints/application-account-settings/contributions/requirements/application-account-settings-req-002.json +18 -0
  11. package/blueprints/application-account-settings/contributions/requirements/application-account-settings-req-003.json +18 -0
  12. package/blueprints/application-account-settings/contributions/requirements/application-account-settings-req-004.json +18 -0
  13. package/blueprints/application-account-settings/contributions/requirements/application-account-settings-req-005.json +18 -0
  14. package/blueprints/application-account-settings/contributions/requirements/application-account-settings-req-006.json +18 -0
  15. package/blueprints/application-account-settings/contributions/tacs/tac-2601-application-account-settings-shell.json +41 -0
  16. package/blueprints/application-account-settings/contributions/tacs/tac-2602-application-account-settings-capability-discovery.json +28 -0
  17. package/blueprints/application-account-settings/contributions/tacs/tac-2603-application-account-settings-hosted-ui-bridge.json +35 -0
  18. package/blueprints/application-account-settings/contributions/tacs/tac-2604-application-account-settings-session-store.json +40 -0
  19. package/blueprints/application-account-settings/contributions/user-stories/application-account-settings-us-25101.json +34 -0
  20. package/blueprints/application-account-settings/contributions/user-stories/application-account-settings-us-25102.json +27 -0
  21. package/blueprints/application-account-settings/contributions/user-stories/application-account-settings-us-25103.json +27 -0
  22. package/blueprints/application-account-settings/contributions/user-stories/application-account-settings-us-25104.json +27 -0
  23. package/blueprints/application-account-settings/contributions/user-stories/application-account-settings-us-25105.json +33 -0
  24. package/blueprints/application-account-settings/contributions/user-stories/application-account-settings-us-25106.json +27 -0
  25. package/blueprints/application-account-settings/contributions/user-stories/application-account-settings-us-25107.json +27 -0
  26. package/blueprints/application-account-settings/contributions/user-stories/application-account-settings-us-25108.json +27 -0
  27. package/blueprints/application-account-settings/contributions/user-stories/application-account-settings-us-25109.json +33 -0
  28. package/blueprints/application-account-settings/contributions/user-stories/application-account-settings-us-25110.json +27 -0
  29. package/blueprints/application-account-settings/docs/topics.md +48 -0
  30. package/blueprints/application-account-settings/guide/application-account-settings.md +30 -0
  31. package/blueprints/application-account-settings/probe-packs/application-account-settings.pack.mjs +246 -0
  32. package/blueprints/application-admin-console/CHANGELOG.md +11 -0
  33. package/blueprints/application-admin-console/README.md +98 -0
  34. package/blueprints/application-admin-console/blueprint.json +226 -0
  35. package/blueprints/application-admin-console/contributions/adrs/adr-2201-application-admin-console-capability-vocabulary.json +25 -0
  36. package/blueprints/application-admin-console/contributions/adrs/adr-2202-application-admin-console-baseline-roles.json +25 -0
  37. package/blueprints/application-admin-console/contributions/adrs/adr-2203-application-admin-console-invite-transport.json +20 -0
  38. package/blueprints/application-admin-console/contributions/adrs/adr-2204-application-admin-console-audit-retention.json +20 -0
  39. package/blueprints/application-admin-console/contributions/requirements/application-admin-console-req-001.json +18 -0
  40. package/blueprints/application-admin-console/contributions/requirements/application-admin-console-req-002.json +18 -0
  41. package/blueprints/application-admin-console/contributions/requirements/application-admin-console-req-003.json +18 -0
  42. package/blueprints/application-admin-console/contributions/requirements/application-admin-console-req-004.json +18 -0
  43. package/blueprints/application-admin-console/contributions/requirements/application-admin-console-req-005.json +18 -0
  44. package/blueprints/application-admin-console/contributions/requirements/application-admin-console-req-006.json +18 -0
  45. package/blueprints/application-admin-console/contributions/tacs/tac-2201-application-admin-console-shell.json +40 -0
  46. package/blueprints/application-admin-console/contributions/tacs/tac-2202-application-admin-console-capability-discovery.json +44 -0
  47. package/blueprints/application-admin-console/contributions/tacs/tac-2203-application-admin-console-permission-matrix.json +34 -0
  48. package/blueprints/application-admin-console/contributions/tacs/tac-2204-application-admin-console-audit-view.json +40 -0
  49. package/blueprints/application-admin-console/contributions/user-stories/application-admin-console-us-21101.json +34 -0
  50. package/blueprints/application-admin-console/contributions/user-stories/application-admin-console-us-21102.json +34 -0
  51. package/blueprints/application-admin-console/contributions/user-stories/application-admin-console-us-21103.json +34 -0
  52. package/blueprints/application-admin-console/contributions/user-stories/application-admin-console-us-21104.json +28 -0
  53. package/blueprints/application-admin-console/contributions/user-stories/application-admin-console-us-21105.json +34 -0
  54. package/blueprints/application-admin-console/contributions/user-stories/application-admin-console-us-21106.json +27 -0
  55. package/blueprints/application-admin-console/contributions/user-stories/application-admin-console-us-21107.json +27 -0
  56. package/blueprints/application-admin-console/contributions/user-stories/application-admin-console-us-21108.json +27 -0
  57. package/blueprints/application-admin-console/contributions/user-stories/application-admin-console-us-21109.json +33 -0
  58. package/blueprints/application-admin-console/docs/topics.md +42 -0
  59. package/blueprints/application-admin-console/guide/application-admin-console.md +29 -0
  60. package/blueprints/application-admin-console/probe-packs/application-admin-console.pack.mjs +182 -0
  61. package/blueprints/application-api-rest/docs/topics.md +13 -1
  62. package/blueprints/application-charts/CHANGELOG.md +12 -0
  63. package/blueprints/application-charts/README.md +73 -0
  64. package/blueprints/application-charts/blueprint.json +26 -0
  65. package/blueprints/application-charts/contributions/adrs/adr-1901-application-charts-engine-choice.json +25 -0
  66. package/blueprints/application-charts/contributions/adrs/adr-1902-application-charts-accessible-palette.json +25 -0
  67. package/blueprints/application-charts/contributions/adrs/adr-1903-application-charts-motion.json +25 -0
  68. package/blueprints/application-charts/contributions/requirements/application-charts-req-001.json +15 -0
  69. package/blueprints/application-charts/contributions/requirements/application-charts-req-002.json +15 -0
  70. package/blueprints/application-charts/contributions/requirements/application-charts-req-003.json +15 -0
  71. package/blueprints/application-charts/contributions/requirements/application-charts-req-004.json +15 -0
  72. package/blueprints/application-charts/contributions/tacs/tac-1901-application-charts-render-shell.json +42 -0
  73. package/blueprints/application-charts/contributions/tacs/tac-1902-application-charts-keyboard-traversal.json +40 -0
  74. package/blueprints/application-charts/contributions/user-stories/application-charts-us-18101.json +35 -0
  75. package/blueprints/application-charts/contributions/user-stories/application-charts-us-18102.json +35 -0
  76. package/blueprints/application-charts/contributions/user-stories/application-charts-us-18103.json +35 -0
  77. package/blueprints/application-charts/contributions/user-stories/application-charts-us-18104.json +35 -0
  78. package/blueprints/application-charts/contributions/user-stories/application-charts-us-18105.json +35 -0
  79. package/blueprints/application-charts/contributions/user-stories/application-charts-us-18106.json +35 -0
  80. package/blueprints/application-charts/docs/topics.md +44 -0
  81. package/blueprints/application-charts/guide/application-charts.md +44 -0
  82. package/blueprints/application-charts/probe-packs/application-charts.pack.mjs +191 -0
  83. package/blueprints/application-dashboard/CHANGELOG.md +10 -0
  84. package/blueprints/application-dashboard/README.md +102 -0
  85. package/blueprints/application-dashboard/assets/guidance/dashboard-design.md +124 -0
  86. package/blueprints/application-dashboard/blueprint.json +29 -0
  87. package/blueprints/application-dashboard/contributions/adrs/adr-2001-application-dashboard-primary-kpi-enum.json +25 -0
  88. package/blueprints/application-dashboard/contributions/adrs/adr-2002-application-dashboard-timeframe-presets.json +25 -0
  89. package/blueprints/application-dashboard/contributions/adrs/adr-2003-application-dashboard-export-formats.json +25 -0
  90. package/blueprints/application-dashboard/contributions/requirements/application-dashboard-req-001.json +15 -0
  91. package/blueprints/application-dashboard/contributions/requirements/application-dashboard-req-002.json +15 -0
  92. package/blueprints/application-dashboard/contributions/requirements/application-dashboard-req-003.json +15 -0
  93. package/blueprints/application-dashboard/contributions/requirements/application-dashboard-req-004.json +15 -0
  94. package/blueprints/application-dashboard/contributions/requirements/application-dashboard-req-005.json +15 -0
  95. package/blueprints/application-dashboard/contributions/tacs/tac-2001-application-dashboard-tile-grid.json +47 -0
  96. package/blueprints/application-dashboard/contributions/tacs/tac-2002-application-dashboard-filter-chrome.json +41 -0
  97. package/blueprints/application-dashboard/contributions/tacs/tac-2003-application-dashboard-export-handle.json +35 -0
  98. package/blueprints/application-dashboard/contributions/user-stories/application-dashboard-us-19101.json +35 -0
  99. package/blueprints/application-dashboard/contributions/user-stories/application-dashboard-us-19102.json +35 -0
  100. package/blueprints/application-dashboard/contributions/user-stories/application-dashboard-us-19103.json +35 -0
  101. package/blueprints/application-dashboard/contributions/user-stories/application-dashboard-us-19104.json +35 -0
  102. package/blueprints/application-dashboard/contributions/user-stories/application-dashboard-us-19105.json +35 -0
  103. package/blueprints/application-dashboard/contributions/user-stories/application-dashboard-us-19106.json +35 -0
  104. package/blueprints/application-dashboard/contributions/user-stories/application-dashboard-us-19107.json +35 -0
  105. package/blueprints/application-dashboard/docs/topics.md +50 -0
  106. package/blueprints/application-dashboard/guide/application-dashboard.md +48 -0
  107. package/blueprints/application-dashboard/probe-packs/application-dashboard.pack.mjs +231 -0
  108. package/blueprints/application-datatable/CHANGELOG.md +8 -0
  109. package/blueprints/application-datatable/README.md +43 -0
  110. package/blueprints/application-datatable/blueprint.json +33 -0
  111. package/blueprints/application-datatable/contributions/adrs/adr-1801-application-datatable-pattern-choice.json +25 -0
  112. package/blueprints/application-datatable/contributions/adrs/adr-1802-application-datatable-url-state.json +20 -0
  113. package/blueprints/application-datatable/contributions/adrs/adr-1803-application-datatable-page-size.json +20 -0
  114. package/blueprints/application-datatable/contributions/adrs/adr-1804-application-datatable-selection-persistence.json +20 -0
  115. package/blueprints/application-datatable/contributions/requirements/application-datatable-req-001.json +15 -0
  116. package/blueprints/application-datatable/contributions/requirements/application-datatable-req-002.json +15 -0
  117. package/blueprints/application-datatable/contributions/requirements/application-datatable-req-003.json +15 -0
  118. package/blueprints/application-datatable/contributions/requirements/application-datatable-req-004.json +15 -0
  119. package/blueprints/application-datatable/contributions/requirements/application-datatable-req-005.json +15 -0
  120. package/blueprints/application-datatable/contributions/requirements/application-datatable-req-006.json +15 -0
  121. package/blueprints/application-datatable/contributions/tacs/tac-1801-application-datatable-shell.json +50 -0
  122. package/blueprints/application-datatable/contributions/tacs/tac-1802-application-datatable-query-adapter.json +39 -0
  123. package/blueprints/application-datatable/contributions/tacs/tac-1803-application-datatable-selection-model.json +28 -0
  124. package/blueprints/application-datatable/contributions/user-stories/application-datatable-us-17101.json +44 -0
  125. package/blueprints/application-datatable/contributions/user-stories/application-datatable-us-17102.json +44 -0
  126. package/blueprints/application-datatable/contributions/user-stories/application-datatable-us-17103.json +44 -0
  127. package/blueprints/application-datatable/contributions/user-stories/application-datatable-us-17104.json +44 -0
  128. package/blueprints/application-datatable/contributions/user-stories/application-datatable-us-17105.json +44 -0
  129. package/blueprints/application-datatable/contributions/user-stories/application-datatable-us-17106.json +44 -0
  130. package/blueprints/application-datatable/contributions/user-stories/application-datatable-us-17107.json +44 -0
  131. package/blueprints/application-datatable/contributions/user-stories/application-datatable-us-17108.json +44 -0
  132. package/blueprints/application-datatable/contributions/user-stories/application-datatable-us-17109.json +44 -0
  133. package/blueprints/application-datatable/docs/topics.md +42 -0
  134. package/blueprints/application-datatable/guide/application-datatable.md +38 -0
  135. package/blueprints/application-datatable/probe-packs/application-datatable.pack.mjs +240 -0
  136. package/blueprints/application-empty-error-states/CHANGELOG.md +9 -0
  137. package/blueprints/application-empty-error-states/README.md +88 -0
  138. package/blueprints/application-empty-error-states/blueprint.json +119 -0
  139. package/blueprints/application-empty-error-states/contributions/adrs/adr-2301-application-empty-error-states-status-contract.json +25 -0
  140. package/blueprints/application-empty-error-states/contributions/adrs/adr-2302-application-empty-error-states-stack-trace-visibility.json +25 -0
  141. package/blueprints/application-empty-error-states/contributions/adrs/adr-2303-application-empty-error-states-offline-strategy.json +25 -0
  142. package/blueprints/application-empty-error-states/contributions/requirements/application-empty-error-states-req-001.json +18 -0
  143. package/blueprints/application-empty-error-states/contributions/requirements/application-empty-error-states-req-002.json +18 -0
  144. package/blueprints/application-empty-error-states/contributions/requirements/application-empty-error-states-req-003.json +18 -0
  145. package/blueprints/application-empty-error-states/contributions/requirements/application-empty-error-states-req-004.json +18 -0
  146. package/blueprints/application-empty-error-states/contributions/requirements/application-empty-error-states-req-005.json +18 -0
  147. package/blueprints/application-empty-error-states/contributions/tacs/tac-2301-application-empty-error-states-state-machine.json +46 -0
  148. package/blueprints/application-empty-error-states/contributions/tacs/tac-2302-application-empty-error-states-recovery-router.json +36 -0
  149. package/blueprints/application-empty-error-states/contributions/tacs/tac-2303-application-empty-error-states-offline-buffer.json +40 -0
  150. package/blueprints/application-empty-error-states/contributions/user-stories/application-empty-error-states-us-22101.json +29 -0
  151. package/blueprints/application-empty-error-states/contributions/user-stories/application-empty-error-states-us-22102.json +29 -0
  152. package/blueprints/application-empty-error-states/contributions/user-stories/application-empty-error-states-us-22103.json +29 -0
  153. package/blueprints/application-empty-error-states/contributions/user-stories/application-empty-error-states-us-22104.json +29 -0
  154. package/blueprints/application-empty-error-states/contributions/user-stories/application-empty-error-states-us-22105.json +29 -0
  155. package/blueprints/application-empty-error-states/contributions/user-stories/application-empty-error-states-us-22106.json +29 -0
  156. package/blueprints/application-empty-error-states/contributions/user-stories/application-empty-error-states-us-22107.json +29 -0
  157. package/blueprints/application-empty-error-states/contributions/user-stories/application-empty-error-states-us-22108.json +29 -0
  158. package/blueprints/application-empty-error-states/docs/topics.md +53 -0
  159. package/blueprints/application-empty-error-states/guide/application-empty-error-states.md +50 -0
  160. package/blueprints/application-empty-error-states/probe-packs/application-empty-error-states.pack.mjs +284 -0
  161. package/blueprints/application-error-handling/docs/topics.md +12 -0
  162. package/blueprints/application-file-upload/CHANGELOG.md +9 -0
  163. package/blueprints/application-file-upload/README.md +85 -0
  164. package/blueprints/application-file-upload/blueprint.json +114 -0
  165. package/blueprints/application-file-upload/contributions/adrs/adr-2401-application-file-upload-transport.json +25 -0
  166. package/blueprints/application-file-upload/contributions/adrs/adr-2402-application-file-upload-accepted-set.json +25 -0
  167. package/blueprints/application-file-upload/contributions/adrs/adr-2403-application-file-upload-virus-scan.json +25 -0
  168. package/blueprints/application-file-upload/contributions/requirements/application-file-upload-req-001.json +18 -0
  169. package/blueprints/application-file-upload/contributions/requirements/application-file-upload-req-002.json +18 -0
  170. package/blueprints/application-file-upload/contributions/requirements/application-file-upload-req-003.json +18 -0
  171. package/blueprints/application-file-upload/contributions/requirements/application-file-upload-req-004.json +18 -0
  172. package/blueprints/application-file-upload/contributions/requirements/application-file-upload-req-005.json +18 -0
  173. package/blueprints/application-file-upload/contributions/tacs/tac-2401-application-file-upload-input.json +46 -0
  174. package/blueprints/application-file-upload/contributions/tacs/tac-2402-application-file-upload-transport.json +47 -0
  175. package/blueprints/application-file-upload/contributions/tacs/tac-2403-application-file-upload-progress-announcer.json +46 -0
  176. package/blueprints/application-file-upload/contributions/user-stories/application-file-upload-us-23101.json +28 -0
  177. package/blueprints/application-file-upload/contributions/user-stories/application-file-upload-us-23102.json +28 -0
  178. package/blueprints/application-file-upload/contributions/user-stories/application-file-upload-us-23103.json +29 -0
  179. package/blueprints/application-file-upload/contributions/user-stories/application-file-upload-us-23104.json +28 -0
  180. package/blueprints/application-file-upload/contributions/user-stories/application-file-upload-us-23105.json +29 -0
  181. package/blueprints/application-file-upload/contributions/user-stories/application-file-upload-us-23106.json +28 -0
  182. package/blueprints/application-file-upload/contributions/user-stories/application-file-upload-us-23107.json +28 -0
  183. package/blueprints/application-file-upload/docs/topics.md +58 -0
  184. package/blueprints/application-file-upload/guide/application-file-upload.md +48 -0
  185. package/blueprints/application-file-upload/probe-packs/application-file-upload.pack.mjs +238 -0
  186. package/blueprints/application-forms-wizard/CHANGELOG.md +9 -0
  187. package/blueprints/application-forms-wizard/README.md +102 -0
  188. package/blueprints/application-forms-wizard/blueprint.json +120 -0
  189. package/blueprints/application-forms-wizard/contributions/adrs/adr-2501-application-forms-wizard-navigation.json +25 -0
  190. package/blueprints/application-forms-wizard/contributions/adrs/adr-2502-application-forms-wizard-save-and-return.json +25 -0
  191. package/blueprints/application-forms-wizard/contributions/adrs/adr-2503-application-forms-wizard-step-indicator.json +25 -0
  192. package/blueprints/application-forms-wizard/contributions/requirements/application-forms-wizard-req-001.json +18 -0
  193. package/blueprints/application-forms-wizard/contributions/requirements/application-forms-wizard-req-002.json +18 -0
  194. package/blueprints/application-forms-wizard/contributions/requirements/application-forms-wizard-req-003.json +18 -0
  195. package/blueprints/application-forms-wizard/contributions/requirements/application-forms-wizard-req-004.json +18 -0
  196. package/blueprints/application-forms-wizard/contributions/requirements/application-forms-wizard-req-005.json +18 -0
  197. package/blueprints/application-forms-wizard/contributions/tacs/tac-2501-application-forms-wizard-task-list.json +46 -0
  198. package/blueprints/application-forms-wizard/contributions/tacs/tac-2502-application-forms-wizard-error-summary.json +40 -0
  199. package/blueprints/application-forms-wizard/contributions/tacs/tac-2503-application-forms-wizard-draft-store.json +40 -0
  200. package/blueprints/application-forms-wizard/contributions/user-stories/application-forms-wizard-us-24101.json +28 -0
  201. package/blueprints/application-forms-wizard/contributions/user-stories/application-forms-wizard-us-24102.json +29 -0
  202. package/blueprints/application-forms-wizard/contributions/user-stories/application-forms-wizard-us-24103.json +28 -0
  203. package/blueprints/application-forms-wizard/contributions/user-stories/application-forms-wizard-us-24104.json +29 -0
  204. package/blueprints/application-forms-wizard/contributions/user-stories/application-forms-wizard-us-24105.json +28 -0
  205. package/blueprints/application-forms-wizard/contributions/user-stories/application-forms-wizard-us-24106.json +28 -0
  206. package/blueprints/application-forms-wizard/contributions/user-stories/application-forms-wizard-us-24107.json +28 -0
  207. package/blueprints/application-forms-wizard/contributions/user-stories/application-forms-wizard-us-24108.json +29 -0
  208. package/blueprints/application-forms-wizard/docs/topics.md +49 -0
  209. package/blueprints/application-forms-wizard/guide/application-forms-wizard.md +48 -0
  210. package/blueprints/application-forms-wizard/probe-packs/application-forms-wizard.pack.mjs +233 -0
  211. package/blueprints/application-notifications-in-app/CHANGELOG.md +9 -0
  212. package/blueprints/application-notifications-in-app/README.md +80 -0
  213. package/blueprints/application-notifications-in-app/blueprint.json +30 -0
  214. package/blueprints/application-notifications-in-app/contributions/adrs/adr-2101-application-notifications-in-app-live-region-role-mapping.json +25 -0
  215. package/blueprints/application-notifications-in-app/contributions/adrs/adr-2102-application-notifications-in-app-toast-timeout-floor.json +25 -0
  216. package/blueprints/application-notifications-in-app/contributions/adrs/adr-2103-application-notifications-in-app-retention-window.json +25 -0
  217. package/blueprints/application-notifications-in-app/contributions/requirements/application-notifications-in-app-req-001.json +15 -0
  218. package/blueprints/application-notifications-in-app/contributions/requirements/application-notifications-in-app-req-002.json +15 -0
  219. package/blueprints/application-notifications-in-app/contributions/requirements/application-notifications-in-app-req-003.json +15 -0
  220. package/blueprints/application-notifications-in-app/contributions/requirements/application-notifications-in-app-req-004.json +15 -0
  221. package/blueprints/application-notifications-in-app/contributions/requirements/application-notifications-in-app-req-005.json +15 -0
  222. package/blueprints/application-notifications-in-app/contributions/tacs/tac-2101-application-notifications-in-app-live-region.json +46 -0
  223. package/blueprints/application-notifications-in-app/contributions/tacs/tac-2102-application-notifications-in-app-centre.json +52 -0
  224. package/blueprints/application-notifications-in-app/contributions/tacs/tac-2103-application-notifications-in-app-preferences.json +40 -0
  225. package/blueprints/application-notifications-in-app/contributions/user-stories/application-notifications-in-app-us-20101.json +35 -0
  226. package/blueprints/application-notifications-in-app/contributions/user-stories/application-notifications-in-app-us-20102.json +35 -0
  227. package/blueprints/application-notifications-in-app/contributions/user-stories/application-notifications-in-app-us-20103.json +35 -0
  228. package/blueprints/application-notifications-in-app/contributions/user-stories/application-notifications-in-app-us-20104.json +35 -0
  229. package/blueprints/application-notifications-in-app/contributions/user-stories/application-notifications-in-app-us-20105.json +35 -0
  230. package/blueprints/application-notifications-in-app/contributions/user-stories/application-notifications-in-app-us-20106.json +26 -0
  231. package/blueprints/application-notifications-in-app/contributions/user-stories/application-notifications-in-app-us-20107.json +26 -0
  232. package/blueprints/application-notifications-in-app/contributions/user-stories/application-notifications-in-app-us-20108.json +26 -0
  233. package/blueprints/application-notifications-in-app/docs/topics.md +46 -0
  234. package/blueprints/application-notifications-in-app/guide/application-notifications-in-app.md +47 -0
  235. package/blueprints/application-notifications-in-app/probe-packs/application-notifications-in-app.pack.mjs +328 -0
  236. package/blueprints/application-onboarding-tour/CHANGELOG.md +12 -0
  237. package/blueprints/application-onboarding-tour/README.md +77 -0
  238. package/blueprints/application-onboarding-tour/blueprint.json +164 -0
  239. package/blueprints/application-onboarding-tour/contributions/adrs/adr-2701-application-onboarding-tour-dismissal-policy.json +20 -0
  240. package/blueprints/application-onboarding-tour/contributions/adrs/adr-2702-application-onboarding-tour-completion-store-shape.json +20 -0
  241. package/blueprints/application-onboarding-tour/contributions/adrs/adr-2703-application-onboarding-tour-checklist-anchor.json +20 -0
  242. package/blueprints/application-onboarding-tour/contributions/requirements/application-onboarding-tour-req-001.json +18 -0
  243. package/blueprints/application-onboarding-tour/contributions/requirements/application-onboarding-tour-req-002.json +18 -0
  244. package/blueprints/application-onboarding-tour/contributions/requirements/application-onboarding-tour-req-003.json +18 -0
  245. package/blueprints/application-onboarding-tour/contributions/requirements/application-onboarding-tour-req-004.json +18 -0
  246. package/blueprints/application-onboarding-tour/contributions/tacs/tac-2701-application-onboarding-tour-step-runner.json +41 -0
  247. package/blueprints/application-onboarding-tour/contributions/tacs/tac-2702-application-onboarding-tour-checklist-slot.json +35 -0
  248. package/blueprints/application-onboarding-tour/contributions/tacs/tac-2703-application-onboarding-tour-completion-store.json +34 -0
  249. package/blueprints/application-onboarding-tour/contributions/user-stories/application-onboarding-tour-us-26101.json +27 -0
  250. package/blueprints/application-onboarding-tour/contributions/user-stories/application-onboarding-tour-us-26102.json +27 -0
  251. package/blueprints/application-onboarding-tour/contributions/user-stories/application-onboarding-tour-us-26103.json +27 -0
  252. package/blueprints/application-onboarding-tour/contributions/user-stories/application-onboarding-tour-us-26104.json +27 -0
  253. package/blueprints/application-onboarding-tour/contributions/user-stories/application-onboarding-tour-us-26105.json +27 -0
  254. package/blueprints/application-onboarding-tour/contributions/user-stories/application-onboarding-tour-us-26106.json +27 -0
  255. package/blueprints/application-onboarding-tour/contributions/user-stories/application-onboarding-tour-us-26107.json +27 -0
  256. package/blueprints/application-onboarding-tour/docs/topics.md +48 -0
  257. package/blueprints/application-onboarding-tour/guide/application-onboarding-tour.md +59 -0
  258. package/blueprints/application-onboarding-tour/probe-packs/application-onboarding-tour.pack.mjs +231 -0
  259. package/blueprints/application-spa/docs/topics.md +13 -1
  260. package/blueprints/delivery-ci-workflows/docs/topics.md +13 -1
  261. package/blueprints/deploy-cloudflare-workers/docs/topics.md +13 -1
  262. package/blueprints/email-smtp-resend/docs/topics.md +13 -1
  263. package/blueprints/object-storage-s3/CHANGELOG.md +13 -0
  264. package/blueprints/object-storage-s3/README.md +108 -0
  265. package/blueprints/object-storage-s3/blueprint.json +72 -0
  266. package/blueprints/object-storage-s3/contributions/adrs/adr-2901-object-storage-s3-adapter.json +30 -0
  267. package/blueprints/object-storage-s3/contributions/adrs/adr-2902-object-storage-s3-presigned-ttl-floor.json +25 -0
  268. package/blueprints/object-storage-s3/contributions/adrs/adr-2903-object-storage-s3-multipart-threshold.json +25 -0
  269. package/blueprints/object-storage-s3/contributions/adrs/adr-2904-object-storage-s3-contract.json +25 -0
  270. package/blueprints/object-storage-s3/contributions/probes/event-secrecy.mjs +103 -0
  271. package/blueprints/object-storage-s3/contributions/probes/facade-round-trip.mjs +43 -0
  272. package/blueprints/object-storage-s3/contributions/probes/multipart-upload.mjs +84 -0
  273. package/blueprints/object-storage-s3/contributions/probes/presigned-url.mjs +101 -0
  274. package/blueprints/object-storage-s3/contributions/probes/probe-utils.mjs +85 -0
  275. package/blueprints/object-storage-s3/contributions/probes/put-get-round-trip.mjs +84 -0
  276. package/blueprints/object-storage-s3/contributions/probes/r2-real-account-smoke.mjs +64 -0
  277. package/blueprints/object-storage-s3/contributions/probes/run-event-secrecy.mjs +4 -0
  278. package/blueprints/object-storage-s3/contributions/probes/run-facade-round-trip.mjs +10 -0
  279. package/blueprints/object-storage-s3/contributions/probes/run-multipart-upload.mjs +4 -0
  280. package/blueprints/object-storage-s3/contributions/probes/run-presigned-url.mjs +4 -0
  281. package/blueprints/object-storage-s3/contributions/probes/run-put-get-round-trip.mjs +7 -0
  282. package/blueprints/object-storage-s3/contributions/probes/run-r2-real-account-smoke.mjs +4 -0
  283. package/blueprints/object-storage-s3/contributions/requirements/object-storage-s3-req-001.json +18 -0
  284. package/blueprints/object-storage-s3/contributions/requirements/object-storage-s3-req-002.json +18 -0
  285. package/blueprints/object-storage-s3/contributions/requirements/object-storage-s3-req-003.json +18 -0
  286. package/blueprints/object-storage-s3/contributions/requirements/object-storage-s3-req-004.json +18 -0
  287. package/blueprints/object-storage-s3/contributions/requirements/object-storage-s3-req-005.json +18 -0
  288. package/blueprints/object-storage-s3/contributions/requirements/object-storage-s3-req-006.json +18 -0
  289. package/blueprints/object-storage-s3/contributions/tacs/tac-2901-object-storage-s3-facade.json +57 -0
  290. package/blueprints/object-storage-s3/contributions/tacs/tac-2902-object-storage-s3-multipart-uploader.json +36 -0
  291. package/blueprints/object-storage-s3/contributions/tacs/tac-2903-object-storage-s3-event-sink.json +36 -0
  292. package/blueprints/object-storage-s3/contributions/user-stories/object-storage-s3-us-28101.json +34 -0
  293. package/blueprints/object-storage-s3/contributions/user-stories/object-storage-s3-us-28102.json +43 -0
  294. package/blueprints/object-storage-s3/contributions/user-stories/object-storage-s3-us-28103.json +25 -0
  295. package/blueprints/object-storage-s3/contributions/user-stories/object-storage-s3-us-28104.json +34 -0
  296. package/blueprints/object-storage-s3/contributions/user-stories/object-storage-s3-us-28105.json +25 -0
  297. package/blueprints/object-storage-s3/contributions/user-stories/object-storage-s3-us-28106.json +34 -0
  298. package/blueprints/object-storage-s3/contributions/user-stories/object-storage-s3-us-28107.json +34 -0
  299. package/blueprints/object-storage-s3/contributions/user-stories/object-storage-s3-us-28108.json +34 -0
  300. package/blueprints/object-storage-s3/docs/topics.md +62 -0
  301. package/blueprints/object-storage-s3/guide/object-storage-s3.md +207 -0
  302. package/blueprints/observability-essentials/docs/topics.md +13 -1
  303. package/blueprints/observability-logging/CHANGELOG.md +9 -0
  304. package/blueprints/observability-logging/README.md +4 -1
  305. package/blueprints/observability-logging/blueprint.json +114 -21
  306. package/blueprints/observability-logging/docs/topics.md +12 -0
  307. package/blueprints/observability-probe-endpoints/docs/topics.md +13 -1
  308. package/blueprints/persistence-data-d1/docs/topics.md +13 -1
  309. package/blueprints/persistence-data-postgres/CHANGELOG.md +12 -0
  310. package/blueprints/persistence-data-postgres/README.md +101 -0
  311. package/blueprints/persistence-data-postgres/blueprint.json +80 -0
  312. package/blueprints/persistence-data-postgres/contributions/adrs/adr-2801-persistence-data-postgres-driver.json +30 -0
  313. package/blueprints/persistence-data-postgres/contributions/adrs/adr-2802-persistence-data-postgres-migration-shape.json +25 -0
  314. package/blueprints/persistence-data-postgres/contributions/adrs/adr-2803-persistence-data-postgres-runner-mode.json +25 -0
  315. package/blueprints/persistence-data-postgres/contributions/adrs/adr-2804-persistence-data-postgres-recovery.json +25 -0
  316. package/blueprints/persistence-data-postgres/contributions/adrs/adr-2805-persistence-data-postgres-connection-pool-posture.json +25 -0
  317. package/blueprints/persistence-data-postgres/contributions/probes/facade-round-trip.mjs +56 -0
  318. package/blueprints/persistence-data-postgres/contributions/probes/migration-apply.mjs +75 -0
  319. package/blueprints/persistence-data-postgres/contributions/probes/pool-posture-smoke.mjs +56 -0
  320. package/blueprints/persistence-data-postgres/contributions/probes/prepared-statement-scan.mjs +186 -0
  321. package/blueprints/persistence-data-postgres/contributions/probes/probe-utils.mjs +76 -0
  322. package/blueprints/persistence-data-postgres/contributions/probes/recovery-restore-round-trip.mjs +173 -0
  323. package/blueprints/persistence-data-postgres/contributions/probes/run-facade-round-trip.mjs +10 -0
  324. package/blueprints/persistence-data-postgres/contributions/probes/run-migration-apply.mjs +10 -0
  325. package/blueprints/persistence-data-postgres/contributions/probes/run-pool-posture-smoke.mjs +9 -0
  326. package/blueprints/persistence-data-postgres/contributions/probes/run-prepared-statement-scan.mjs +10 -0
  327. package/blueprints/persistence-data-postgres/contributions/probes/run-recovery-restore-round-trip.mjs +9 -0
  328. package/blueprints/persistence-data-postgres/contributions/probes/run-transaction-atomicity.mjs +10 -0
  329. package/blueprints/persistence-data-postgres/contributions/probes/transaction-atomicity.mjs +79 -0
  330. package/blueprints/persistence-data-postgres/contributions/requirements/persistence-data-postgres-req-001.json +18 -0
  331. package/blueprints/persistence-data-postgres/contributions/requirements/persistence-data-postgres-req-002.json +18 -0
  332. package/blueprints/persistence-data-postgres/contributions/requirements/persistence-data-postgres-req-003.json +18 -0
  333. package/blueprints/persistence-data-postgres/contributions/requirements/persistence-data-postgres-req-004.json +18 -0
  334. package/blueprints/persistence-data-postgres/contributions/requirements/persistence-data-postgres-req-005.json +18 -0
  335. package/blueprints/persistence-data-postgres/contributions/requirements/persistence-data-postgres-req-006.json +18 -0
  336. package/blueprints/persistence-data-postgres/contributions/requirements/persistence-data-postgres-req-007.json +18 -0
  337. package/blueprints/persistence-data-postgres/contributions/tacs/tac-2801-persistence-data-postgres-facade.json +58 -0
  338. package/blueprints/persistence-data-postgres/contributions/tacs/tac-2802-persistence-data-postgres-migration-runner.json +40 -0
  339. package/blueprints/persistence-data-postgres/contributions/tacs/tac-2803-persistence-data-postgres-transaction-helper.json +35 -0
  340. package/blueprints/persistence-data-postgres/contributions/tacs/tac-2804-persistence-data-postgres-recovery-runner.json +40 -0
  341. package/blueprints/persistence-data-postgres/contributions/user-stories/persistence-data-postgres-us-27101.json +34 -0
  342. package/blueprints/persistence-data-postgres/contributions/user-stories/persistence-data-postgres-us-27102.json +25 -0
  343. package/blueprints/persistence-data-postgres/contributions/user-stories/persistence-data-postgres-us-27103.json +25 -0
  344. package/blueprints/persistence-data-postgres/contributions/user-stories/persistence-data-postgres-us-27104.json +25 -0
  345. package/blueprints/persistence-data-postgres/contributions/user-stories/persistence-data-postgres-us-27105.json +25 -0
  346. package/blueprints/persistence-data-postgres/contributions/user-stories/persistence-data-postgres-us-27106.json +25 -0
  347. package/blueprints/persistence-data-postgres/contributions/user-stories/persistence-data-postgres-us-27107.json +25 -0
  348. package/blueprints/persistence-data-postgres/contributions/user-stories/persistence-data-postgres-us-27108.json +25 -0
  349. package/blueprints/persistence-data-postgres/contributions/user-stories/persistence-data-postgres-us-27109.json +25 -0
  350. package/blueprints/persistence-data-postgres/contributions/user-stories/persistence-data-postgres-us-27110.json +25 -0
  351. package/blueprints/persistence-data-postgres/docs/topics.md +64 -0
  352. package/blueprints/persistence-data-postgres/guide/persistence-data-postgres.md +172 -0
  353. package/blueprints/persistence-data-sqlite/docs/topics.md +13 -1
  354. package/blueprints/security-auth-clerk/CHANGELOG.md +9 -0
  355. package/blueprints/security-auth-clerk/README.md +3 -0
  356. package/blueprints/security-auth-clerk/blueprint.json +147 -29
  357. package/blueprints/security-auth-clerk/docs/topics.md +13 -1
  358. package/blueprints/security-auth-keycloak/CHANGELOG.md +9 -0
  359. package/blueprints/security-auth-keycloak/README.md +3 -0
  360. package/blueprints/security-auth-keycloak/blueprint.json +182 -36
  361. package/blueprints/security-auth-keycloak/docs/topics.md +13 -1
  362. package/blueprints/security-auth-magic-link/CHANGELOG.md +9 -0
  363. package/blueprints/security-auth-magic-link/README.md +3 -0
  364. package/blueprints/security-auth-magic-link/blueprint.json +159 -32
  365. package/blueprints/security-auth-magic-link/docs/topics.md +13 -1
  366. package/blueprints/security-auth-oauth2/CHANGELOG.md +9 -0
  367. package/blueprints/security-auth-oauth2/README.md +3 -0
  368. package/blueprints/security-auth-oauth2/blueprint.json +158 -31
  369. package/blueprints/security-auth-oauth2/docs/topics.md +13 -1
  370. package/blueprints/security-secrets-management/CHANGELOG.md +11 -0
  371. package/blueprints/security-secrets-management/blueprint.json +2 -1
  372. package/blueprints/security-secrets-management/docs/topics.md +13 -1
  373. package/fixtures/canary-manifest.json +9 -9
  374. package/package.json +2 -2
  375. package/rcf/code-nodes/cn-106.json +13 -0
  376. package/rcf/code-nodes/cn-107.json +14 -0
  377. package/rcf/code-nodes/cn-108.json +13 -0
  378. package/rcf/code-nodes/cn-109.json +12 -0
  379. package/rcf/code-nodes/cn-110.json +12 -0
  380. package/rcf/code-nodes/cn-111.json +14 -0
  381. package/rcf/code-nodes/cn-112.json +14 -0
  382. package/rcf/code-nodes/cn-113.json +12 -0
  383. package/rcf/code-nodes/cn-114.json +13 -0
  384. package/rcf/code-nodes/cn-115.json +13 -0
  385. package/rcf/code-nodes/cn-116.json +12 -0
  386. package/rcf/code-nodes/cn-117.json +13 -0
  387. package/rcf/code-nodes/cn-118.json +13 -0
  388. package/rcf/code-nodes/cn-119.json +13 -0
  389. package/rcf/code-nodes/cn-120.json +13 -0
  390. package/rcf/code-nodes/cn-121.json +12 -0
  391. package/rcf/code-nodes/cn-122.json +12 -0
  392. package/rcf/code-nodes/cn-123.json +13 -0
  393. package/rcf/code-nodes/cn-124.json +13 -0
  394. package/rcf/code-nodes/cn-125.json +13 -0
  395. package/rcf/code-nodes/cn-126.json +13 -0
  396. package/rcf/code-nodes/cn-127.json +12 -0
  397. package/rcf/code-nodes/cn-128.json +14 -0
  398. package/rcf/code-nodes/cn-129.json +14 -0
  399. package/rcf/code-nodes/cn-130.json +14 -0
  400. package/rcf/code-nodes/cn-131.json +15 -0
  401. package/rcf/code-nodes/cn-132.json +12 -0
  402. package/rcf/code-nodes/cn-133.json +13 -0
  403. package/rcf/code-nodes/cn-134.json +13 -0
  404. package/rcf/code-nodes/cn-135.json +12 -0
  405. package/rcf/code-nodes/cn-136.json +13 -0
  406. package/rcf/code-nodes/cn-137.json +13 -0
  407. package/rcf/code-nodes/cn-138.json +12 -0
  408. package/rcf/code-nodes/cn-139.json +12 -0
  409. package/rcf/code-nodes/cn-140.json +13 -0
  410. package/rcf/code-nodes/cn-141.json +13 -0
  411. package/rcf/code-nodes/cn-142.json +12 -0
  412. package/rcf/code-nodes/cn-143.json +13 -0
  413. package/rcf/code-nodes/cn-144.json +13 -0
  414. package/rcf/code-nodes/cn-145.json +12 -0
  415. package/rcf/code-nodes/cn-146.json +12 -0
  416. package/rcf/code-nodes/cn-147.json +13 -0
  417. package/rcf/code-nodes/cn-148.json +13 -0
  418. package/rcf/code-nodes/cn-149.json +12 -0
  419. package/rcf/code-nodes/cn-150.json +13 -0
  420. package/rcf/code-nodes/cn-151.json +13 -0
  421. package/rcf/code-nodes/cn-152.json +12 -0
  422. package/rcf/code-nodes/cn-153.json +12 -0
  423. package/rcf/code-nodes/cn-154.json +13 -0
  424. package/rcf/code-nodes/cn-155.json +14 -0
  425. package/rcf/code-nodes/cn-156.json +13 -0
  426. package/rcf/code-nodes/cn-157.json +13 -0
  427. package/rcf/code-nodes/cn-158.json +12 -0
  428. package/rcf/code-nodes/cn-159.json +13 -0
  429. package/rcf/code-nodes/cn-160.json +12 -0
  430. package/rcf/code-nodes/cn-161.json +12 -0
  431. package/rcf/code-nodes/cn-162.json +13 -0
  432. package/rcf/code-nodes/cn-163.json +12 -0
  433. package/rcf/code-nodes/cn-164.json +13 -0
  434. package/rcf/code-nodes/cn-165.json +12 -0
  435. package/rcf/code-nodes/cn-166.json +12 -0
  436. package/rcf/code-nodes/cn-167.json +12 -0
  437. package/rcf/code-nodes/cn-168.json +12 -0
  438. package/rcf/code-nodes/cn-169.json +12 -0
  439. package/rcf/code-nodes/cn-170.json +12 -0
  440. package/rcf/code-nodes/cn-171.json +12 -0
  441. package/rcf/code-nodes/cn-172.json +12 -0
  442. package/rcf/code-nodes/cn-173.json +12 -0
  443. package/rcf/code-nodes/cn-174.json +12 -0
  444. package/rcf/code-nodes/cn-175.json +13 -0
  445. package/rcf/code-nodes/cn-176.json +12 -0
  446. package/rcf/code-nodes/cn-177.json +12 -0
  447. package/rcf/code-nodes/cn-178.json +12 -0
  448. package/rcf/code-nodes/cn-179.json +12 -0
  449. package/rcf/code-nodes/cn-180.json +13 -0
  450. package/rcf/code-nodes/cn-181.json +12 -0
  451. package/rcf/code-nodes/cn-182.json +13 -0
  452. package/rcf/code-nodes/cn-183.json +12 -0
  453. package/rcf/code-nodes/cn-184.json +13 -0
  454. package/rcf/code-nodes/cn-185.json +12 -0
  455. package/rcf/code-nodes/cn-186.json +12 -0
  456. package/rcf/code-nodes/cn-200.json +14 -0
  457. package/rcf/code-nodes/cn-201.json +13 -0
  458. package/rcf/code-nodes/cn-202.json +14 -0
  459. package/rcf/code-nodes/cn-203.json +14 -0
  460. package/rcf/code-nodes/cn-204.json +13 -0
  461. package/rcf/code-nodes/cn-205.json +14 -0
  462. package/rcf/fbs/fbs-036.json +22 -0
  463. package/rcf/fbs/fbs-037.json +19 -0
  464. package/rcf/fbs/fbs-038.json +19 -0
  465. package/rcf/fbs/fbs-039.json +21 -0
  466. package/rcf/fbs/fbs-040.json +20 -0
  467. package/rcf/fbs/fbs-041.json +13 -0
  468. package/rcf/fbs/fbs-042.json +13 -0
  469. package/rcf/fbs/fbs-043.json +23 -0
  470. package/rcf/fbs/fbs-044.json +23 -0
  471. package/rcf/fbs/fbs-045.json +23 -0
  472. package/rcf/fbs/fbs-046.json +24 -0
  473. package/rcf/fbs/fbs-047.json +24 -0
  474. package/rcf/fbs/fbs-060.json +22 -0
  475. package/rcf/fbs/fbs-061.json +20 -0
  476. package/rcf/requirements/req-017.json +18 -0
  477. package/rcf/requirements/req-018.json +18 -0
  478. package/rcf/requirements/req-019.json +38 -0
  479. package/rcf/requirements/req-020.json +13 -0
  480. package/rcf/requirements/req-021.json +13 -0
  481. package/rcf/requirements/req-022.json +13 -0
  482. package/rcf/requirements/req-023.json +14 -0
  483. package/rcf/requirements/req-024.json +69 -0
  484. package/rcf/requirements/req-025.json +59 -0
  485. package/rcf/requirements/req-026.json +154 -0
  486. package/rcf/requirements/req-027.json +33 -0
  487. package/rcf/requirements/req-028.json +13 -0
  488. package/rcf/requirements/req-040.json +13 -0
  489. package/rcf/requirements/req-041.json +125 -0
  490. package/rcf/test-suites/ts-046.json +78 -0
  491. package/rcf/test-suites/ts-047.json +54 -0
  492. package/rcf/test-suites/ts-048.json +54 -0
  493. package/rcf/test-suites/ts-049.json +70 -0
  494. package/rcf/test-suites/ts-050.json +69 -0
  495. package/rcf/test-suites/ts-051.json +22 -0
  496. package/rcf/test-suites/ts-052.json +20 -0
  497. package/rcf/test-suites/ts-053.json +70 -0
  498. package/rcf/test-suites/ts-054.json +70 -0
  499. package/rcf/test-suites/ts-055.json +77 -0
  500. package/rcf/test-suites/ts-056.json +78 -0
  501. package/rcf/test-suites/ts-057.json +78 -0
  502. package/rcf/test-suites/ts-070.json +62 -0
  503. package/rcf/test-suites/ts-071.json +62 -0
  504. package/rcf/user-stories/us-1701.json +56 -0
  505. package/rcf/user-stories/us-1801.json +40 -0
  506. package/rcf/user-stories/us-1901.json +40 -0
  507. package/rcf/user-stories/us-2001.json +50 -0
  508. package/rcf/user-stories/us-2101.json +45 -0
  509. package/rcf/user-stories/us-2201.json +60 -0
  510. package/rcf/user-stories/us-2301.json +51 -0
  511. package/rcf/user-stories/us-2401.json +62 -0
  512. package/rcf/user-stories/us-2501.json +58 -0
  513. package/rcf/user-stories/us-2601.json +51 -0
  514. package/rcf/user-stories/us-2701.json +55 -0
  515. package/rcf/user-stories/us-2801.json +55 -0
  516. package/rcf/user-stories/us-4001.json +69 -0
  517. package/rcf/user-stories/us-4101.json +69 -0
  518. package/releases/releases.yaml +21 -1
  519. package/src/blueprint/apply.js +107 -1
  520. package/src/blueprint/capabilities.js +357 -0
  521. package/src/blueprint/loader.js +247 -0
  522. package/src/browser-verify/boot.js +180 -0
  523. package/src/browser-verify/index.js +13 -0
  524. package/src/browser-verify/manifest-writer.js +31 -6
  525. package/src/browser-verify/pack-browser.js +294 -0
  526. package/src/browser-verify/pack-loader.js +176 -0
  527. package/src/browser-verify/pack-runner.js +193 -0
  528. package/src/browser-verify/pack-schema.js +155 -0
  529. package/src/browser-verify/runner.js +24 -1
  530. package/src/cli/blueprint.js +99 -0
  531. package/src/cli/browser-verify.js +147 -7
  532. package/src/core/errors/index.js +7 -0
@@ -0,0 +1,231 @@
1
+ // application-onboarding-tour probe pack (v1.0.0).
2
+ //
3
+ // Four surface-observable checks anchored to the blueprint AC ids:
4
+ // AC-26101-1 step-container focus lifecycle and Escape (drives the tour open,
5
+ // asserts the first step renders, walks Tab through the tour
6
+ // controls, presses Escape, asserts dismissal)
7
+ // AC-26102-1 tooltip-as-dialog contract (opens a step, reads the DOM, asserts
8
+ // role="dialog" and aria-labelledby; asserts focus moves to the
9
+ // tooltip on open; asserts focus is not obscured at breakpoints
10
+ // 1440 and 360 via the browser.resize seam)
11
+ // AC-26103-1 checklist slot (asserts the checklist renders inside <details open>
12
+ // on the dashboard-top anchor when application-dashboard is applied
13
+ // and inside a <details> closed on the settings-page anchor when not)
14
+ // AC-26104-1 completion-state persistence (completes the tour, reads the
15
+ // completion-state store per the elicited shape, activates restart
16
+ // from the settings surface, asserts the tour re-opens)
17
+ //
18
+ // Every check drives the real Playwright browser the T-0 runner injects and
19
+ // reads its per-check applicability from the blueprint applied sidecar
20
+ // (rcf/blueprints/application-onboarding-tour.applied.json) written by the apply
21
+ // verb. T-5 has no requiresAppliedCapabilities, but the checklist-slot check
22
+ // gates its dashboard-vs-settings branch on the applied-blueprint set
23
+ // (application-dashboard present or not), and the persistence check gates its
24
+ // backend on the elicited completion-state-store answer (with the Q4 fallback
25
+ // spa-local-storage when no persistence blueprint is applied).
26
+ //
27
+ // Sample-app fixture: packages/rcf-lite/test/fixtures/probe-pack-application-onboarding-tour/.
28
+ // The fixture ships APPS and STORE env / ?apps= / ?store= query switches
29
+ // mirroring the applied-blueprint set and the elicited completion-state store,
30
+ // plus four break switches (?break=no-role, ?break=focus-escape,
31
+ // ?break=no-collapse, ?break=no-persist) driving the negative runs.
32
+
33
+ import { readFile } from 'node:fs/promises';
34
+ import { join } from 'node:path';
35
+
36
+ async function readAppliedSidecar(projectRoot) {
37
+ if (!projectRoot) return { appliedCapabilities: [], appliedElicitations: {}, appliedBlueprints: [] };
38
+ try {
39
+ const raw = await readFile(join(projectRoot, 'rcf', 'blueprints', 'application-onboarding-tour.applied.json'), 'utf8');
40
+ const doc = JSON.parse(raw);
41
+ return {
42
+ appliedCapabilities: Array.isArray(doc.appliedCapabilities) ? doc.appliedCapabilities.slice() : [],
43
+ appliedElicitations: typeof doc.appliedElicitations === 'object' && doc.appliedElicitations ? doc.appliedElicitations : {},
44
+ appliedBlueprints: Array.isArray(doc.appliedBlueprints) ? doc.appliedBlueprints.slice() : [],
45
+ };
46
+ } catch {
47
+ return { appliedCapabilities: [], appliedElicitations: {}, appliedBlueprints: [] };
48
+ }
49
+ }
50
+
51
+ function withUrl(runtimeUrl, path) {
52
+ return new URL(path, runtimeUrl).toString();
53
+ }
54
+
55
+ function appsQuery(sidecar) {
56
+ // The sidecar's appliedBlueprints[] is the truth; on a fixture where the
57
+ // sidecar is absent (a bare test run) the fixture defaults route through
58
+ // the ?apps= query so the check still runs against the honest branch.
59
+ return sidecar.appliedBlueprints.join(',');
60
+ }
61
+
62
+ export default {
63
+ packName: 'application-onboarding-tour',
64
+ version: '1.0.0',
65
+ blueprintSlug: 'application-onboarding-tour',
66
+ // Applies to any FBS that realises the step-runner TAC or whose navModel
67
+ // routes match the operator-configured tour-anchor path glob (any /tour,
68
+ // /welcome, /getting-started, /onboarding path is a legal anchor).
69
+ appliesTo: ({ fbs }) => {
70
+ const routes = fbs?.designStage?.navModel?.routes ?? [];
71
+ const tacIds = fbs?.contextRequirements?.tacIds ?? [];
72
+ if (tacIds.includes('TAC-2701-application-onboarding-tour-step-runner')) return true;
73
+ return routes.some((r) => typeof r?.path === 'string' && /\/(tour|welcome|getting-started|onboarding)(\/|$)/.test(r.path));
74
+ },
75
+ boot: { bootCommand: null, waitForUrl: null, waitForSelector: null },
76
+ checks: [
77
+ {
78
+ id: 'AC-26101-1',
79
+ severity: 'block',
80
+ description: 'Step-container focus lifecycle: the tour opens the first step on a first-run principal, Tab reaches every tour control inside the tooltip in DOM order without escaping to the underlying surface, and Escape dismisses the tour and returns focus to the anchor (WCAG 2.1.1 Keyboard, 2.1.2 No Keyboard Trap, 2.4.3 Focus Order)',
81
+ appliesTo: async () => true,
82
+ run: async ({ browser, runtimeUrl, projectRoot }) => {
83
+ if (!browser) return { verdict: 'fail', detail: 'no packBrowser wired' };
84
+ const sidecar = await readAppliedSidecar(projectRoot);
85
+ const apps = appsQuery(sidecar);
86
+ await browser.goto(withUrl(runtimeUrl, `/tour?first-run=1&apps=${encodeURIComponent(apps)}`));
87
+ const open = await browser.evaluate(() => {
88
+ const tip = document.querySelector('[data-role="onboarding-tour-tooltip"]');
89
+ if (!tip) return { present: false };
90
+ const role = tip.getAttribute('role');
91
+ const step = tip.getAttribute('data-step-id');
92
+ const controls = Array.from(tip.querySelectorAll('[data-tour-control]')).map((c) => c.getAttribute('data-tour-control'));
93
+ const focusInside = tip.contains(document.activeElement);
94
+ return { present: true, role, step, controls, focusInside };
95
+ });
96
+ if (!open.present) return { verdict: 'fail', detail: 'onboarding tooltip [data-role="onboarding-tour-tooltip"] not rendered on first run' };
97
+ if (open.role !== 'dialog') return { verdict: 'fail', detail: `tooltip role expected dialog, got ${open.role}` };
98
+ if (!open.focusInside) return { verdict: 'fail', detail: 'focus did not move into the tooltip on open' };
99
+ const requiredControls = ['previous', 'next', 'dismiss'];
100
+ const missingControls = requiredControls.filter((c) => !open.controls.includes(c));
101
+ if (missingControls.length > 0) return { verdict: 'fail', detail: `tooltip missing tour controls: ${JSON.stringify(missingControls)} present=${JSON.stringify(open.controls)}` };
102
+ // Walk Tab across every control; refuse if focus escapes the tooltip.
103
+ for (let i = 0; i < open.controls.length + 1; i += 1) {
104
+ await browser.press('Tab');
105
+ }
106
+ const walk = await browser.evaluate(() => {
107
+ const tip = document.querySelector('[data-role="onboarding-tour-tooltip"]');
108
+ return { focusInside: tip ? tip.contains(document.activeElement) : false };
109
+ });
110
+ if (!walk.focusInside) return { verdict: 'fail', detail: 'Tab traversal escaped the tooltip (focus trap failed)' };
111
+ await browser.press('Escape');
112
+ const closed = await browser.evaluate(() => {
113
+ const tip = document.querySelector('[data-role="onboarding-tour-tooltip"]');
114
+ return { present: !!tip };
115
+ });
116
+ if (closed.present) return { verdict: 'fail', detail: 'tooltip still present after Escape (dismiss did not fire)' };
117
+ return { verdict: 'pass', detail: `step=${open.step} controls=${JSON.stringify(open.controls)} focus trapped and Escape dismissed cleanly` };
118
+ },
119
+ },
120
+ {
121
+ id: 'AC-26102-1',
122
+ severity: 'block',
123
+ description: 'Tooltip-as-dialog contract per the ARIA APG dialog-modal pattern: role="dialog", aria-labelledby to the step heading, aria-describedby to the step body, focus moves in on open, focus not obscured at the 1440 wide and 360 narrow breakpoints (WCAG 2.4.11 Focus Not Obscured Minimum)',
124
+ appliesTo: async () => true,
125
+ run: async ({ browser, runtimeUrl, projectRoot }) => {
126
+ if (!browser) return { verdict: 'fail', detail: 'no packBrowser wired' };
127
+ const sidecar = await readAppliedSidecar(projectRoot);
128
+ const apps = appsQuery(sidecar);
129
+ // Wide breakpoint first.
130
+ await browser.resize(1440, 900);
131
+ await browser.goto(withUrl(runtimeUrl, `/tour?first-run=1&apps=${encodeURIComponent(apps)}`));
132
+ const wide = await browser.evaluate(() => {
133
+ const tip = document.querySelector('[data-role="onboarding-tour-tooltip"]');
134
+ if (!tip) return { present: false };
135
+ const headingId = tip.getAttribute('aria-labelledby');
136
+ const bodyId = tip.getAttribute('aria-describedby');
137
+ const headingEl = headingId ? document.getElementById(headingId) : null;
138
+ const bodyEl = bodyId ? document.getElementById(bodyId) : null;
139
+ const rect = tip.getBoundingClientRect();
140
+ const inViewport = rect.top >= 0 && rect.left >= 0 && rect.bottom <= window.innerHeight && rect.right <= window.innerWidth;
141
+ return { present: true, role: tip.getAttribute('role'), headingId, bodyId, headingText: headingEl ? headingEl.textContent : null, bodyText: bodyEl ? bodyEl.textContent : null, inViewport, rect: { top: rect.top, left: rect.left, right: rect.right, bottom: rect.bottom }, viewport: { w: window.innerWidth, h: window.innerHeight } };
142
+ });
143
+ if (!wide.present) return { verdict: 'fail', detail: 'tooltip not rendered at 1440x900' };
144
+ if (wide.role !== 'dialog') return { verdict: 'fail', detail: `tooltip role expected dialog at 1440, got ${wide.role}` };
145
+ if (!wide.headingId || !wide.headingText) return { verdict: 'fail', detail: `tooltip aria-labelledby ("${wide.headingId}") does not point at a live heading element` };
146
+ if (!wide.bodyId || !wide.bodyText) return { verdict: 'fail', detail: `tooltip aria-describedby ("${wide.bodyId}") does not point at a live body element` };
147
+ if (!wide.inViewport) return { verdict: 'fail', detail: `tooltip focus obscured at 1440x900: rect=${JSON.stringify(wide.rect)} viewport=${JSON.stringify(wide.viewport)}` };
148
+ // Narrow breakpoint.
149
+ await browser.resize(360, 640);
150
+ await browser.goto(withUrl(runtimeUrl, `/tour?first-run=1&apps=${encodeURIComponent(apps)}`));
151
+ const narrow = await browser.evaluate(() => {
152
+ const tip = document.querySelector('[data-role="onboarding-tour-tooltip"]');
153
+ if (!tip) return { present: false };
154
+ const rect = tip.getBoundingClientRect();
155
+ const inViewport = rect.top >= 0 && rect.left >= 0 && rect.bottom <= window.innerHeight && rect.right <= window.innerWidth;
156
+ return { present: true, rect: { top: rect.top, left: rect.left, right: rect.right, bottom: rect.bottom }, viewport: { w: window.innerWidth, h: window.innerHeight }, inViewport };
157
+ });
158
+ if (!narrow.present) return { verdict: 'fail', detail: 'tooltip not rendered at 360x640' };
159
+ if (!narrow.inViewport) return { verdict: 'fail', detail: `tooltip focus obscured at 360x640: rect=${JSON.stringify(narrow.rect)} viewport=${JSON.stringify(narrow.viewport)}` };
160
+ return { verdict: 'pass', detail: `dialog contract clean at 1440 and 360; aria-labelledby="${wide.headingId}" aria-describedby="${wide.bodyId}"` };
161
+ },
162
+ },
163
+ {
164
+ id: 'AC-26103-1',
165
+ severity: 'block',
166
+ description: 'Checklist slot: renders inside <details open> on the dashboard-top anchor when application-dashboard is applied, and inside <details> (closed) on the settings-page anchor when not; both branches carry data-role="onboarding-tour-checklist"',
167
+ appliesTo: async () => true,
168
+ run: async ({ browser, runtimeUrl, projectRoot }) => {
169
+ if (!browser) return { verdict: 'fail', detail: 'no packBrowser wired' };
170
+ const sidecar = await readAppliedSidecar(projectRoot);
171
+ const apps = appsQuery(sidecar);
172
+ const dashboardApplied = sidecar.appliedBlueprints.includes('application-dashboard');
173
+ const targetPath = dashboardApplied ? '/dashboard' : '/settings';
174
+ await browser.goto(withUrl(runtimeUrl, `${targetPath}?apps=${encodeURIComponent(apps)}`));
175
+ const dom = await browser.evaluate((expectedAnchor) => {
176
+ const checklist = document.querySelector('details[data-role="onboarding-tour-checklist"]');
177
+ if (!checklist) return { present: false };
178
+ const isOpen = checklist.hasAttribute('open');
179
+ const anchor = checklist.getAttribute('data-anchor');
180
+ const items = Array.from(checklist.querySelectorAll('[data-checklist-item]')).map((el) => el.getAttribute('data-checklist-item'));
181
+ return { present: true, isOpen, anchor, items, expectedAnchor };
182
+ }, dashboardApplied ? 'dashboard-top' : 'settings-page');
183
+ if (!dom.present) return { verdict: 'fail', detail: `details[data-role="onboarding-tour-checklist"] not found at ${targetPath} (apps=${apps})` };
184
+ if (dashboardApplied && !dom.isOpen) return { verdict: 'fail', detail: `checklist on dashboard-top anchor is not <details open> (anchor="${dom.anchor}")` };
185
+ if (!dashboardApplied && dom.isOpen) return { verdict: 'fail', detail: `checklist on settings-page anchor rendered <details open> but should default closed (anchor="${dom.anchor}")` };
186
+ if (dom.anchor !== dom.expectedAnchor) return { verdict: 'fail', detail: `data-anchor expected "${dom.expectedAnchor}", got "${dom.anchor}"` };
187
+ return { verdict: 'pass', detail: `anchor=${dom.anchor} open=${dom.isOpen} items=${JSON.stringify(dom.items)} (dashboardApplied=${dashboardApplied})` };
188
+ },
189
+ },
190
+ {
191
+ id: 'AC-26104-1',
192
+ severity: 'block',
193
+ description: 'Completion-state persistence: completing the tour writes to the elicited completion-state store (spa-local-storage per the Q4 fallback when no persistence blueprint is applied; spa-session-storage or server-side-per-principal per the elicit); the restart-tour control on the settings surface clears the record and re-opens the tour on the next principal load',
194
+ appliesTo: async () => true,
195
+ run: async ({ browser, runtimeUrl, projectRoot }) => {
196
+ if (!browser) return { verdict: 'fail', detail: 'no packBrowser wired' };
197
+ const sidecar = await readAppliedSidecar(projectRoot);
198
+ const apps = appsQuery(sidecar);
199
+ const store = sidecar.appliedElicitations['completion-state-store'] || 'spa-local-storage';
200
+ await browser.goto(withUrl(runtimeUrl, `/tour?first-run=1&apps=${encodeURIComponent(apps)}&store=${encodeURIComponent(store)}&complete=1`));
201
+ const afterComplete = await browser.evaluate((s) => {
202
+ const marker = document.querySelector('[data-role="onboarding-tour-completion-marker"]');
203
+ const writtenAttr = marker ? marker.getAttribute('data-written-to') : null;
204
+ const key = 'onboarding-tour:completion';
205
+ let readBack = null;
206
+ try {
207
+ if (s === 'spa-local-storage') readBack = window.localStorage.getItem(key);
208
+ else if (s === 'spa-session-storage') readBack = window.sessionStorage.getItem(key);
209
+ } catch (e) {
210
+ readBack = `storage-error: ${e.message}`;
211
+ }
212
+ return { markerPresent: !!marker, writtenAttr, readBack };
213
+ }, store);
214
+ if (!afterComplete.markerPresent) return { verdict: 'fail', detail: `completion marker [data-role="onboarding-tour-completion-marker"] not present after complete flow (store=${store})` };
215
+ if (afterComplete.writtenAttr !== store) return { verdict: 'fail', detail: `completion marker data-written-to expected "${store}", got "${afterComplete.writtenAttr}"` };
216
+ if ((store === 'spa-local-storage' || store === 'spa-session-storage') && !afterComplete.readBack) {
217
+ return { verdict: 'fail', detail: `store "${store}" reports no persisted record under key onboarding-tour:completion` };
218
+ }
219
+ // Drive the restart control.
220
+ await browser.goto(withUrl(runtimeUrl, `/settings?apps=${encodeURIComponent(apps)}&store=${encodeURIComponent(store)}`));
221
+ const restartBtn = await browser.evaluate(() => !!document.querySelector('button[data-action="restart-tour"]'));
222
+ if (!restartBtn) return { verdict: 'fail', detail: 'restart-tour control not reachable on settings surface' };
223
+ await browser.click('button[data-action="restart-tour"]');
224
+ await browser.goto(withUrl(runtimeUrl, `/tour?apps=${encodeURIComponent(apps)}&store=${encodeURIComponent(store)}`));
225
+ const reopen = await browser.evaluate(() => !!document.querySelector('[data-role="onboarding-tour-tooltip"]'));
226
+ if (!reopen) return { verdict: 'fail', detail: 'tour did not re-open on the highest-value surface after restart' };
227
+ return { verdict: 'pass', detail: `store=${store} completion persisted, restart cleared, tour re-opened` };
228
+ },
229
+ },
230
+ ],
231
+ };
@@ -34,7 +34,7 @@ This table is maintained shelf-wide across every blueprint's `docs/topics.md`. R
34
34
  | persistence-data-sqlite | 5101-5899 | 6xx | shipped v1.0.0 | `persistenceStore`, `migrationDiscipline` |
35
35
  | delivery-ci-workflows | 6101-6899 | 7xx | shipped v2.0.0 (renamed from ci-pipeline) | `ciGates`, `strictCoverageGate`, `releaseArtefacts` |
36
36
  | observability-essentials | 7101-7899 | 8xx | shipped v2.0.0 | `statusPageContract` |
37
- | security-secrets-management | 8101-8899 | 9xx | shipped v1.0.0 | `secretsSource` |
37
+ | security-secrets-management | 8101-8899 | 9xx | shipped v1.0.1 | `secretsSource` |
38
38
  | security-auth-clerk | 9101-9899 | 10xx | shipped v1.0.0 | `authModel` |
39
39
  | security-auth-oauth2 | 10101-10899 | 11xx | shipped v1.0.0 | `authModel` |
40
40
  | security-auth-keycloak | 11101-11899 | 12xx | shipped v1.0.0 | `authModel` |
@@ -43,6 +43,18 @@ This table is maintained shelf-wide across every blueprint's `docs/topics.md`. R
43
43
  | observability-probe-endpoints | 14101-14899 | 15xx | shipped v1.1.0 | `healthProbes`, `readinessSemantics` |
44
44
  | observability-logging | 15101-15899 | 16xx | shipped v1.0.0 | `logging` |
45
45
  | application-error-handling | 16101-16899 | 17xx | shipped v1.0.0 | `errorHandling` |
46
+ | application-datatable | 17101-17899 | 18xx | shipped v1.0.0 | none |
47
+ | application-charts | 18101-18899 | 19xx | shipped v1.0.0 | none |
48
+ | application-dashboard | 19101-19899 | 20xx | shipped v1.0.0 | none |
49
+ | application-notifications-in-app | 20101-20899 | 21xx | shipped v1.0.0 | none |
50
+ | application-admin-console | 21101-21899 | 22xx | shipped v1.0.0 | none |
51
+ | application-empty-error-states | 22101-22899 | 23xx | shipped v1.0.0 | none |
52
+ | application-file-upload | 23101-23899 | 24xx | shipped v1.0.0 | none |
53
+ | application-forms-wizard | 24101-24899 | 25xx | shipped v1.0.0 | none |
54
+ | application-account-settings | 25101-25899 | 26xx | shipped v1.0.0 | none |
55
+ | application-onboarding-tour | 26101-26899 | 27xx | shipped v1.0.0 | none |
56
+ | persistence-data-postgres | 27101-27899 | 28xx | shipped v1.0.0 | `persistenceStore`, `migrationDiscipline` |
57
+ | object-storage-s3 | 28101-28899 | 29xx | shipped v1.0.0 | `objectStorageContract` |
46
58
 
47
59
  SPA v1.1.0 stays on the LOW end of its band: v1.0.0 occupied US-1101 through US-1128; v1.1.0 adds US-1129 and US-1130, leaving headroom above 1130 for future minor bumps and for project-side stories that mechanically derive to the 11xx numeric range.
48
60
 
@@ -42,13 +42,25 @@ This table is maintained shelf-wide across every blueprint's `docs/topics.md`. R
42
42
  | persistence-data-sqlite | 5101-5899 | 6xx | shipped v1.0.0 | `persistenceStore`, `migrationDiscipline` |
43
43
  | delivery-ci-workflows | 6101-6899 | 7xx | shipped v2.0.0 (renamed from ci-pipeline) | `ciGates`, `strictCoverageGate`, `releaseArtefacts` |
44
44
  | observability-essentials | 7101-7899 | 8xx | shipped v2.0.0 | `statusPageContract` |
45
- | security-secrets-management | 8101-8899 | 9xx | shipped v1.0.0 | `secretsSource` |
45
+ | security-secrets-management | 8101-8899 | 9xx | shipped v1.0.1 | `secretsSource` |
46
46
  | security-auth-clerk | 9101-9899 | 10xx | shipped v1.0.0 | `authModel` |
47
47
  | security-auth-oauth2 | 10101-10899 | 11xx | shipped v1.0.0 | `authModel` |
48
48
  | security-auth-keycloak | 11101-11899 | 12xx | shipped v1.0.0 | `authModel` |
49
49
  | deploy-cloudflare-workers | 12101-12899 | 13xx | shipped v1.0.0 | `deploymentTarget` |
50
50
  | persistence-data-d1 | 13101-13899 | 14xx | shipped v1.0.0 | `persistenceStore`, `migrationDiscipline` |
51
51
  | observability-probe-endpoints | 14101-14899 | 15xx | shipped v1.1.0 | `healthProbes`, `readinessSemantics` |
52
+ | application-datatable | 17101-17899 | 18xx | shipped v1.0.0 | none |
53
+ | application-charts | 18101-18899 | 19xx | shipped v1.0.0 | none |
54
+ | application-dashboard | 19101-19899 | 20xx | shipped v1.0.0 | none |
55
+ | application-notifications-in-app | 20101-20899 | 21xx | shipped v1.0.0 | none |
56
+ | application-admin-console | 21101-21899 | 22xx | shipped v1.0.0 | none |
57
+ | application-empty-error-states | 22101-22899 | 23xx | shipped v1.0.0 | none |
58
+ | application-file-upload | 23101-23899 | 24xx | shipped v1.0.0 | none |
59
+ | application-forms-wizard | 24101-24899 | 25xx | shipped v1.0.0 | none |
60
+ | application-account-settings | 25101-25899 | 26xx | shipped v1.0.0 | none |
61
+ | application-onboarding-tour | 26101-26899 | 27xx | shipped v1.0.0 | none |
62
+ | persistence-data-postgres | 27101-27899 | 28xx | shipped v1.0.0 | `persistenceStore`, `migrationDiscipline` |
63
+ | object-storage-s3 | 28101-28899 | 29xx | shipped v1.0.0 | `objectStorageContract` |
52
64
 
53
65
  US 6101-6110 sit at the LOW end of the 6101-6899 band on purpose. A project-side story that mechanically derives from `delivery-ci-workflows-REQ-011` into the number `6111` would collide against delivery-ci-workflows-US-6111 in this package; the band leaves headroom at the HIGH end (US 6181-6899) so a project's own stories anchored to delivery-ci-workflows REQs can allocate without conflict. The watchpost run4 lesson applies here too.
54
66
 
@@ -28,13 +28,25 @@ This table is maintained shelf-wide across every blueprint's `docs/topics.md`. R
28
28
  | persistence-data-sqlite | 5101-5899 | 6xx | shipped v1.0.0 | `persistenceStore`, `migrationDiscipline` |
29
29
  | delivery-ci-workflows | 6101-6899 | 7xx | shipped v2.0.0 (renamed from ci-pipeline) | `ciGates`, `strictCoverageGate`, `releaseArtefacts` |
30
30
  | observability-essentials | 7101-7899 | 8xx | shipped v2.0.0 | `statusPageContract` |
31
- | security-secrets-management | 8101-8899 | 9xx | shipped v1.0.0 | `secretsSource` |
31
+ | security-secrets-management | 8101-8899 | 9xx | shipped v1.0.1 | `secretsSource` |
32
32
  | security-auth-clerk | 9101-9899 | 10xx | shipped v1.0.0 | `authModel` |
33
33
  | security-auth-oauth2 | 10101-10899 | 11xx | shipped v1.0.0 | `authModel` |
34
34
  | security-auth-keycloak | 11101-11899 | 12xx | shipped v1.0.0 | `authModel` |
35
35
  | deploy-cloudflare-workers | 12101-12899 | 13xx | shipped v1.0.0 | `deploymentTarget` |
36
36
  | persistence-data-d1 | 13101-13899 | 14xx | shipped v1.0.0 | `persistenceStore`, `migrationDiscipline` |
37
37
  | observability-probe-endpoints | 14101-14899 | 15xx | shipped v1.1.0 | `healthProbes`, `readinessSemantics` |
38
+ | application-datatable | 17101-17899 | 18xx | shipped v1.0.0 | none |
39
+ | application-charts | 18101-18899 | 19xx | shipped v1.0.0 | none |
40
+ | application-dashboard | 19101-19899 | 20xx | shipped v1.0.0 | none |
41
+ | application-notifications-in-app | 20101-20899 | 21xx | shipped v1.0.0 | none |
42
+ | application-admin-console | 21101-21899 | 22xx | shipped v1.0.0 | none |
43
+ | application-empty-error-states | 22101-22899 | 23xx | shipped v1.0.0 | none |
44
+ | application-file-upload | 23101-23899 | 24xx | shipped v1.0.0 | none |
45
+ | application-forms-wizard | 24101-24899 | 25xx | shipped v1.0.0 | none |
46
+ | application-account-settings | 25101-25899 | 26xx | shipped v1.0.0 | none |
47
+ | application-onboarding-tour | 26101-26899 | 27xx | shipped v1.0.0 | none |
48
+ | persistence-data-postgres | 27101-27899 | 28xx | shipped v1.0.0 | `persistenceStore`, `migrationDiscipline` |
49
+ | object-storage-s3 | 28101-28899 | 29xx | shipped v1.0.0 | `objectStorageContract` |
38
50
 
39
51
  US 12101-12112 sit at the LOW end of the 12101-12899 band on purpose. A project-side story that mechanically derives from a deploy-cloudflare-workers REQ id into the number `12112` would collide against deploy-cloudflare-workers-US-12112 in this package; the band leaves headroom at the HIGH end (US 12181-12899) so a project's own stories anchored to deploy-cloudflare-workers REQs can allocate without conflict. The watchpost run4 lesson applies here too. Band spacing between the last shipped block (security-secrets-management, 8101-8899, 9xx) and this one (12101-12899, 13xx) leaves the 9xxx-11xxx US bands and the 10xx-12xx suffix blocks open for concurrent-lane authoring so a peer authoring another blueprint in the same PR window does not collide with this one.
40
52
 
@@ -24,13 +24,25 @@ This table is maintained shelf-wide across every blueprint's `docs/topics.md`. R
24
24
  | persistence-data-sqlite | 5101-5899 | 6xx | shipped v1.0.0 | `persistenceStore`, `migrationDiscipline` |
25
25
  | delivery-ci-workflows | 6101-6899 | 7xx | shipped v2.0.0 (renamed from ci-pipeline) | `ciGates`, `strictCoverageGate`, `releaseArtefacts` |
26
26
  | observability-essentials | 7101-7899 | 8xx | shipped v2.0.0 | `statusPageContract` |
27
- | security-secrets-management | 8101-8899 | 9xx | shipped v1.0.0 | `secretsSource` |
27
+ | security-secrets-management | 8101-8899 | 9xx | shipped v1.0.1 | `secretsSource` |
28
28
  | security-auth-clerk | 9101-9899 | 10xx | shipped v1.0.0 | `authModel` |
29
29
  | security-auth-oauth2 | 10101-10899 | 11xx | shipped v1.0.0 | `authModel` |
30
30
  | security-auth-keycloak | 11101-11899 | 12xx | shipped v1.0.0 | `authModel` |
31
31
  | deploy-cloudflare-workers | 12101-12899 | 13xx | shipped v1.0.0 | `deploymentTarget` |
32
32
  | persistence-data-d1 | 13101-13899 | 14xx | shipped v1.0.0 | `persistenceStore`, `migrationDiscipline` |
33
33
  | observability-probe-endpoints | 14101-14899 | 15xx | shipped v1.1.0 | `healthProbes`, `readinessSemantics` |
34
+ | application-datatable | 17101-17899 | 18xx | shipped v1.0.0 | none |
35
+ | application-charts | 18101-18899 | 19xx | shipped v1.0.0 | none |
36
+ | application-dashboard | 19101-19899 | 20xx | shipped v1.0.0 | none |
37
+ | application-notifications-in-app | 20101-20899 | 21xx | shipped v1.0.0 | none |
38
+ | application-admin-console | 21101-21899 | 22xx | shipped v1.0.0 | none |
39
+ | application-empty-error-states | 22101-22899 | 23xx | shipped v1.0.0 | none |
40
+ | application-file-upload | 23101-23899 | 24xx | shipped v1.0.0 | none |
41
+ | application-forms-wizard | 24101-24899 | 25xx | shipped v1.0.0 | none |
42
+ | application-account-settings | 25101-25899 | 26xx | shipped v1.0.0 | none |
43
+ | application-onboarding-tour | 26101-26899 | 27xx | shipped v1.0.0 | none |
44
+ | persistence-data-postgres | 27101-27899 | 28xx | shipped v1.0.0 | `persistenceStore`, `migrationDiscipline` |
45
+ | object-storage-s3 | 28101-28899 | 29xx | shipped v1.0.0 | `objectStorageContract` |
34
46
 
35
47
  US 4101-4106 sit at the LOW end of the 4101-4899 band on purpose. A project-side story that mechanically derives from an email-smtp-resend REQ id into the number `4106` (leading `4` + sequence `106`) would collide against email-smtp-resend-US-4106 in this package; the band leaves headroom at the HIGH end (US 4181-4899) so a project's own stories anchored to email-smtp-resend REQs can allocate without conflict. The watchpost run4 lesson applies here too.
36
48
 
@@ -0,0 +1,13 @@
1
+ # object-storage-s3 changelog
2
+
3
+ ## 1.0.0 - 2026-09-06
4
+
5
+ Initial release. Contract for S3-shape object storage on any S3-compatible endpoint (Cloudflare R2 first, MinIO for local dev, AWS S3, Backblaze B2, Wasabi, self-hosted). Accessed through a store facade that is the sole reader of the S3 client (`@aws-sdk/client-s3` on Node targets or `aws4fetch` on Workers targets). Landed via the infra round 5 spec (ratified 2026-09-06) as track T-2.
6
+
7
+ - 21 contributions: 6 REQs on facade sole-reader / put-get-delete-list / presigned URL / multipart / lifecycle events / credential-pair discipline; 8 USs at 28101-28108; 3 TACs (2901 facade, 2902 multipart uploader, 2903 event sink); 4 ADRs (2901 adapter elicited between AWS SDK and aws4fetch, 2902 presigned TTL default 15 minutes floor 1 minute, 2903 multipart threshold default 8 MiB, 2904 objectStorageContract with scope global).
8
+ - Six Node-only probes under `contributions/probes/` proven against a live MinIO container: `facade-round-trip`, `put-get-round-trip`, `presigned-url`, `multipart-upload`, `event-secrecy`, and the accountBound `r2-real-account-smoke`. The R2 smoke records `accountBoundSkipped: true` when `CI_HAS_CLOUDFLARE_ACCOUNT` is unset per spec section 3.5.
9
+ - T-2 slice of the shared sample-app fixture at `packages/rcf-lite/test/fixtures/infra-s3-and-queue/` boots MinIO via docker compose, exposes the facade over `@aws-sdk/client-s3`, ships a security-secrets-management shim realising the `secretRef` opaque-string contract, and hosts four wired induced-failure switches for the negative-run paths (SIMULATE_MINIO_DOWN, SIMULATE_403_ON_GET, SIMULATE_PART_UPLOAD_FAIL, SIMULATE_PRESIGN_MALFORMED).
10
+ - Declares `capabilities: ["objectStorage"]`, `suggestedCompanions: [{role: "logging"}, {role: "errorHandling"}]`, `providesRoles` absent, `requiresAppliedCapabilities` absent.
11
+ - Contributes ADR-2904 as `scope: global` on new topic `objectStorageContract`. Future non-S3-shape siblings (`object-storage-native-gcs`, `object-storage-native-azure`, reserved slugs) conflict here by design.
12
+ - Refuses composition when `security-secrets-management` v1.0.1+ is not applied. Declares `requiresAppliedCapabilities: {capabilities: ["secretsProvider"], allowSkipFlag: "allow-no-secrets-yet", refusalMessageId: "object-storage-s3-no-secrets"}` per the T-5 capability mechanism. `rcf define blueprint add object-storage-s3` on a bare project exits 3 with `[object-storage-s3-no-secrets]` on stderr, names the shipped predecessor, and points at the override. `--allow-no-secrets-yet` records a `notes` line on `rcf/blueprints/object-storage-s3.applied.json` for later reconciliation. Companion runner extensions (added by this PR to keep the mechanism whole): `src/blueprint/capabilities.js` `buildRefusalMessage` gains a bespoke template branch for `object-storage-s3-no-secrets` (echoes the message id as the first-line tag; other refusalMessageId values also gain a `[<id>]` tag on the first line of the generic fallback for dashboards/lint); `src/cli/blueprint.js` accepts the new `--allow-no-secrets-yet` flag; `src/blueprint/apply.js` sidecar `notes` prose derives predecessor family from the `allowSkipFlag` name (auth vs secrets-management) so the note reads sensibly for either predecessor.
13
+ - Every ADR contribution entry on `blueprint.json` carries a `standardsTraceClause` per section 8a.2 (per HQ mid-flight ruling after PR #154 gate).
@@ -0,0 +1,108 @@
1
+ # object-storage-s3
2
+
3
+ Object storage on the S3 API, accessed through a store facade that is the sole reader of the S3 client. Cloudflare R2 is the first adapter, MinIO is the local dev target, any S3-compatible remote (AWS S3, Backblaze B2, Wasabi, self-hosted) composes cleanly. Ships put / get / delete / list, presigned GET URLs with a bounded TTL, and multipart-upload above an elicited threshold, plus a lifecycle-event sink with a metadata-only field discipline. Refuses composition without `security-secrets-management` applied (Baz decision 6): the credential pair is a `secretRef`, never a value.
4
+
5
+ ## What this blueprint gives you
6
+
7
+ - **A store facade** (TAC-2901) that is the sole importer of the S3 client (`@aws-sdk/client-s3` on Node targets or `aws4fetch` on Workers targets per ADR-2901) in your source tree, opens the client on boot, and exposes typed named domain verbs. Emits `facadeReady` on the first successful ready-check.
8
+ - **A multipart uploader** (TAC-2902) that the facade delegates to for payloads above the elicited threshold (default 8 MiB per ADR-2903); initiates, part-uploads, completes; aborts in-flight on any part-upload failure so no orphan multipart uploads remain on the bucket.
9
+ - **An event sink** (TAC-2903) with a metadata-only field discipline: `facadeReady`, `objectPut`, `objectDeleted`, `presignedIssued`; no body bytes, no user id, no PII drawn from the object body.
10
+ - **Six Node-only probes** proving every runtime observable: five against a real MinIO container (facade round-trip, put/get, presigned URL, multipart 10 MiB, event secrecy against a PII fixture) plus one accountBound R2 real-account smoke that skips cleanly without `CI_HAS_CLOUDFLARE_ACCOUNT`.
11
+
12
+ ## The six REQs
13
+
14
+ | REQ | What it commits |
15
+ |---|---|
16
+ | REQ-001 | Facade module is the sole reader of the S3 client; opens on boot; emits `facadeReady`. |
17
+ | REQ-002 | Put / get / delete / list contract on typed keys with `objectPut` and `objectDeleted` events. |
18
+ | REQ-003 | Presigned GET URL with bounded TTL (floor 1 minute, default 15 minutes per ADR-2902); 200 within TTL, 403 after. |
19
+ | REQ-004 | Multipart-upload above the ADR-2903 threshold (default 8 MiB); abort-on-failure with no orphan in-flight uploads. |
20
+ | REQ-005 | Four lifecycle events with metadata-only fields; event-secrecy probe asserts against a PII fixture. |
21
+ | REQ-006 | Credential-pair discipline via `security-secrets-management`; refuses composition without with stable message id `object-storage-s3-no-secrets`. |
22
+
23
+ ## The three TACs
24
+
25
+ - **TAC-2901 facade**: the object-storage S3 facade module.
26
+ - **TAC-2902 multipart uploader**: initiate/part-upload/complete with abort-on-failure.
27
+ - **TAC-2903 event sink**: metadata-only lifecycle event contract.
28
+
29
+ ## The four ADRs
30
+
31
+ - **ADR-2901 adapter**: `@aws-sdk/client-s3` on Node targets, `aws4fetch` on Workers targets; elicited, `recommendedDefault: true`. Standards trace clause: AWS S3 API and R2 S3-compatibility notes.
32
+ - **ADR-2902 presigned URL TTL**: default 15 minutes, floor 1 minute; elicited ceiling. Standards trace clause: generic enterprise practice.
33
+ - **ADR-2903 multipart threshold**: default 8 MiB, elicited. Standards trace clause: generic enterprise practice.
34
+ - **ADR-2904 object storage contract** (scope: global, topic `objectStorageContract`): S3 API as the shipped shape; conflicts by design with future non-S3-shape siblings. Standards trace clause: AWS S3 API and R2 S3-compatibility notes.
35
+
36
+ ## Elicited parameters
37
+
38
+ Endpoint URL (R2 `https://<account-id>.r2.cloudflarestorage.com`, AWS S3 `https://s3.<region>.amazonaws.com`, MinIO `http://localhost:9000`, any S3-compatible remote); bucket name; credential-pair reference via `security-secrets-management` (never value); adapter (`awsSdk` or `aws4fetch`); presigned-URL default TTL (default 15 minutes); presigned-URL ceiling (elicited, no shipped default, S3 API 7-day outer bound); multipart-upload threshold (default 8 MiB); force path style (`true` for MinIO, `false` for AWS/R2 with virtual-hosted style); server-side encryption default (`sseNone` on R2 per the R2 compatibility notes; `sseS3` on AWS S3 when the operator elicits it).
39
+
40
+ ## Companions
41
+
42
+ - **logging**: every lifecycle event (facadeReady, objectPut, objectDeleted, presignedIssued) writes through the applied logger; a logging companion supplies the factory.
43
+ - **errorHandling**: a put failure, a get 404, a presigned-URL malformed request constructs an internal error record; an error-handling companion supplies the record factory and the boundary.
44
+
45
+ ## Composition and conflicts
46
+
47
+ Consumes `security-secrets-management` v1.0.1+ for the credential pair. Declares `requiresAppliedCapabilities: {capabilities: ["secretsProvider"], allowSkipFlag: "allow-no-secrets-yet", refusalMessageId: "object-storage-s3-no-secrets"}` per the T-5 capability mechanism (visual round spec 5.5.1). The apply verb refuses on a project without `secretsProvider` (exit 3, stderr carries `[object-storage-s3-no-secrets]` as the first-line tag and names the required capability, the shipped predecessor, and the override flag). `--allow-no-secrets-yet` overrides for a scaffolding pass and records a `notes` line on `rcf/blueprints/object-storage-s3.applied.json` for later reconciliation. Contributes ADR-2904 as `scope: global` on new topic `objectStorageContract`; future `object-storage-native-gcs` or `object-storage-native-azure` siblings would conflict here by design. `capabilities: ["objectStorage"]`; `providesRoles: []`.
48
+
49
+ ## The six probes
50
+
51
+ Each probe is a Node module under `contributions/probes/` exporting the round-5 spec section 3.2 verdict envelope, with a matching `run-<probe-name>.mjs` shim that drives the probe against the shared fixture and writes the per-blueprint report at `.rcf/reports/blueprints/object-storage-s3/<probe-name>.json`.
52
+
53
+ | Probe | Anchor AC | What it proves | accountBound |
54
+ |---|---|---|---|
55
+ | `facade-round-trip` | AC-28101-1 | Facade opens against MinIO; `facadeReady` fires with endpointHost and bucketName. | false |
56
+ | `put-get-round-trip` | AC-28102-1, AC-28102-2, AC-28102-3 | 1 KiB round-trip byte-equal; delete and list round-trip; `objectPut` and `objectDeleted` fire. | false |
57
+ | `presigned-url` | AC-28103-1 | Presign at 60 s TTL returns 200 within TTL, 403 on tampered signature (or full TTL wall-clock with `SIMULATE_PRESIGN_EXPIRE=true`); floor refusal at 30 s. | false |
58
+ | `multipart-upload` | AC-28104-1, AC-28104-2 | 10 MiB payload above the 8 MiB threshold round-trips byte-equal via multipart; no orphan in-flight uploads after complete; abort-on-failure with `SIMULATE_PART_UPLOAD_FAIL=true`. | false |
59
+ | `event-secrecy` | AC-28105-1 | Every event record carries only whitelisted metadata fields; no PII fixture text; no forbidden field name. | false |
60
+ | `r2-real-account-smoke` | AC-28108-1 | Real R2 round-trip when `CI_HAS_CLOUDFLARE_ACCOUNT` is set; records `accountBoundSkipped: true` when it is not. | true |
61
+
62
+ ## How to run the probes locally
63
+
64
+ ```sh
65
+ cd packages/rcf-lite/test/fixtures/infra-s3-and-queue
66
+ docker compose up -d minio
67
+ sleep 4
68
+ npm install --silent
69
+ node src/create-bucket.mjs
70
+ node ../../../../blueprints/object-storage-s3/contributions/probes/run-facade-round-trip.mjs
71
+ node ../../../../blueprints/object-storage-s3/contributions/probes/run-put-get-round-trip.mjs
72
+ node ../../../../blueprints/object-storage-s3/contributions/probes/run-presigned-url.mjs
73
+ node ../../../../blueprints/object-storage-s3/contributions/probes/run-multipart-upload.mjs
74
+ node ../../../../blueprints/object-storage-s3/contributions/probes/run-event-secrecy.mjs
75
+ node ../../../../blueprints/object-storage-s3/contributions/probes/run-r2-real-account-smoke.mjs
76
+ docker compose down -v
77
+ ```
78
+
79
+ Each shim exits 0 on aggregate pass and 1 otherwise; every per-blueprint report at `.rcf/reports/blueprints/object-storage-s3/<probe-name>.json` carries `aggregateVerdict pass` on the canonical fixture state. The R2 smoke exits 0 with `accountBoundSkipped: true` when `CI_HAS_CLOUDFLARE_ACCOUNT` is unset.
80
+
81
+ ## R2 deviations from full S3
82
+
83
+ Cloudflare R2 is S3-compatible per https://developers.cloudflare.com/r2/api/s3/api/ but explicitly does not implement:
84
+
85
+ - **ACLs**: no per-object or per-bucket ACLs; permissions go through Cloudflare account roles and bucket-level API tokens.
86
+ - **Bucket policies**: no S3-style JSON bucket policies.
87
+ - **Object Lock**: no WORM or retention hold surface.
88
+ - **Versioning**: no object versioning; a put replaces the object.
89
+ - **Lifecycle policies**: R2 marks lifecycle-configuration surface as "feature implementation is currently in progress"; do not depend on time-based expiration or class transitions on R2 at v1.0.0.
90
+
91
+ An operator relying on any of the four either picks a different endpoint (AWS S3 covers all four) or handles the equivalent semantics application-side. The guide's "R2 deviations" section names each and points at the vendor doc.
92
+
93
+ ## The multipart re-upload gotcha
94
+
95
+ Per the R2 doc: re-uploading to the same part number replaces the previous part with loss-on-fail semantics. If a re-upload fails, the original part is gone. The facade avoids the case in the shipped path (part uploads are single-attempt; abort-on-failure covers the mid-multipart failure), but a project that layers its own retry on top of the facade's `putObject` should retry the whole put, not a partial multipart.
96
+
97
+ ## Known mechanism-reach gaps
98
+
99
+ - **Adapter choice (ADR-2901)** is elicited at apply time; the facade's public surface is adapter-neutral so a consumer cannot tell at import time which adapter was picked. Mitigation: the checklist row on the applied blueprint records the adapter chosen; the shipped Node fixture uses `@aws-sdk/client-s3` for probe verifiability.
100
+ - **Server-side encryption default (elicited)** is set at apply time; the facade does not enforce a shipped default because R2 differs from AWS S3 here (R2: SSE-C only, no AWS KMS; AWS: sseS3 available). Mitigation: the guide's "Encryption at rest" section names the two per-target defaults and the applied ADR records the operator choice.
101
+ - **Multipart part re-upload loss-on-fail** per the R2 doc: the facade avoids the case internally but a consumer-side retry loop can walk into it. Mitigation: the README calls it out; the guide's "Retry semantics" section names the shipped-path guarantees.
102
+
103
+ ## Standards trace
104
+
105
+ - Cloudflare R2 S3-compatibility surface: https://developers.cloudflare.com/r2/api/s3/api/ (documents supported ops and the four deviations enumerated above; SSE-C only; auto region only).
106
+ - Cloudflare R2 overview and presigned URLs: https://developers.cloudflare.com/r2/ (S3 API, zero egress fees, presigned URLs).
107
+ - MinIO S3 compatibility for local dev: https://docs.min.io/community/minio-object-store/administration/object-management/object-lifecycle-management.html.
108
+ - GitHub Actions service container shape (for the CI seam): https://docs.github.com/en/actions/using-containerized-services/about-service-containers.
@@ -0,0 +1,72 @@
1
+ {
2
+ "slug": "object-storage-s3",
3
+ "version": "1.0.0",
4
+ "category": "object-storage",
5
+ "capabilities": ["objectStorage"],
6
+ "requiresAppliedCapabilities": {
7
+ "capabilities": ["secretsProvider"],
8
+ "allowSkipFlag": "allow-no-secrets-yet",
9
+ "refusalMessageId": "object-storage-s3-no-secrets"
10
+ },
11
+ "suggestedCompanions": [
12
+ {
13
+ "role": "logging",
14
+ "reason": "Every lifecycle event (facadeReady, objectPut, objectDeleted, presignedIssued) writes through the applied logger; a logging companion supplies the factory."
15
+ },
16
+ {
17
+ "role": "errorHandling",
18
+ "reason": "A put failure, a get 404, a presigned-URL malformed request constructs an internal error record; an error-handling companion supplies the record factory and the boundary."
19
+ }
20
+ ],
21
+ "contributions": [
22
+ { "id": "object-storage-s3-REQ-001", "kind": "req", "path": "requirements/object-storage-s3-req-001.json" },
23
+ { "id": "object-storage-s3-REQ-002", "kind": "req", "path": "requirements/object-storage-s3-req-002.json" },
24
+ { "id": "object-storage-s3-REQ-003", "kind": "req", "path": "requirements/object-storage-s3-req-003.json" },
25
+ { "id": "object-storage-s3-REQ-004", "kind": "req", "path": "requirements/object-storage-s3-req-004.json" },
26
+ { "id": "object-storage-s3-REQ-005", "kind": "req", "path": "requirements/object-storage-s3-req-005.json" },
27
+ { "id": "object-storage-s3-REQ-006", "kind": "req", "path": "requirements/object-storage-s3-req-006.json" },
28
+ { "id": "object-storage-s3-US-28101", "kind": "us", "path": "user-stories/object-storage-s3-us-28101.json" },
29
+ { "id": "object-storage-s3-US-28102", "kind": "us", "path": "user-stories/object-storage-s3-us-28102.json" },
30
+ { "id": "object-storage-s3-US-28103", "kind": "us", "path": "user-stories/object-storage-s3-us-28103.json" },
31
+ { "id": "object-storage-s3-US-28104", "kind": "us", "path": "user-stories/object-storage-s3-us-28104.json" },
32
+ { "id": "object-storage-s3-US-28105", "kind": "us", "path": "user-stories/object-storage-s3-us-28105.json" },
33
+ { "id": "object-storage-s3-US-28106", "kind": "us", "path": "user-stories/object-storage-s3-us-28106.json" },
34
+ { "id": "object-storage-s3-US-28107", "kind": "us", "path": "user-stories/object-storage-s3-us-28107.json" },
35
+ { "id": "object-storage-s3-US-28108", "kind": "us", "path": "user-stories/object-storage-s3-us-28108.json" },
36
+ { "id": "TAC-2901-object-storage-s3-facade", "kind": "tac", "path": "tacs/tac-2901-object-storage-s3-facade.json" },
37
+ { "id": "TAC-2902-object-storage-s3-multipart-uploader", "kind": "tac", "path": "tacs/tac-2902-object-storage-s3-multipart-uploader.json" },
38
+ { "id": "TAC-2903-object-storage-s3-event-sink", "kind": "tac", "path": "tacs/tac-2903-object-storage-s3-event-sink.json" },
39
+ {
40
+ "id": "ADR-2901-object-storage-s3-adapter",
41
+ "kind": "adr",
42
+ "path": "adrs/adr-2901-object-storage-s3-adapter.json",
43
+ "recommendedDefault": true,
44
+ "elicited": true,
45
+ "standardsTraceClause": "AWS S3 API and Cloudflare R2 S3-compatibility notes"
46
+ },
47
+ {
48
+ "id": "ADR-2902-object-storage-s3-presigned-ttl-floor",
49
+ "kind": "adr",
50
+ "path": "adrs/adr-2902-object-storage-s3-presigned-ttl-floor.json",
51
+ "recommendedDefault": true,
52
+ "elicited": true,
53
+ "standardsTraceClause": "generic enterprise practice"
54
+ },
55
+ {
56
+ "id": "ADR-2903-object-storage-s3-multipart-threshold",
57
+ "kind": "adr",
58
+ "path": "adrs/adr-2903-object-storage-s3-multipart-threshold.json",
59
+ "recommendedDefault": true,
60
+ "elicited": true,
61
+ "standardsTraceClause": "generic enterprise practice"
62
+ },
63
+ {
64
+ "id": "ADR-2904-object-storage-s3-contract",
65
+ "kind": "adr",
66
+ "path": "adrs/adr-2904-object-storage-s3-contract.json",
67
+ "scope": "global",
68
+ "topic": "objectStorageContract",
69
+ "standardsTraceClause": "AWS S3 API and Cloudflare R2 S3-compatibility notes"
70
+ }
71
+ ]
72
+ }
@@ -0,0 +1,30 @@
1
+ {
2
+ "adrId": "ADR-2901-object-storage-s3-adapter",
3
+ "prdId": "PRD-001",
4
+ "tadId": "TAD-001",
5
+ "version": "1.0.0",
6
+ "status": "accepted",
7
+ "title": "S3 client adapter: @aws-sdk/client-s3 on Node targets; aws4fetch on Workers targets; elicited",
8
+ "context": "A project deploying object storage on an S3-shape endpoint has two mainstream client choices for the two dominant deploy targets. On Node targets, @aws-sdk/client-s3 (the modular AWS JavaScript SDK v3) is the reference client with a mature multipart transferer, presigned URL helper, and Cloudflare R2 compatibility. On Cloudflare Workers targets, aws4fetch is the lightweight fetch-native client that avoids the AWS SDK's Node polyfills and ships tiny. Both speak the S3 wire protocol; both handle SigV4; both cover the ops the v1.0.0 facade surface needs (PutObject, GetObject, DeleteObject, ListObjectsV2, presigned URL via query-string, CreateMultipartUpload / UploadPart / CompleteMultipartUpload / AbortMultipartUpload). The v1.0.0 facade design has to hold the adapter reference opaque at the facade boundary so the operator picks per deploy target and a future adapter (a GCS shim, an Azure Blob shim under a sibling blueprint) slots in without a facade re-shape.",
9
+ "decision": "The shipped v1.0.0 default on a Node target is @aws-sdk/client-s3 (AWS SDK v3, modular client-s3 package). The shipped v1.0.0 default on a Workers target is aws4fetch. Both are elicited at apply time under the adapter parameter; the operator picks based on the deploy target. Every S3 request goes through the elicited client; the facade module is the sole importer of either package in the source tree per REQ-001. The adapter reference is OPAQUE at this ADR: the facade imports the elicited adapter at the top of the module and any consumer wanting a different adapter (a GCS shim, an Azure Blob shim inside a sibling blueprint that mints on demand) replaces the import here without touching the outward interface.",
10
+ "consequences": "The project inherits the elicited adapter's mature request-signing surface, its presigned-URL helper, and its multipart-upload transferer. Standards trace clause: AWS S3 API (the de facto interop standard, no single normative RFC) and the Cloudflare R2 S3-compatibility notes at https://developers.cloudflare.com/r2/api/s3/api/ enumerating the supported ops (PutObject, GetObject, DeleteObject, ListObjectsV2, HeadObject, HeadBucket, CopyObject, multipart upload, ListMultipartUploads) and the deviations (no ACLs, no bucket policies, no Object Lock, no versioning, no lifecycle policies, SSE-C only). Projects deploying to MinIO for local dev pick the AWS SDK adapter transparently; MinIO covers the S3 surface for the shipped ops per the MinIO S3 compatibility posture at https://docs.min.io/community/minio-object-store/administration/object-management/object-lifecycle-management.html. A future GCS or Azure Blob sibling mints on demand under a different global topic on objectStorageContract (ADR-2904); the operator resolution surfaces as a topic conflict per the round-2 pattern.",
11
+ "alternativesConsidered": [
12
+ {
13
+ "name": "aws-sdk v2 as the shipped Node default",
14
+ "summary": "Ship the monolithic aws-sdk v2 npm package as the Node default.",
15
+ "reasonNotChosen": "aws-sdk v2 is in maintenance mode as of 2024; the modular v3 package @aws-sdk/client-s3 is the recommended surface for new work and ships smaller. Choosing v2 would drag every consumer to a maintenance-mode dependency at v1.0.0."
16
+ },
17
+ {
18
+ "name": "aws4fetch as the shipped Node default too",
19
+ "summary": "Ship aws4fetch on both Node and Workers targets to shrink the dependency footprint.",
20
+ "reasonNotChosen": "aws4fetch is fetch-native and Workers-friendly but lacks the presigned-URL helper and the multipart transferer the v1.0.0 REQ-003 and REQ-004 need out of the box; a Node target picking aws4fetch would need consumer-side glue for both, defeating the value of the shipped facade."
21
+ },
22
+ {
23
+ "name": "Ship a hand-rolled SigV4 signer with fetch",
24
+ "summary": "Roll our own SigV4 signer as the v1.0.0 default and skip both AWS SDK and aws4fetch.",
25
+ "reasonNotChosen": "SigV4 is well-specified but the surface area (request signing, presigned URL, multipart) exceeds a shelf blueprint's maintenance envelope. Two mature adapters exist; picking one per target and eliciting is the shelf pattern."
26
+ }
27
+ ],
28
+ "createdAt": "2026-09-06T18:00:00.000Z",
29
+ "updatedAt": "2026-09-06T18:00:00.000Z"
30
+ }
@@ -0,0 +1,25 @@
1
+ {
2
+ "adrId": "ADR-2902-object-storage-s3-presigned-ttl-floor",
3
+ "prdId": "PRD-001",
4
+ "tadId": "TAD-001",
5
+ "version": "1.0.0",
6
+ "status": "accepted",
7
+ "title": "Presigned-URL default TTL 15 minutes, floor 1 minute, ceiling elicited",
8
+ "context": "A presigned URL is the S3-shape mechanism for delegating read access to an object without handing out credentials. The URL carries a bounded TTL after which the storage endpoint refuses the request with 403 (S3 AccessDenied; MinIO returns a 403 XML with AccessDenied code; the R2 shape matches). Too-short a TTL and legitimate readers miss the window; too-long a TTL and a leaked URL becomes a persistent breach. The AWS SDK's default expires-in value is 900 seconds (15 minutes) which most enterprises match; the S3 API caps SigV4 presigned URLs at 604800 seconds (7 days) though few callers reach that ceiling. Local dev with MinIO handles the full range identically.",
9
+ "decision": "The shipped default TTL is 15 minutes (900 seconds). The floor is 1 minute (60 seconds); the facade refuses a presign request below the floor with a value error. The ceiling is elicited at apply time (no shipped default) with the S3 API's own 7-day ceiling as the outer bound; the operator picks a shorter cap when their threat model calls for it. Every presignedIssued event carries the ttl value used so downstream logging can flag long-lived URLs.",
10
+ "consequences": "The default is the AWS SDK's own default; most consumer code needs no override. Standards trace clause: generic enterprise practice (no single normative RFC for presigned URL TTL; the S3 API's 7-day ceiling is the outer bound). The 1-minute floor is a defensive against copy-paste ADRs that drift TTL toward seconds; a legitimate short-TTL use case (a 30-second CDN-signed URL) is handled by a dedicated CDN blueprint, not by object-storage-s3. Operators who want a longer default author a project-level ADR overriding the elicited ceiling; the shipped default stays at 15 minutes.",
11
+ "alternativesConsidered": [
12
+ {
13
+ "name": "Ship a shorter default (5 minutes)",
14
+ "summary": "Ship 5 minutes as the default TTL, matching the tightest common threat model.",
15
+ "reasonNotChosen": "5 minutes trips legitimate browser-side retries and long-form downloads on slow connections; the AWS SDK's own default of 15 minutes has years of production burn-in without visible complaints."
16
+ },
17
+ {
18
+ "name": "Ship no floor",
19
+ "summary": "Let the operator set any TTL >= 1 second, matching the SDK's own minimum.",
20
+ "reasonNotChosen": "A 1-second TTL is a footgun for the copy-paste ADR class of failure; the 1-minute floor is a small defensive with no measured cost."
21
+ }
22
+ ],
23
+ "createdAt": "2026-09-06T18:00:00.000Z",
24
+ "updatedAt": "2026-09-06T18:00:00.000Z"
25
+ }