rcf-lite 0.21.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.
- package/CHANGELOG.md +16 -0
- package/blueprints/application-account-settings/CHANGELOG.md +12 -0
- package/blueprints/application-account-settings/README.md +114 -0
- package/blueprints/application-account-settings/blueprint.json +234 -0
- package/blueprints/application-account-settings/contributions/adrs/adr-2601-application-account-settings-capability-vocabulary.json +20 -0
- package/blueprints/application-account-settings/contributions/adrs/adr-2602-application-account-settings-security-surface-shape.json +20 -0
- package/blueprints/application-account-settings/contributions/adrs/adr-2603-application-account-settings-theme-persistence.json +20 -0
- package/blueprints/application-account-settings/contributions/adrs/adr-2604-application-account-settings-reauth-window.json +20 -0
- package/blueprints/application-account-settings/contributions/requirements/application-account-settings-req-001.json +18 -0
- package/blueprints/application-account-settings/contributions/requirements/application-account-settings-req-002.json +18 -0
- package/blueprints/application-account-settings/contributions/requirements/application-account-settings-req-003.json +18 -0
- package/blueprints/application-account-settings/contributions/requirements/application-account-settings-req-004.json +18 -0
- package/blueprints/application-account-settings/contributions/requirements/application-account-settings-req-005.json +18 -0
- package/blueprints/application-account-settings/contributions/requirements/application-account-settings-req-006.json +18 -0
- package/blueprints/application-account-settings/contributions/tacs/tac-2601-application-account-settings-shell.json +41 -0
- package/blueprints/application-account-settings/contributions/tacs/tac-2602-application-account-settings-capability-discovery.json +28 -0
- package/blueprints/application-account-settings/contributions/tacs/tac-2603-application-account-settings-hosted-ui-bridge.json +35 -0
- package/blueprints/application-account-settings/contributions/tacs/tac-2604-application-account-settings-session-store.json +40 -0
- package/blueprints/application-account-settings/contributions/user-stories/application-account-settings-us-25101.json +34 -0
- package/blueprints/application-account-settings/contributions/user-stories/application-account-settings-us-25102.json +27 -0
- package/blueprints/application-account-settings/contributions/user-stories/application-account-settings-us-25103.json +27 -0
- package/blueprints/application-account-settings/contributions/user-stories/application-account-settings-us-25104.json +27 -0
- package/blueprints/application-account-settings/contributions/user-stories/application-account-settings-us-25105.json +33 -0
- package/blueprints/application-account-settings/contributions/user-stories/application-account-settings-us-25106.json +27 -0
- package/blueprints/application-account-settings/contributions/user-stories/application-account-settings-us-25107.json +27 -0
- package/blueprints/application-account-settings/contributions/user-stories/application-account-settings-us-25108.json +27 -0
- package/blueprints/application-account-settings/contributions/user-stories/application-account-settings-us-25109.json +33 -0
- package/blueprints/application-account-settings/contributions/user-stories/application-account-settings-us-25110.json +27 -0
- package/blueprints/application-account-settings/docs/topics.md +48 -0
- package/blueprints/application-account-settings/guide/application-account-settings.md +30 -0
- package/blueprints/application-account-settings/probe-packs/application-account-settings.pack.mjs +246 -0
- package/blueprints/application-admin-console/docs/topics.md +7 -0
- package/blueprints/application-api-rest/docs/topics.md +8 -1
- package/blueprints/application-charts/docs/topics.md +7 -0
- package/blueprints/application-dashboard/docs/topics.md +7 -0
- package/blueprints/application-datatable/docs/topics.md +7 -0
- package/blueprints/application-empty-error-states/CHANGELOG.md +9 -0
- package/blueprints/application-empty-error-states/README.md +88 -0
- package/blueprints/application-empty-error-states/blueprint.json +119 -0
- package/blueprints/application-empty-error-states/contributions/adrs/adr-2301-application-empty-error-states-status-contract.json +25 -0
- package/blueprints/application-empty-error-states/contributions/adrs/adr-2302-application-empty-error-states-stack-trace-visibility.json +25 -0
- package/blueprints/application-empty-error-states/contributions/adrs/adr-2303-application-empty-error-states-offline-strategy.json +25 -0
- package/blueprints/application-empty-error-states/contributions/requirements/application-empty-error-states-req-001.json +18 -0
- package/blueprints/application-empty-error-states/contributions/requirements/application-empty-error-states-req-002.json +18 -0
- package/blueprints/application-empty-error-states/contributions/requirements/application-empty-error-states-req-003.json +18 -0
- package/blueprints/application-empty-error-states/contributions/requirements/application-empty-error-states-req-004.json +18 -0
- package/blueprints/application-empty-error-states/contributions/requirements/application-empty-error-states-req-005.json +18 -0
- package/blueprints/application-empty-error-states/contributions/tacs/tac-2301-application-empty-error-states-state-machine.json +46 -0
- package/blueprints/application-empty-error-states/contributions/tacs/tac-2302-application-empty-error-states-recovery-router.json +36 -0
- package/blueprints/application-empty-error-states/contributions/tacs/tac-2303-application-empty-error-states-offline-buffer.json +40 -0
- package/blueprints/application-empty-error-states/contributions/user-stories/application-empty-error-states-us-22101.json +29 -0
- package/blueprints/application-empty-error-states/contributions/user-stories/application-empty-error-states-us-22102.json +29 -0
- package/blueprints/application-empty-error-states/contributions/user-stories/application-empty-error-states-us-22103.json +29 -0
- package/blueprints/application-empty-error-states/contributions/user-stories/application-empty-error-states-us-22104.json +29 -0
- package/blueprints/application-empty-error-states/contributions/user-stories/application-empty-error-states-us-22105.json +29 -0
- package/blueprints/application-empty-error-states/contributions/user-stories/application-empty-error-states-us-22106.json +29 -0
- package/blueprints/application-empty-error-states/contributions/user-stories/application-empty-error-states-us-22107.json +29 -0
- package/blueprints/application-empty-error-states/contributions/user-stories/application-empty-error-states-us-22108.json +29 -0
- package/blueprints/application-empty-error-states/docs/topics.md +53 -0
- package/blueprints/application-empty-error-states/guide/application-empty-error-states.md +50 -0
- package/blueprints/application-empty-error-states/probe-packs/application-empty-error-states.pack.mjs +284 -0
- package/blueprints/application-error-handling/docs/topics.md +7 -0
- package/blueprints/application-file-upload/CHANGELOG.md +9 -0
- package/blueprints/application-file-upload/README.md +85 -0
- package/blueprints/application-file-upload/blueprint.json +114 -0
- package/blueprints/application-file-upload/contributions/adrs/adr-2401-application-file-upload-transport.json +25 -0
- package/blueprints/application-file-upload/contributions/adrs/adr-2402-application-file-upload-accepted-set.json +25 -0
- package/blueprints/application-file-upload/contributions/adrs/adr-2403-application-file-upload-virus-scan.json +25 -0
- package/blueprints/application-file-upload/contributions/requirements/application-file-upload-req-001.json +18 -0
- package/blueprints/application-file-upload/contributions/requirements/application-file-upload-req-002.json +18 -0
- package/blueprints/application-file-upload/contributions/requirements/application-file-upload-req-003.json +18 -0
- package/blueprints/application-file-upload/contributions/requirements/application-file-upload-req-004.json +18 -0
- package/blueprints/application-file-upload/contributions/requirements/application-file-upload-req-005.json +18 -0
- package/blueprints/application-file-upload/contributions/tacs/tac-2401-application-file-upload-input.json +46 -0
- package/blueprints/application-file-upload/contributions/tacs/tac-2402-application-file-upload-transport.json +47 -0
- package/blueprints/application-file-upload/contributions/tacs/tac-2403-application-file-upload-progress-announcer.json +46 -0
- package/blueprints/application-file-upload/contributions/user-stories/application-file-upload-us-23101.json +28 -0
- package/blueprints/application-file-upload/contributions/user-stories/application-file-upload-us-23102.json +28 -0
- package/blueprints/application-file-upload/contributions/user-stories/application-file-upload-us-23103.json +29 -0
- package/blueprints/application-file-upload/contributions/user-stories/application-file-upload-us-23104.json +28 -0
- package/blueprints/application-file-upload/contributions/user-stories/application-file-upload-us-23105.json +29 -0
- package/blueprints/application-file-upload/contributions/user-stories/application-file-upload-us-23106.json +28 -0
- package/blueprints/application-file-upload/contributions/user-stories/application-file-upload-us-23107.json +28 -0
- package/blueprints/application-file-upload/docs/topics.md +58 -0
- package/blueprints/application-file-upload/guide/application-file-upload.md +48 -0
- package/blueprints/application-file-upload/probe-packs/application-file-upload.pack.mjs +238 -0
- package/blueprints/application-forms-wizard/CHANGELOG.md +9 -0
- package/blueprints/application-forms-wizard/README.md +102 -0
- package/blueprints/application-forms-wizard/blueprint.json +120 -0
- package/blueprints/application-forms-wizard/contributions/adrs/adr-2501-application-forms-wizard-navigation.json +25 -0
- package/blueprints/application-forms-wizard/contributions/adrs/adr-2502-application-forms-wizard-save-and-return.json +25 -0
- package/blueprints/application-forms-wizard/contributions/adrs/adr-2503-application-forms-wizard-step-indicator.json +25 -0
- package/blueprints/application-forms-wizard/contributions/requirements/application-forms-wizard-req-001.json +18 -0
- package/blueprints/application-forms-wizard/contributions/requirements/application-forms-wizard-req-002.json +18 -0
- package/blueprints/application-forms-wizard/contributions/requirements/application-forms-wizard-req-003.json +18 -0
- package/blueprints/application-forms-wizard/contributions/requirements/application-forms-wizard-req-004.json +18 -0
- package/blueprints/application-forms-wizard/contributions/requirements/application-forms-wizard-req-005.json +18 -0
- package/blueprints/application-forms-wizard/contributions/tacs/tac-2501-application-forms-wizard-task-list.json +46 -0
- package/blueprints/application-forms-wizard/contributions/tacs/tac-2502-application-forms-wizard-error-summary.json +40 -0
- package/blueprints/application-forms-wizard/contributions/tacs/tac-2503-application-forms-wizard-draft-store.json +40 -0
- package/blueprints/application-forms-wizard/contributions/user-stories/application-forms-wizard-us-24101.json +28 -0
- package/blueprints/application-forms-wizard/contributions/user-stories/application-forms-wizard-us-24102.json +29 -0
- package/blueprints/application-forms-wizard/contributions/user-stories/application-forms-wizard-us-24103.json +28 -0
- package/blueprints/application-forms-wizard/contributions/user-stories/application-forms-wizard-us-24104.json +29 -0
- package/blueprints/application-forms-wizard/contributions/user-stories/application-forms-wizard-us-24105.json +28 -0
- package/blueprints/application-forms-wizard/contributions/user-stories/application-forms-wizard-us-24106.json +28 -0
- package/blueprints/application-forms-wizard/contributions/user-stories/application-forms-wizard-us-24107.json +28 -0
- package/blueprints/application-forms-wizard/contributions/user-stories/application-forms-wizard-us-24108.json +29 -0
- package/blueprints/application-forms-wizard/docs/topics.md +49 -0
- package/blueprints/application-forms-wizard/guide/application-forms-wizard.md +48 -0
- package/blueprints/application-forms-wizard/probe-packs/application-forms-wizard.pack.mjs +233 -0
- package/blueprints/application-notifications-in-app/docs/topics.md +7 -0
- package/blueprints/application-onboarding-tour/CHANGELOG.md +12 -0
- package/blueprints/application-onboarding-tour/README.md +77 -0
- package/blueprints/application-onboarding-tour/blueprint.json +164 -0
- package/blueprints/application-onboarding-tour/contributions/adrs/adr-2701-application-onboarding-tour-dismissal-policy.json +20 -0
- package/blueprints/application-onboarding-tour/contributions/adrs/adr-2702-application-onboarding-tour-completion-store-shape.json +20 -0
- package/blueprints/application-onboarding-tour/contributions/adrs/adr-2703-application-onboarding-tour-checklist-anchor.json +20 -0
- package/blueprints/application-onboarding-tour/contributions/requirements/application-onboarding-tour-req-001.json +18 -0
- package/blueprints/application-onboarding-tour/contributions/requirements/application-onboarding-tour-req-002.json +18 -0
- package/blueprints/application-onboarding-tour/contributions/requirements/application-onboarding-tour-req-003.json +18 -0
- package/blueprints/application-onboarding-tour/contributions/requirements/application-onboarding-tour-req-004.json +18 -0
- package/blueprints/application-onboarding-tour/contributions/tacs/tac-2701-application-onboarding-tour-step-runner.json +41 -0
- package/blueprints/application-onboarding-tour/contributions/tacs/tac-2702-application-onboarding-tour-checklist-slot.json +35 -0
- package/blueprints/application-onboarding-tour/contributions/tacs/tac-2703-application-onboarding-tour-completion-store.json +34 -0
- package/blueprints/application-onboarding-tour/contributions/user-stories/application-onboarding-tour-us-26101.json +27 -0
- package/blueprints/application-onboarding-tour/contributions/user-stories/application-onboarding-tour-us-26102.json +27 -0
- package/blueprints/application-onboarding-tour/contributions/user-stories/application-onboarding-tour-us-26103.json +27 -0
- package/blueprints/application-onboarding-tour/contributions/user-stories/application-onboarding-tour-us-26104.json +27 -0
- package/blueprints/application-onboarding-tour/contributions/user-stories/application-onboarding-tour-us-26105.json +27 -0
- package/blueprints/application-onboarding-tour/contributions/user-stories/application-onboarding-tour-us-26106.json +27 -0
- package/blueprints/application-onboarding-tour/contributions/user-stories/application-onboarding-tour-us-26107.json +27 -0
- package/blueprints/application-onboarding-tour/docs/topics.md +48 -0
- package/blueprints/application-onboarding-tour/guide/application-onboarding-tour.md +59 -0
- package/blueprints/application-onboarding-tour/probe-packs/application-onboarding-tour.pack.mjs +231 -0
- package/blueprints/application-spa/docs/topics.md +8 -1
- package/blueprints/delivery-ci-workflows/docs/topics.md +8 -1
- package/blueprints/deploy-cloudflare-workers/docs/topics.md +8 -1
- package/blueprints/email-smtp-resend/docs/topics.md +8 -1
- package/blueprints/object-storage-s3/CHANGELOG.md +13 -0
- package/blueprints/object-storage-s3/README.md +108 -0
- package/blueprints/object-storage-s3/blueprint.json +72 -0
- package/blueprints/object-storage-s3/contributions/adrs/adr-2901-object-storage-s3-adapter.json +30 -0
- package/blueprints/object-storage-s3/contributions/adrs/adr-2902-object-storage-s3-presigned-ttl-floor.json +25 -0
- package/blueprints/object-storage-s3/contributions/adrs/adr-2903-object-storage-s3-multipart-threshold.json +25 -0
- package/blueprints/object-storage-s3/contributions/adrs/adr-2904-object-storage-s3-contract.json +25 -0
- package/blueprints/object-storage-s3/contributions/probes/event-secrecy.mjs +103 -0
- package/blueprints/object-storage-s3/contributions/probes/facade-round-trip.mjs +43 -0
- package/blueprints/object-storage-s3/contributions/probes/multipart-upload.mjs +84 -0
- package/blueprints/object-storage-s3/contributions/probes/presigned-url.mjs +101 -0
- package/blueprints/object-storage-s3/contributions/probes/probe-utils.mjs +85 -0
- package/blueprints/object-storage-s3/contributions/probes/put-get-round-trip.mjs +84 -0
- package/blueprints/object-storage-s3/contributions/probes/r2-real-account-smoke.mjs +64 -0
- package/blueprints/object-storage-s3/contributions/probes/run-event-secrecy.mjs +4 -0
- package/blueprints/object-storage-s3/contributions/probes/run-facade-round-trip.mjs +10 -0
- package/blueprints/object-storage-s3/contributions/probes/run-multipart-upload.mjs +4 -0
- package/blueprints/object-storage-s3/contributions/probes/run-presigned-url.mjs +4 -0
- package/blueprints/object-storage-s3/contributions/probes/run-put-get-round-trip.mjs +7 -0
- package/blueprints/object-storage-s3/contributions/probes/run-r2-real-account-smoke.mjs +4 -0
- package/blueprints/object-storage-s3/contributions/requirements/object-storage-s3-req-001.json +18 -0
- package/blueprints/object-storage-s3/contributions/requirements/object-storage-s3-req-002.json +18 -0
- package/blueprints/object-storage-s3/contributions/requirements/object-storage-s3-req-003.json +18 -0
- package/blueprints/object-storage-s3/contributions/requirements/object-storage-s3-req-004.json +18 -0
- package/blueprints/object-storage-s3/contributions/requirements/object-storage-s3-req-005.json +18 -0
- package/blueprints/object-storage-s3/contributions/requirements/object-storage-s3-req-006.json +18 -0
- package/blueprints/object-storage-s3/contributions/tacs/tac-2901-object-storage-s3-facade.json +57 -0
- package/blueprints/object-storage-s3/contributions/tacs/tac-2902-object-storage-s3-multipart-uploader.json +36 -0
- package/blueprints/object-storage-s3/contributions/tacs/tac-2903-object-storage-s3-event-sink.json +36 -0
- package/blueprints/object-storage-s3/contributions/user-stories/object-storage-s3-us-28101.json +34 -0
- package/blueprints/object-storage-s3/contributions/user-stories/object-storage-s3-us-28102.json +43 -0
- package/blueprints/object-storage-s3/contributions/user-stories/object-storage-s3-us-28103.json +25 -0
- package/blueprints/object-storage-s3/contributions/user-stories/object-storage-s3-us-28104.json +34 -0
- package/blueprints/object-storage-s3/contributions/user-stories/object-storage-s3-us-28105.json +25 -0
- package/blueprints/object-storage-s3/contributions/user-stories/object-storage-s3-us-28106.json +34 -0
- package/blueprints/object-storage-s3/contributions/user-stories/object-storage-s3-us-28107.json +34 -0
- package/blueprints/object-storage-s3/contributions/user-stories/object-storage-s3-us-28108.json +34 -0
- package/blueprints/object-storage-s3/docs/topics.md +62 -0
- package/blueprints/object-storage-s3/guide/object-storage-s3.md +207 -0
- package/blueprints/observability-essentials/docs/topics.md +8 -1
- package/blueprints/observability-logging/CHANGELOG.md +4 -0
- package/blueprints/observability-logging/README.md +3 -0
- package/blueprints/observability-logging/blueprint.json +3 -2
- package/blueprints/observability-logging/docs/topics.md +7 -0
- package/blueprints/observability-probe-endpoints/docs/topics.md +8 -1
- package/blueprints/persistence-data-d1/docs/topics.md +8 -1
- package/blueprints/persistence-data-postgres/CHANGELOG.md +12 -0
- package/blueprints/persistence-data-postgres/README.md +101 -0
- package/blueprints/persistence-data-postgres/blueprint.json +80 -0
- package/blueprints/persistence-data-postgres/contributions/adrs/adr-2801-persistence-data-postgres-driver.json +30 -0
- package/blueprints/persistence-data-postgres/contributions/adrs/adr-2802-persistence-data-postgres-migration-shape.json +25 -0
- package/blueprints/persistence-data-postgres/contributions/adrs/adr-2803-persistence-data-postgres-runner-mode.json +25 -0
- package/blueprints/persistence-data-postgres/contributions/adrs/adr-2804-persistence-data-postgres-recovery.json +25 -0
- package/blueprints/persistence-data-postgres/contributions/adrs/adr-2805-persistence-data-postgres-connection-pool-posture.json +25 -0
- package/blueprints/persistence-data-postgres/contributions/probes/facade-round-trip.mjs +56 -0
- package/blueprints/persistence-data-postgres/contributions/probes/migration-apply.mjs +75 -0
- package/blueprints/persistence-data-postgres/contributions/probes/pool-posture-smoke.mjs +56 -0
- package/blueprints/persistence-data-postgres/contributions/probes/prepared-statement-scan.mjs +186 -0
- package/blueprints/persistence-data-postgres/contributions/probes/probe-utils.mjs +76 -0
- package/blueprints/persistence-data-postgres/contributions/probes/recovery-restore-round-trip.mjs +173 -0
- package/blueprints/persistence-data-postgres/contributions/probes/run-facade-round-trip.mjs +10 -0
- package/blueprints/persistence-data-postgres/contributions/probes/run-migration-apply.mjs +10 -0
- package/blueprints/persistence-data-postgres/contributions/probes/run-pool-posture-smoke.mjs +9 -0
- package/blueprints/persistence-data-postgres/contributions/probes/run-prepared-statement-scan.mjs +10 -0
- package/blueprints/persistence-data-postgres/contributions/probes/run-recovery-restore-round-trip.mjs +9 -0
- package/blueprints/persistence-data-postgres/contributions/probes/run-transaction-atomicity.mjs +10 -0
- package/blueprints/persistence-data-postgres/contributions/probes/transaction-atomicity.mjs +79 -0
- package/blueprints/persistence-data-postgres/contributions/requirements/persistence-data-postgres-req-001.json +18 -0
- package/blueprints/persistence-data-postgres/contributions/requirements/persistence-data-postgres-req-002.json +18 -0
- package/blueprints/persistence-data-postgres/contributions/requirements/persistence-data-postgres-req-003.json +18 -0
- package/blueprints/persistence-data-postgres/contributions/requirements/persistence-data-postgres-req-004.json +18 -0
- package/blueprints/persistence-data-postgres/contributions/requirements/persistence-data-postgres-req-005.json +18 -0
- package/blueprints/persistence-data-postgres/contributions/requirements/persistence-data-postgres-req-006.json +18 -0
- package/blueprints/persistence-data-postgres/contributions/requirements/persistence-data-postgres-req-007.json +18 -0
- package/blueprints/persistence-data-postgres/contributions/tacs/tac-2801-persistence-data-postgres-facade.json +58 -0
- package/blueprints/persistence-data-postgres/contributions/tacs/tac-2802-persistence-data-postgres-migration-runner.json +40 -0
- package/blueprints/persistence-data-postgres/contributions/tacs/tac-2803-persistence-data-postgres-transaction-helper.json +35 -0
- package/blueprints/persistence-data-postgres/contributions/tacs/tac-2804-persistence-data-postgres-recovery-runner.json +40 -0
- package/blueprints/persistence-data-postgres/contributions/user-stories/persistence-data-postgres-us-27101.json +34 -0
- package/blueprints/persistence-data-postgres/contributions/user-stories/persistence-data-postgres-us-27102.json +25 -0
- package/blueprints/persistence-data-postgres/contributions/user-stories/persistence-data-postgres-us-27103.json +25 -0
- package/blueprints/persistence-data-postgres/contributions/user-stories/persistence-data-postgres-us-27104.json +25 -0
- package/blueprints/persistence-data-postgres/contributions/user-stories/persistence-data-postgres-us-27105.json +25 -0
- package/blueprints/persistence-data-postgres/contributions/user-stories/persistence-data-postgres-us-27106.json +25 -0
- package/blueprints/persistence-data-postgres/contributions/user-stories/persistence-data-postgres-us-27107.json +25 -0
- package/blueprints/persistence-data-postgres/contributions/user-stories/persistence-data-postgres-us-27108.json +25 -0
- package/blueprints/persistence-data-postgres/contributions/user-stories/persistence-data-postgres-us-27109.json +25 -0
- package/blueprints/persistence-data-postgres/contributions/user-stories/persistence-data-postgres-us-27110.json +25 -0
- package/blueprints/persistence-data-postgres/docs/topics.md +64 -0
- package/blueprints/persistence-data-postgres/guide/persistence-data-postgres.md +172 -0
- package/blueprints/persistence-data-sqlite/docs/topics.md +8 -1
- package/blueprints/security-auth-clerk/CHANGELOG.md +4 -0
- package/blueprints/security-auth-clerk/README.md +3 -0
- package/blueprints/security-auth-clerk/blueprint.json +147 -30
- package/blueprints/security-auth-clerk/docs/topics.md +8 -1
- package/blueprints/security-auth-keycloak/CHANGELOG.md +4 -0
- package/blueprints/security-auth-keycloak/README.md +3 -0
- package/blueprints/security-auth-keycloak/blueprint.json +182 -37
- package/blueprints/security-auth-keycloak/docs/topics.md +8 -1
- package/blueprints/security-auth-magic-link/CHANGELOG.md +4 -0
- package/blueprints/security-auth-magic-link/README.md +3 -0
- package/blueprints/security-auth-magic-link/blueprint.json +159 -33
- package/blueprints/security-auth-magic-link/docs/topics.md +8 -1
- package/blueprints/security-auth-oauth2/CHANGELOG.md +4 -0
- package/blueprints/security-auth-oauth2/README.md +3 -0
- package/blueprints/security-auth-oauth2/blueprint.json +158 -32
- package/blueprints/security-auth-oauth2/docs/topics.md +8 -1
- package/blueprints/security-secrets-management/CHANGELOG.md +11 -0
- package/blueprints/security-secrets-management/blueprint.json +2 -1
- package/blueprints/security-secrets-management/docs/topics.md +8 -1
- package/fixtures/canary-manifest.json +9 -9
- package/package.json +1 -1
- package/rcf/code-nodes/cn-134.json +13 -0
- package/rcf/code-nodes/cn-135.json +12 -0
- package/rcf/code-nodes/cn-136.json +13 -0
- package/rcf/code-nodes/cn-137.json +13 -0
- package/rcf/code-nodes/cn-138.json +12 -0
- package/rcf/code-nodes/cn-139.json +12 -0
- package/rcf/code-nodes/cn-140.json +13 -0
- package/rcf/code-nodes/cn-141.json +13 -0
- package/rcf/code-nodes/cn-142.json +12 -0
- package/rcf/code-nodes/cn-143.json +13 -0
- package/rcf/code-nodes/cn-144.json +13 -0
- package/rcf/code-nodes/cn-145.json +12 -0
- package/rcf/code-nodes/cn-146.json +12 -0
- package/rcf/code-nodes/cn-147.json +13 -0
- package/rcf/code-nodes/cn-148.json +13 -0
- package/rcf/code-nodes/cn-149.json +12 -0
- package/rcf/code-nodes/cn-150.json +13 -0
- package/rcf/code-nodes/cn-151.json +13 -0
- package/rcf/code-nodes/cn-152.json +12 -0
- package/rcf/code-nodes/cn-153.json +12 -0
- package/rcf/code-nodes/cn-154.json +13 -0
- package/rcf/code-nodes/cn-155.json +14 -0
- package/rcf/code-nodes/cn-156.json +13 -0
- package/rcf/code-nodes/cn-157.json +13 -0
- package/rcf/code-nodes/cn-158.json +12 -0
- package/rcf/code-nodes/cn-159.json +13 -0
- package/rcf/code-nodes/cn-160.json +12 -0
- package/rcf/code-nodes/cn-161.json +12 -0
- package/rcf/code-nodes/cn-162.json +13 -0
- package/rcf/code-nodes/cn-163.json +12 -0
- package/rcf/code-nodes/cn-164.json +13 -0
- package/rcf/code-nodes/cn-165.json +12 -0
- package/rcf/code-nodes/cn-166.json +12 -0
- package/rcf/code-nodes/cn-167.json +12 -0
- package/rcf/code-nodes/cn-168.json +12 -0
- package/rcf/code-nodes/cn-169.json +12 -0
- package/rcf/code-nodes/cn-170.json +12 -0
- package/rcf/code-nodes/cn-171.json +12 -0
- package/rcf/code-nodes/cn-172.json +12 -0
- package/rcf/code-nodes/cn-173.json +12 -0
- package/rcf/code-nodes/cn-174.json +12 -0
- package/rcf/code-nodes/cn-175.json +13 -0
- package/rcf/code-nodes/cn-176.json +12 -0
- package/rcf/code-nodes/cn-177.json +12 -0
- package/rcf/code-nodes/cn-178.json +12 -0
- package/rcf/code-nodes/cn-179.json +12 -0
- package/rcf/code-nodes/cn-180.json +13 -0
- package/rcf/code-nodes/cn-181.json +12 -0
- package/rcf/code-nodes/cn-182.json +13 -0
- package/rcf/code-nodes/cn-183.json +12 -0
- package/rcf/code-nodes/cn-184.json +13 -0
- package/rcf/code-nodes/cn-185.json +12 -0
- package/rcf/code-nodes/cn-186.json +12 -0
- package/rcf/code-nodes/cn-200.json +14 -0
- package/rcf/code-nodes/cn-201.json +13 -0
- package/rcf/code-nodes/cn-202.json +14 -0
- package/rcf/code-nodes/cn-203.json +14 -0
- package/rcf/code-nodes/cn-204.json +13 -0
- package/rcf/code-nodes/cn-205.json +14 -0
- package/rcf/fbs/fbs-043.json +23 -0
- package/rcf/fbs/fbs-044.json +23 -0
- package/rcf/fbs/fbs-045.json +23 -0
- package/rcf/fbs/fbs-046.json +24 -0
- package/rcf/fbs/fbs-047.json +24 -0
- package/rcf/fbs/fbs-060.json +22 -0
- package/rcf/fbs/fbs-061.json +20 -0
- package/rcf/requirements/req-024.json +69 -0
- package/rcf/requirements/req-025.json +59 -0
- package/rcf/requirements/req-026.json +154 -0
- package/rcf/requirements/req-027.json +33 -0
- package/rcf/requirements/req-028.json +13 -0
- package/rcf/requirements/req-040.json +13 -0
- package/rcf/requirements/req-041.json +125 -0
- package/rcf/test-suites/ts-053.json +70 -0
- package/rcf/test-suites/ts-054.json +70 -0
- package/rcf/test-suites/ts-055.json +77 -0
- package/rcf/test-suites/ts-056.json +78 -0
- package/rcf/test-suites/ts-057.json +78 -0
- package/rcf/test-suites/ts-070.json +62 -0
- package/rcf/test-suites/ts-071.json +62 -0
- package/rcf/user-stories/us-2401.json +62 -0
- package/rcf/user-stories/us-2501.json +58 -0
- package/rcf/user-stories/us-2601.json +51 -0
- package/rcf/user-stories/us-2701.json +55 -0
- package/rcf/user-stories/us-2801.json +55 -0
- package/rcf/user-stories/us-4001.json +69 -0
- package/rcf/user-stories/us-4101.json +69 -0
- package/releases/releases.yaml +11 -1
- package/src/blueprint/apply.js +10 -1
- package/src/blueprint/capabilities.js +41 -2
- package/src/cli/blueprint.js +8 -1
package/blueprints/application-account-settings/probe-packs/application-account-settings.pack.mjs
ADDED
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
// application-account-settings probe pack (v1.0.0).
|
|
2
|
+
//
|
|
3
|
+
// Five capability-gated checks anchored to the blueprint AC ids:
|
|
4
|
+
// AC-25101-1 shell tabs mirror the applied capability set (always fires; guard-checked)
|
|
5
|
+
// AC-25102-1 profile surface renders with WCAG 1.3.5 autocomplete tokens (always fires)
|
|
6
|
+
// AC-25105-1 security surface renders the branch matching the applied capability +
|
|
7
|
+
// the elicited security-surface-shape (fires when credentialSelfService or
|
|
8
|
+
// hostedIdentityUi is applied)
|
|
9
|
+
// AC-25106-1 sessions surface lists rows and renders the ARIA APG dialog-modal on
|
|
10
|
+
// terminate (fires when sessionInventory is applied)
|
|
11
|
+
// AC-25108-1 theme surface renders the radiogroup and persists per the elicited
|
|
12
|
+
// theme-persistence (fires when application-spa is applied via caps)
|
|
13
|
+
//
|
|
14
|
+
// Every check drives the real Playwright browser the T-0 runner injects and reads
|
|
15
|
+
// its per-check applicability from the blueprint applied sidecar
|
|
16
|
+
// (rcf/blueprints/application-account-settings.applied.json) written by the apply
|
|
17
|
+
// verb: an absent capability records verdict: skipped and the aggregate treats the
|
|
18
|
+
// check as neither pass nor fail (spec section 3.3, rcf-schemas 0.6.1 has no
|
|
19
|
+
// applicable: false field, per round-3 T-5 precedent).
|
|
20
|
+
//
|
|
21
|
+
// Sample-app fixture: packages/rcf-lite/test/fixtures/probe-pack-application-account-settings/.
|
|
22
|
+
// The fixture ships CAPS and APPS env / ?caps= / ?apps= switches mirroring the
|
|
23
|
+
// applied capability set so the pack can be probed for every fixture combination
|
|
24
|
+
// on the shelf gate.
|
|
25
|
+
|
|
26
|
+
import { readFile } from 'node:fs/promises';
|
|
27
|
+
import { join } from 'node:path';
|
|
28
|
+
|
|
29
|
+
async function readAppliedCapabilities(projectRoot) {
|
|
30
|
+
if (!projectRoot) return [];
|
|
31
|
+
try {
|
|
32
|
+
const raw = await readFile(join(projectRoot, 'rcf', 'blueprints', 'application-account-settings.applied.json'), 'utf8');
|
|
33
|
+
const doc = JSON.parse(raw);
|
|
34
|
+
return Array.isArray(doc.appliedCapabilities) ? doc.appliedCapabilities.slice() : [];
|
|
35
|
+
} catch {
|
|
36
|
+
return [];
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
async function readAppliedElicitations(projectRoot) {
|
|
41
|
+
if (!projectRoot) return {};
|
|
42
|
+
try {
|
|
43
|
+
const raw = await readFile(join(projectRoot, 'rcf', 'blueprints', 'application-account-settings.applied.json'), 'utf8');
|
|
44
|
+
const doc = JSON.parse(raw);
|
|
45
|
+
return typeof doc.appliedElicitations === 'object' && doc.appliedElicitations ? doc.appliedElicitations : {};
|
|
46
|
+
} catch {
|
|
47
|
+
return {};
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function withUrl(runtimeUrl, path) {
|
|
52
|
+
return new URL(path, runtimeUrl).toString();
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export default {
|
|
56
|
+
packName: 'application-account-settings',
|
|
57
|
+
version: '1.0.0',
|
|
58
|
+
blueprintSlug: 'application-account-settings',
|
|
59
|
+
appliesTo: ({ fbs }) => {
|
|
60
|
+
const routes = fbs?.designStage?.navModel?.routes ?? [];
|
|
61
|
+
const tacIds = fbs?.contextRequirements?.tacIds ?? [];
|
|
62
|
+
if (tacIds.includes('TAC-2601-application-account-settings-shell')) return true;
|
|
63
|
+
return routes.some((r) => typeof r?.path === 'string' && /\/(account|settings|profile)(\/|$)/.test(r.path));
|
|
64
|
+
},
|
|
65
|
+
boot: { bootCommand: null, waitForUrl: null, waitForSelector: null },
|
|
66
|
+
checks: [
|
|
67
|
+
{
|
|
68
|
+
id: 'AC-25101-1',
|
|
69
|
+
severity: 'block',
|
|
70
|
+
description: 'Shell renders as an ARIA APG tabs region and its tabs mirror the union of applied capabilities plus the always-on profile tab; a tab whose capability is not applied does not render',
|
|
71
|
+
appliesTo: async () => true,
|
|
72
|
+
run: async ({ browser, runtimeUrl, projectRoot }) => {
|
|
73
|
+
if (!browser) return { verdict: 'fail', detail: 'no packBrowser wired' };
|
|
74
|
+
const caps = await readAppliedCapabilities(projectRoot);
|
|
75
|
+
await browser.goto(withUrl(runtimeUrl, '/account'));
|
|
76
|
+
const dom = await browser.evaluate(() => {
|
|
77
|
+
const nav = document.querySelector('nav[data-role="account-settings-nav"]');
|
|
78
|
+
if (!nav) return { present: false };
|
|
79
|
+
const tabs = Array.from(nav.querySelectorAll('[role="tab"]')).map((t) => t.getAttribute('data-tab-id'));
|
|
80
|
+
const role = nav.getAttribute('role');
|
|
81
|
+
const ariaLabel = nav.getAttribute('aria-label');
|
|
82
|
+
return { present: true, tabs, role, ariaLabel };
|
|
83
|
+
});
|
|
84
|
+
if (!dom.present) return { verdict: 'fail', detail: 'nav[data-role="account-settings-nav"] not found' };
|
|
85
|
+
if (dom.role !== 'tablist') return { verdict: 'fail', detail: `nav role expected tablist, got ${dom.role}` };
|
|
86
|
+
if (!dom.ariaLabel) return { verdict: 'fail', detail: 'nav missing aria-label (accessible name)' };
|
|
87
|
+
if (!dom.tabs.includes('profile')) return { verdict: 'fail', detail: `profile tab missing from ${JSON.stringify(dom.tabs)}` };
|
|
88
|
+
const securityExpected = caps.includes('credentialSelfService') || caps.includes('hostedIdentityUi');
|
|
89
|
+
const securityRendered = dom.tabs.includes('security');
|
|
90
|
+
if (securityExpected && !securityRendered) return { verdict: 'fail', detail: `security tab expected (caps=${JSON.stringify(caps)}) but not rendered` };
|
|
91
|
+
if (!securityExpected && securityRendered) return { verdict: 'fail', detail: `security tab rendered but caps=${JSON.stringify(caps)} declare neither credentialSelfService nor hostedIdentityUi (leak)` };
|
|
92
|
+
const sessionsExpected = caps.includes('sessionInventory');
|
|
93
|
+
const sessionsRendered = dom.tabs.includes('sessions');
|
|
94
|
+
if (sessionsExpected && !sessionsRendered) return { verdict: 'fail', detail: `sessions tab expected but not rendered` };
|
|
95
|
+
if (!sessionsExpected && sessionsRendered) return { verdict: 'fail', detail: `sessions tab rendered but sessionInventory not applied (leak)` };
|
|
96
|
+
return { verdict: 'pass', detail: `tabs=${JSON.stringify(dom.tabs)} caps=${JSON.stringify(caps)}` };
|
|
97
|
+
},
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
id: 'AC-25102-1',
|
|
101
|
+
severity: 'block',
|
|
102
|
+
description: 'Profile surface renders a form with WCAG 1.3.5 autocomplete tokens (name, email, bday, country) and a polite aria-live save-status region',
|
|
103
|
+
appliesTo: async () => true,
|
|
104
|
+
run: async ({ browser, runtimeUrl }) => {
|
|
105
|
+
if (!browser) return { verdict: 'fail', detail: 'no packBrowser wired' };
|
|
106
|
+
await browser.goto(withUrl(runtimeUrl, '/account/profile'));
|
|
107
|
+
const dom = await browser.evaluate(() => {
|
|
108
|
+
const form = document.querySelector('form[data-surface="profile"]');
|
|
109
|
+
if (!form) return { present: false };
|
|
110
|
+
const nameAuto = form.querySelector('input[name="name"]')?.getAttribute('autocomplete');
|
|
111
|
+
const emailAuto = form.querySelector('input[name="email"]')?.getAttribute('autocomplete');
|
|
112
|
+
const bdayAuto = form.querySelector('input[name="bday"]')?.getAttribute('autocomplete');
|
|
113
|
+
const countryAuto = form.querySelector('input[name="country"]')?.getAttribute('autocomplete');
|
|
114
|
+
const status = form.querySelector('[role="status"][aria-live="polite"]');
|
|
115
|
+
return { present: true, nameAuto, emailAuto, bdayAuto, countryAuto, statusPresent: !!status };
|
|
116
|
+
});
|
|
117
|
+
if (!dom.present) return { verdict: 'fail', detail: 'form[data-surface="profile"] not found' };
|
|
118
|
+
if (dom.nameAuto !== 'name') return { verdict: 'fail', detail: `name autocomplete token expected "name", got "${dom.nameAuto}"` };
|
|
119
|
+
if (dom.emailAuto !== 'email') return { verdict: 'fail', detail: `email autocomplete token expected "email", got "${dom.emailAuto}"` };
|
|
120
|
+
if (dom.bdayAuto !== 'bday') return { verdict: 'fail', detail: `bday autocomplete token expected "bday", got "${dom.bdayAuto}"` };
|
|
121
|
+
if (dom.countryAuto !== 'country') return { verdict: 'fail', detail: `country autocomplete token expected "country", got "${dom.countryAuto}"` };
|
|
122
|
+
if (!dom.statusPresent) return { verdict: 'fail', detail: 'save-status region [role="status"][aria-live="polite"] not found' };
|
|
123
|
+
return { verdict: 'pass', detail: `autocomplete tokens name+email+bday+country present; save-status present` };
|
|
124
|
+
},
|
|
125
|
+
},
|
|
126
|
+
{
|
|
127
|
+
id: 'AC-25105-1',
|
|
128
|
+
severity: 'block',
|
|
129
|
+
description: 'Security surface renders the self-service branch when credentialSelfService is applied and security-surface-shape=self-service; renders the hosted-link-out or hosted-embed branch when hostedIdentityUi is applied and security-surface-shape matches',
|
|
130
|
+
appliesTo: async ({ projectRoot }) => {
|
|
131
|
+
const caps = await readAppliedCapabilities(projectRoot);
|
|
132
|
+
return caps.includes('credentialSelfService') || caps.includes('hostedIdentityUi');
|
|
133
|
+
},
|
|
134
|
+
run: async ({ browser, runtimeUrl, projectRoot }) => {
|
|
135
|
+
if (!browser) return { verdict: 'fail', detail: 'no packBrowser wired' };
|
|
136
|
+
const caps = await readAppliedCapabilities(projectRoot);
|
|
137
|
+
const elicits = await readAppliedElicitations(projectRoot);
|
|
138
|
+
const shape = elicits['security-surface-shape'] ?? 'self-service';
|
|
139
|
+
await browser.goto(withUrl(runtimeUrl, `/account/security?security-surface-shape=${encodeURIComponent(shape)}`));
|
|
140
|
+
const dom = await browser.evaluate(() => {
|
|
141
|
+
const region = document.querySelector('[data-surface="security"]');
|
|
142
|
+
if (!region) return { present: false };
|
|
143
|
+
return {
|
|
144
|
+
present: true,
|
|
145
|
+
branch: region.getAttribute('data-branch'),
|
|
146
|
+
hasPassword: !!region.querySelector('[data-role="change-password"]'),
|
|
147
|
+
hasMfa: !!region.querySelector('[data-role="mfa-management"]'),
|
|
148
|
+
hasLinkOut: !!region.querySelector('[data-role="hosted-link-out"]'),
|
|
149
|
+
hasEmbed: !!region.querySelector('[data-role="hosted-embed"]'),
|
|
150
|
+
linkRel: region.querySelector('[data-role="hosted-link-out"]')?.getAttribute('rel'),
|
|
151
|
+
embedSandbox: region.querySelector('[data-role="hosted-embed"]')?.getAttribute('sandbox'),
|
|
152
|
+
};
|
|
153
|
+
});
|
|
154
|
+
if (!dom.present) return { verdict: 'fail', detail: '[data-surface="security"] not found' };
|
|
155
|
+
if (caps.includes('credentialSelfService') && shape === 'self-service') {
|
|
156
|
+
if (!dom.hasPassword) return { verdict: 'fail', detail: 'self-service branch missing [data-role="change-password"]' };
|
|
157
|
+
if (!dom.hasMfa) return { verdict: 'fail', detail: 'self-service branch missing [data-role="mfa-management"]' };
|
|
158
|
+
} else if (caps.includes('hostedIdentityUi') && shape === 'hosted-link-out') {
|
|
159
|
+
if (!dom.hasLinkOut) return { verdict: 'fail', detail: 'hosted-link-out branch missing [data-role="hosted-link-out"]' };
|
|
160
|
+
if (!/noopener/.test(dom.linkRel || '')) return { verdict: 'fail', detail: `hosted-link-out missing rel=noopener (rel="${dom.linkRel}")` };
|
|
161
|
+
} else if (caps.includes('hostedIdentityUi') && shape === 'hosted-embed') {
|
|
162
|
+
if (!dom.hasEmbed) return { verdict: 'fail', detail: 'hosted-embed branch missing [data-role="hosted-embed"]' };
|
|
163
|
+
if (!/allow-scripts/.test(dom.embedSandbox || '')) return { verdict: 'fail', detail: `hosted-embed sandbox missing allow-scripts (got "${dom.embedSandbox}")` };
|
|
164
|
+
} else {
|
|
165
|
+
return { verdict: 'fail', detail: `no branch matches caps=${JSON.stringify(caps)} shape="${shape}"` };
|
|
166
|
+
}
|
|
167
|
+
return { verdict: 'pass', detail: `branch=${dom.branch} caps=${JSON.stringify(caps)} shape="${shape}"` };
|
|
168
|
+
},
|
|
169
|
+
},
|
|
170
|
+
{
|
|
171
|
+
id: 'AC-25106-1',
|
|
172
|
+
severity: 'block',
|
|
173
|
+
description: 'Sessions surface renders one row per active session enumerated by data-session-id with device and last-active columns plus a terminate action; opens an ARIA APG dialog-modal on terminate',
|
|
174
|
+
appliesTo: async ({ projectRoot }) => {
|
|
175
|
+
const caps = await readAppliedCapabilities(projectRoot);
|
|
176
|
+
return caps.includes('sessionInventory');
|
|
177
|
+
},
|
|
178
|
+
run: async ({ browser, runtimeUrl }) => {
|
|
179
|
+
if (!browser) return { verdict: 'fail', detail: 'no packBrowser wired' };
|
|
180
|
+
await browser.goto(withUrl(runtimeUrl, '/account/sessions'));
|
|
181
|
+
const dom = await browser.evaluate(() => {
|
|
182
|
+
const region = document.querySelector('[data-surface="sessions"]');
|
|
183
|
+
if (!region) return { present: false };
|
|
184
|
+
const rows = Array.from(region.querySelectorAll('[data-session-id]'));
|
|
185
|
+
const ids = rows.map((r) => r.getAttribute('data-session-id'));
|
|
186
|
+
const firstRowColumns = rows[0] ? Array.from(rows[0].querySelectorAll('[data-column]')).map((c) => c.getAttribute('data-column')) : [];
|
|
187
|
+
const nonCurrentTerminates = rows.filter((r) => r.getAttribute('data-current-session') !== 'true').every((r) => !!r.querySelector('[data-action="terminate"]'));
|
|
188
|
+
const currentRow = rows.find((r) => r.getAttribute('data-current-session') === 'true');
|
|
189
|
+
const currentHasTerminate = currentRow ? !!currentRow.querySelector('[data-action="terminate"]') : false;
|
|
190
|
+
const dialog = region.querySelector('[role="dialog"][aria-modal="true"][data-role="terminate-confirm"]');
|
|
191
|
+
const dialogLabel = dialog ? dialog.getAttribute('aria-labelledby') : null;
|
|
192
|
+
const announce = region.querySelector('[role="status"][aria-live="polite"][data-role="session-terminated-announce"]');
|
|
193
|
+
return { present: true, ids, firstRowColumns, nonCurrentTerminates, currentHasTerminate, dialogPresent: !!dialog, dialogLabel, announcePresent: !!announce };
|
|
194
|
+
});
|
|
195
|
+
if (!dom.present) return { verdict: 'fail', detail: '[data-surface="sessions"] not found' };
|
|
196
|
+
if (dom.ids.length === 0) return { verdict: 'fail', detail: 'sessions surface rendered no rows with data-session-id' };
|
|
197
|
+
const required = ['device', 'lastActive'];
|
|
198
|
+
const missing = required.filter((c) => !dom.firstRowColumns.includes(c));
|
|
199
|
+
if (missing.length > 0) return { verdict: 'fail', detail: `sessions rows missing columns: ${JSON.stringify(missing)} present=${JSON.stringify(dom.firstRowColumns)}` };
|
|
200
|
+
if (!dom.nonCurrentTerminates) return { verdict: 'fail', detail: 'at least one non-current session row missing [data-action="terminate"]' };
|
|
201
|
+
if (dom.currentHasTerminate) return { verdict: 'fail', detail: 'the current-session row must not carry [data-action="terminate"]' };
|
|
202
|
+
if (!dom.dialogPresent) return { verdict: 'fail', detail: 'terminate confirmation dialog [role="dialog"][aria-modal="true"] not rendered' };
|
|
203
|
+
if (!dom.dialogLabel) return { verdict: 'fail', detail: 'dialog missing aria-labelledby' };
|
|
204
|
+
if (!dom.announcePresent) return { verdict: 'fail', detail: 'session-terminated announce region not rendered' };
|
|
205
|
+
return { verdict: 'pass', detail: `rows=${JSON.stringify(dom.ids)} columns=${JSON.stringify(dom.firstRowColumns)} dialog=${dom.dialogPresent}` };
|
|
206
|
+
},
|
|
207
|
+
},
|
|
208
|
+
{
|
|
209
|
+
id: 'AC-25108-1',
|
|
210
|
+
severity: 'block',
|
|
211
|
+
description: 'Theme surface renders as an ARIA APG radiogroup with light/dark/system options and persists per the elicited theme-persistence',
|
|
212
|
+
appliesTo: async ({ projectRoot }) => {
|
|
213
|
+
// The theme surface gates on application-spa being applied. On the
|
|
214
|
+
// fixture side we mirror this via the ?apps=application-spa switch.
|
|
215
|
+
// A future minor bump reads the manifest.blueprints[] set directly;
|
|
216
|
+
// for v1 the applied-blueprint set is inferred from the caps sidecar
|
|
217
|
+
// and the appliedElicitations map (theme-persistence answered => spa applied).
|
|
218
|
+
const elicits = await readAppliedElicitations(projectRoot);
|
|
219
|
+
return typeof elicits['theme-persistence'] === 'string';
|
|
220
|
+
},
|
|
221
|
+
run: async ({ browser, runtimeUrl, projectRoot }) => {
|
|
222
|
+
if (!browser) return { verdict: 'fail', detail: 'no packBrowser wired' };
|
|
223
|
+
const elicits = await readAppliedElicitations(projectRoot);
|
|
224
|
+
const persist = elicits['theme-persistence'] ?? 'spa-local-storage';
|
|
225
|
+
await browser.goto(withUrl(runtimeUrl, `/account/theme?apps=application-spa&theme-persistence=${encodeURIComponent(persist)}`));
|
|
226
|
+
const dom = await browser.evaluate(() => {
|
|
227
|
+
const region = document.querySelector('[data-surface="theme"]');
|
|
228
|
+
if (!region) return { present: false };
|
|
229
|
+
const role = region.getAttribute('role');
|
|
230
|
+
const ariaLabel = region.getAttribute('aria-label');
|
|
231
|
+
const persistAttr = region.getAttribute('data-persist');
|
|
232
|
+
const options = Array.from(region.querySelectorAll('input[type="radio"][name="theme"]')).map((el) => el.getAttribute('value'));
|
|
233
|
+
return { present: true, role, ariaLabel, persistAttr, options };
|
|
234
|
+
});
|
|
235
|
+
if (!dom.present) return { verdict: 'fail', detail: '[data-surface="theme"] not found' };
|
|
236
|
+
if (dom.role !== 'radiogroup') return { verdict: 'fail', detail: `role expected radiogroup, got ${dom.role}` };
|
|
237
|
+
if (!dom.ariaLabel) return { verdict: 'fail', detail: 'radiogroup missing aria-label' };
|
|
238
|
+
const required = ['light', 'dark', 'system'];
|
|
239
|
+
const missing = required.filter((v) => !dom.options.includes(v));
|
|
240
|
+
if (missing.length > 0) return { verdict: 'fail', detail: `radiogroup missing options: ${JSON.stringify(missing)} present=${JSON.stringify(dom.options)}` };
|
|
241
|
+
if (dom.persistAttr !== persist) return { verdict: 'fail', detail: `data-persist expected "${persist}", got "${dom.persistAttr}"` };
|
|
242
|
+
return { verdict: 'pass', detail: `role=${dom.role} options=${JSON.stringify(dom.options)} persist=${dom.persistAttr}` };
|
|
243
|
+
},
|
|
244
|
+
},
|
|
245
|
+
],
|
|
246
|
+
};
|
|
@@ -20,6 +20,13 @@ The blueprint claims no new global topics at v1.0.0. The console is a consumer o
|
|
|
20
20
|
| application-dashboard | 19101-19899 | 20xx | shipped v1.0.0 | none |
|
|
21
21
|
| application-notifications-in-app | 20101-20899 | 21xx | shipped v1.0.0 | none |
|
|
22
22
|
| application-admin-console | 21101-21899 | 22xx | shipped v1.0.0 | none |
|
|
23
|
+
| application-empty-error-states | 22101-22899 | 23xx | shipped v1.0.0 | none |
|
|
24
|
+
| application-file-upload | 23101-23899 | 24xx | shipped v1.0.0 | none |
|
|
25
|
+
| application-forms-wizard | 24101-24899 | 25xx | shipped v1.0.0 | none |
|
|
26
|
+
| application-account-settings | 25101-25899 | 26xx | shipped v1.0.0 | none |
|
|
27
|
+
| application-onboarding-tour | 26101-26899 | 27xx | shipped v1.0.0 | none |
|
|
28
|
+
| persistence-data-postgres | 27101-27899 | 28xx | shipped v1.0.0 | `persistenceStore`, `migrationDiscipline` |
|
|
29
|
+
| object-storage-s3 | 28101-28899 | 29xx | shipped v1.0.0 | `objectStorageContract` |
|
|
23
30
|
|
|
24
31
|
The shelf-wide band registry lives in `packages/rcf-lite/docs/blueprint-authoring.md` section 5.
|
|
25
32
|
|
|
@@ -29,7 +29,7 @@ This table is maintained shelf-wide across every blueprint's `docs/topics.md`. R
|
|
|
29
29
|
| persistence-data-sqlite | 5101-5899 | 6xx | shipped v1.0.0 | `persistenceStore`, `migrationDiscipline` |
|
|
30
30
|
| delivery-ci-workflows | 6101-6899 | 7xx | shipped v2.0.0 (renamed from ci-pipeline) | `ciGates`, `strictCoverageGate`, `releaseArtefacts` |
|
|
31
31
|
| observability-essentials | 7101-7899 | 8xx | shipped v2.0.0 | `statusPageContract` |
|
|
32
|
-
| security-secrets-management | 8101-8899 | 9xx | shipped v1.0.
|
|
32
|
+
| security-secrets-management | 8101-8899 | 9xx | shipped v1.0.1 | `secretsSource` |
|
|
33
33
|
| security-auth-clerk | 9101-9899 | 10xx | shipped v1.0.0 | `authModel` |
|
|
34
34
|
| security-auth-oauth2 | 10101-10899 | 11xx | shipped v1.0.0 | `authModel` |
|
|
35
35
|
| security-auth-keycloak | 11101-11899 | 12xx | shipped v1.0.0 | `authModel` |
|
|
@@ -43,6 +43,13 @@ This table is maintained shelf-wide across every blueprint's `docs/topics.md`. R
|
|
|
43
43
|
| application-dashboard | 19101-19899 | 20xx | shipped v1.0.0 | none |
|
|
44
44
|
| application-notifications-in-app | 20101-20899 | 21xx | shipped v1.0.0 | none |
|
|
45
45
|
| application-admin-console | 21101-21899 | 22xx | shipped v1.0.0 | none |
|
|
46
|
+
| application-empty-error-states | 22101-22899 | 23xx | shipped v1.0.0 | none |
|
|
47
|
+
| application-file-upload | 23101-23899 | 24xx | shipped v1.0.0 | none |
|
|
48
|
+
| application-forms-wizard | 24101-24899 | 25xx | shipped v1.0.0 | none |
|
|
49
|
+
| application-account-settings | 25101-25899 | 26xx | shipped v1.0.0 | none |
|
|
50
|
+
| application-onboarding-tour | 26101-26899 | 27xx | shipped v1.0.0 | none |
|
|
51
|
+
| persistence-data-postgres | 27101-27899 | 28xx | shipped v1.0.0 | `persistenceStore`, `migrationDiscipline` |
|
|
52
|
+
| object-storage-s3 | 28101-28899 | 29xx | shipped v1.0.0 | `objectStorageContract` |
|
|
46
53
|
|
|
47
54
|
Suffix-family ids (ADR, TAC): SPA numbers in the 2xx range, this package takes 3xx (ADR-301 to ADR-308, TAC-301 to TAC-306); the next blueprint should take 4xx.
|
|
48
55
|
|
|
@@ -19,6 +19,13 @@ The blueprint claims no new global topics at v1.0.0. The chart-component contrac
|
|
|
19
19
|
| application-dashboard | 19101-19899 | 20xx | shipped v1.0.0 | none |
|
|
20
20
|
| application-notifications-in-app | 20101-20899 | 21xx | shipped v1.0.0 | none |
|
|
21
21
|
| application-admin-console | 21101-21899 | 22xx | shipped v1.0.0 | none |
|
|
22
|
+
| application-empty-error-states | 22101-22899 | 23xx | shipped v1.0.0 | none |
|
|
23
|
+
| application-file-upload | 23101-23899 | 24xx | shipped v1.0.0 | none |
|
|
24
|
+
| application-forms-wizard | 24101-24899 | 25xx | shipped v1.0.0 | none |
|
|
25
|
+
| application-account-settings | 25101-25899 | 26xx | shipped v1.0.0 | none |
|
|
26
|
+
| application-onboarding-tour | 26101-26899 | 27xx | shipped v1.0.0 | none |
|
|
27
|
+
| persistence-data-postgres | 27101-27899 | 28xx | shipped v1.0.0 | `persistenceStore`, `migrationDiscipline` |
|
|
28
|
+
| object-storage-s3 | 28101-28899 | 29xx | shipped v1.0.0 | `objectStorageContract` |
|
|
22
29
|
|
|
23
30
|
The shelf-wide band registry lives in `packages/rcf-lite/docs/blueprint-authoring.md` section 5.
|
|
24
31
|
|
|
@@ -19,6 +19,13 @@ The blueprint claims no new global topics at v1.0.0. The dashboard-shell contrac
|
|
|
19
19
|
| application-dashboard | 19101-19899 | 20xx | shipped v1.0.0 | none |
|
|
20
20
|
| application-notifications-in-app | 20101-20899 | 21xx | shipped v1.0.0 | none |
|
|
21
21
|
| application-admin-console | 21101-21899 | 22xx | shipped v1.0.0 | none |
|
|
22
|
+
| application-empty-error-states | 22101-22899 | 23xx | shipped v1.0.0 | none |
|
|
23
|
+
| application-file-upload | 23101-23899 | 24xx | shipped v1.0.0 | none |
|
|
24
|
+
| application-forms-wizard | 24101-24899 | 25xx | shipped v1.0.0 | none |
|
|
25
|
+
| application-account-settings | 25101-25899 | 26xx | shipped v1.0.0 | none |
|
|
26
|
+
| application-onboarding-tour | 26101-26899 | 27xx | shipped v1.0.0 | none |
|
|
27
|
+
| persistence-data-postgres | 27101-27899 | 28xx | shipped v1.0.0 | `persistenceStore`, `migrationDiscipline` |
|
|
28
|
+
| object-storage-s3 | 28101-28899 | 29xx | shipped v1.0.0 | `objectStorageContract` |
|
|
22
29
|
|
|
23
30
|
The shelf-wide band registry lives in `packages/rcf-lite/docs/blueprint-authoring.md` section 5.
|
|
24
31
|
|
|
@@ -18,6 +18,13 @@ The blueprint claims no new global topics at v1.0.0. The datatable shell is a ge
|
|
|
18
18
|
| application-dashboard | 19101-19899 | 20xx | shipped v1.0.0 | none |
|
|
19
19
|
| application-notifications-in-app | 20101-20899 | 21xx | shipped v1.0.0 | none |
|
|
20
20
|
| application-admin-console | 21101-21899 | 22xx | shipped v1.0.0 | none |
|
|
21
|
+
| application-empty-error-states | 22101-22899 | 23xx | shipped v1.0.0 | none |
|
|
22
|
+
| application-file-upload | 23101-23899 | 24xx | shipped v1.0.0 | none |
|
|
23
|
+
| application-forms-wizard | 24101-24899 | 25xx | shipped v1.0.0 | none |
|
|
24
|
+
| application-account-settings | 25101-25899 | 26xx | shipped v1.0.0 | none |
|
|
25
|
+
| application-onboarding-tour | 26101-26899 | 27xx | shipped v1.0.0 | none |
|
|
26
|
+
| persistence-data-postgres | 27101-27899 | 28xx | shipped v1.0.0 | `persistenceStore`, `migrationDiscipline` |
|
|
27
|
+
| object-storage-s3 | 28101-28899 | 29xx | shipped v1.0.0 | `objectStorageContract` |
|
|
21
28
|
|
|
22
29
|
The shelf-wide band registry lives in `packages/rcf-lite/docs/blueprint-authoring.md` section 5.
|
|
23
30
|
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# application-empty-error-states CHANGELOG
|
|
2
|
+
|
|
3
|
+
## 1.0.0 (visual round T-1, spec 2026-09-06)
|
|
4
|
+
|
|
5
|
+
- First ratified version of the shelf's empty-and-error-states blueprint. Five REQs (state catalogue with eight named states, recovery-action contract, announcement contract with role region and aria-live polite, least-privilege 5xx and 403 posture, offline state with write-buffer and reconnection semantics), eight USs 22101-22108 binding one runtime-observable AC per named state, three TACs 2301-2303 (state-machine, recovery-action router, offline write-buffer), three ADRs 2301-2303 (HTTP status contract per RFC 9110 as recommendedDefault, stack-trace visibility elicited with recommendedDefault true, offline strategy across write-buffer read-only-banner and refuse-writes elicited). No new global topics.
|
|
6
|
+
- Ships `probe-packs/application-empty-error-states.pack.mjs`: eight surface-observable browser-verify checks anchored one per named state (`AC-22101-1` not-found, `AC-22102-1` forbidden, `AC-22103-1` server-error, `AC-22104-1` permission-denied, `AC-22105-1` offline, `AC-22106-1` empty-list, `AC-22107-1` no-search-results, `AC-22108-1` error-boundary). Every URL is composed by the `withUrl(runtimeUrl, path)` helper per the round 3 T-3 fix train; no bare string concatenation. The pack-level `appliesTo` predicate references BOTH `tacIds` (TAC-2301) AND `route` (the operator-configured error-shell path glob).
|
|
7
|
+
- Ships a dependency-free sample-app fixture at `packages/rcf-lite/test/fixtures/probe-pack-application-empty-error-states/` with a Node HTTP server realising all eight states honestly under `/probe/<name>` and break switches (`?break=stack-trace`, `?break=leak-id`, `?break=no-recovery`, `?break=no-live-region`) driving the negative runs from a single boot. The fixture ships its own README naming PORT, every `?state=`, every `?break=`, the manual boot line and the two-line gate-reviewer boot.
|
|
8
|
+
- Declares `suggestedCompanions` `logging` (every rendered error state writes one request-scoped log line with the correlation identifier) and `errorHandling` (the error-boundary state constructs an internal error record from the caught exception). Does NOT declare `providesRoles` (leaf blueprint per spec; loader refuses an empty `providesRoles` array when set, so the leaf-blueprint intent is expressed by omitting the field). Does NOT declare `capabilities` and does NOT declare `requiresAppliedCapabilities` (no auth required).
|
|
9
|
+
- Sixth shipped consumer of T-0's probe-pack runner extension. T-3 `application-forms-wizard` consumes this blueprint for its "no in-progress forms" empty state; T-4 `application-account-settings` consumes this blueprint for its access-denied and empty-history states.
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# Empty and error states blueprint (v1.0.0)
|
|
2
|
+
|
|
3
|
+
Vendor-neutral empty-and-error-states contract for an rcf-lite application. Ships eight named states, one contract per state: `not-found` (404), `forbidden` (403), `server-error` (500), `offline`, `permission-denied` (403 with a per-resource cause), `empty-list`, `no-search-results`, `error-boundary` (client-side render failure). Each state carries a machine-readable status, a distinct visual, a `role="region"` accessible name, one recovery-action shape from a closed enum, and a polite live-region wrapper for progress and reconnection announcements. Ships a Playwright probe pack under `probe-packs/application-empty-error-states.pack.mjs` whose eight checks each anchor one named state, refuse on the corresponding break switch, and fire against the sample-app fixture on the shelf gate.
|
|
4
|
+
|
|
5
|
+
## Apply
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
rcf define blueprint add <path-to>/blueprints/application-empty-error-states
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Applies 19 contributions (5 REQs, 8 USs, 3 TACs, 3 ADRs) cleanly on any fresh init project. No `requiresAppliedCapabilities`, no auth prerequisite, no elicited-only parameters that block the apply; the two elicits (`ADR-2302` stack-trace visibility and `ADR-2303` offline strategy) carry recommended defaults so the apply proceeds silently and the project can revisit the elicited answers later.
|
|
12
|
+
|
|
13
|
+
## Anatomy
|
|
14
|
+
|
|
15
|
+
| Piece | Where | What |
|
|
16
|
+
|---|---|---|
|
|
17
|
+
| Metadata | `blueprint.json` | Slug, version 1.0.0, category `application`, `suggestedCompanions: [logging, errorHandling]`, 19 contributions in the 23xx / 22xxx band |
|
|
18
|
+
| Doc set | `contributions/` | 5 REQs, 8 USs (8 runtime-observable ACs), 3 TACs, 3 ADRs |
|
|
19
|
+
| Probe pack | `probe-packs/application-empty-error-states.pack.mjs` | Eight surface-observable browser-verify checks, one per named state |
|
|
20
|
+
| Guide | `guide/application-empty-error-states.md` | Operator-facing: when to reach, when not, mechanism-reach gaps |
|
|
21
|
+
| Coordination vocabulary | `docs/topics.md` | Shelf id band registry update; no new global topics claimed |
|
|
22
|
+
| Sample-app fixture | `packages/rcf-lite/test/fixtures/probe-pack-application-empty-error-states/` | Dependency-free Node HTTP server the pack is probed against on the shelf gate |
|
|
23
|
+
|
|
24
|
+
## The eight named states
|
|
25
|
+
|
|
26
|
+
| State | HTTP status | Recovery shape(s) | Announcement | Region wrapper |
|
|
27
|
+
|---|---|---|---|---|
|
|
28
|
+
| `not-found` | 404 | `parent-surface` + `search` | polite live-region | `[data-surface="not-found"]` |
|
|
29
|
+
| `forbidden` | 403 (no per-resource cause) | `request-access` | polite live-region | `[data-surface="forbidden"]` |
|
|
30
|
+
| `server-error` | 5xx | `retry` | polite live-region | `[data-surface="server-error"]` |
|
|
31
|
+
| `permission-denied` | 403 (class-level cause) | `request-access` | polite live-region | `[data-surface="permission-denied"]` |
|
|
32
|
+
| `offline` | (no HTTP; `navigator.onLine` false) | `retry` (implicit on reconnection) | polite live-region for reconnection | `[data-surface="offline"]` |
|
|
33
|
+
| `empty-list` | 200 (empty array on a listing endpoint) | `create` | polite live-region | `[data-surface="empty-list"]` |
|
|
34
|
+
| `no-search-results` | 200 (empty array on a search endpoint) | `clear-filters` | polite live-region | `[data-surface="no-search-results"]` |
|
|
35
|
+
| `error-boundary` | (no HTTP; caught client-side render exception) | `retry` | `role="alert"` (assertive) | `[data-surface="error-boundary"]` |
|
|
36
|
+
|
|
37
|
+
The eight-state enum is closed at v1.0.0. A ninth state is a v1.1.0 minor bump; a state removed or renamed is a v2.0.0 major.
|
|
38
|
+
|
|
39
|
+
## Recovery-action router
|
|
40
|
+
|
|
41
|
+
The closed set of recovery shapes: `parent-surface`, `search`, `request-access`, `retry`, `create`, `clear-filters`, `no-recovery`. Every rendered state carries at least one. The router refuses to render a state without a legitimate shape; a bare state region without any recovery is a build defect the pack catches.
|
|
42
|
+
|
|
43
|
+
## Offline strategy
|
|
44
|
+
|
|
45
|
+
`ADR-2303` commits to `write-buffer` as the default (IndexedDB, idempotency token per write, monotonic sequence, flush in sequence on reconnection with server-side dedupe). Elicited alternatives: `read-only-banner` and `refuse-writes`. All three shapes render the offline region and the polite reconnection announcement per REQ-005; the difference is only whether writes queue, disable or refuse.
|
|
46
|
+
|
|
47
|
+
## Elicited parameters
|
|
48
|
+
|
|
49
|
+
- **States in scope for v1.** Default: all eight. A project that has not yet shipped offline mode can elicit a reduced set; the pack skips checks whose state is out of scope on that project.
|
|
50
|
+
- **Recovery-action targets per state.** Default: the router's built-ins (parent-surface, search, request-access, retry, create, clear-filters). Projects override the endpoint paths and callbacks per FBS.
|
|
51
|
+
- **Stack-trace visibility in production.** Default: true (hidden). `ADR-2302` elicits an override for staging.
|
|
52
|
+
- **Offline strategy.** Default: `write-buffer`. `ADR-2303` elicits `read-only-banner` or `refuse-writes`.
|
|
53
|
+
|
|
54
|
+
## The one runtime gate
|
|
55
|
+
|
|
56
|
+
`probe-packs/application-empty-error-states.pack.mjs` ships eight checks the `rcf verify browser` runner invokes on any FBS whose surface binds `TAC-2301-application-empty-error-states-state-machine` or whose nav model routes name an operator-configured error-shell path. Each check drives the real Playwright browser the runner provisions, reads the accessibility tree and the DOM, and returns a verdict. URLs are composed by the `withUrl(runtimeUrl, path)` helper per the round 3 T-3 fix train; no bare string concatenation.
|
|
57
|
+
|
|
58
|
+
## Quality bar
|
|
59
|
+
|
|
60
|
+
WCAG 2.2 AA on every state region: 3.3.1 Error Identification (every error state names the error class in the heading), 2.4.6 Headings and Labels (every region carries a heading and an accessible name), 3.2.4 Consistent Identification (every recovery control carries the same `data-recovery` attribute across states), 4.1.3 Status Messages (every progress and reconnection announcement fires through the polite live-region wrapper), 3.3.3 Error Suggestion (the recovery-action prose names the next action, not just the error). HTTP semantics per RFC 9110 for the status-code contract (ADR-2301). ARIA APG alert pattern on `error-boundary`. `standardsTrace` on the blueprint is empty (this is a general-enterprise-practice blueprint); each ADR contribution carries `standardsTraceClause` naming the clause it implements.
|
|
61
|
+
|
|
62
|
+
The 500 surface is a CSP-shape enforcement. `AC-22103-1` reads the rendered surface, tokenises against a bundled sensitive-pattern list (backtrace-frame prefix, source-path shape, environment-variable key shape, framework-internal frame prefix, `process.env.NAME` reference), and refuses when any pattern matches.
|
|
63
|
+
|
|
64
|
+
## Known mechanism-reach gaps
|
|
65
|
+
|
|
66
|
+
Runtime-observable ACs the pack does NOT bind directly (checklist section 6.g), listed individually per AC id:
|
|
67
|
+
|
|
68
|
+
- **AC-22101-1 keyboard-focus-on-recovery.** The pack asserts the parent-surface link and the search entry exist and carry the correct `data-recovery` attribute; it does NOT additionally probe that keyboard focus lands on the recovery control on state entry. A v1.1.0 minor bump can drive the browser's accessibility tree and assert focus placement.
|
|
69
|
+
- **AC-22102-1 request-access transport round-trip.** The pack asserts the `[data-action="request-access"]` control exists; it does NOT additionally exercise the POST round-trip and assert the applied notification centre receives the submission. A v1.1.0 minor bump can invoke the click path and inspect the network request log.
|
|
70
|
+
- **AC-22103-1 non-production staging branch.** The pack drives the production branch (`?break=stack-trace` is the negative run for the production posture); the elicited staging-visible branch (`ADR-2302`) is present on the fixture through the same break switch but the pack does not additionally probe the staging-legitimate render.
|
|
71
|
+
- **AC-22104-1 cause-string vocabulary registry.** The pack asserts the class-level cause is present and refuses when a resource-id shape appears; it does NOT additionally cross-check the cause string against a project-side vocabulary registry. A v1.1.0 minor bump can read a project-declared vocabulary file and diff.
|
|
72
|
+
- **AC-22105-1 write-buffer flush order.** The pack asserts a synthetic buffered write is enumerable on `window.__offlineBuffer` and that the polite reconnection announcement fires; it does NOT additionally probe that a multi-entry buffer flushes in sequence with per-entry retry counters. A v1.1.0 minor bump can seed a multi-entry buffer and drive the flush loop.
|
|
73
|
+
- **AC-22106-1 empty-list distinction from loading.** The pack asserts the `[data-visual="empty-list"]` wrapper is present; it does NOT additionally probe that the wrapper is distinct from `[data-visual="loading"]` and `[data-visual="loaded"]` on the same route. A v1.1.0 minor bump can drive the loading branch and diff the wrapper attributes.
|
|
74
|
+
- **AC-22107-1 clear-filters callback shape.** The pack asserts the `[data-recovery="clear-filters"]` control exists and echoes the query; it does NOT additionally exercise the callback and assert the search parameters are removed from the URL. A v1.1.0 minor bump can drive the click path and inspect the resulting URL.
|
|
75
|
+
- **AC-22108-1 boundary retry re-mounts the component.** The pack asserts the `role="alert"` region and the retry control exist; it does NOT additionally probe that the retry re-mounts the crashed component subtree. A v1.1.0 minor bump can drive the click path and inspect the DOM diff.
|
|
76
|
+
|
|
77
|
+
## Companions
|
|
78
|
+
|
|
79
|
+
`suggestedCompanions` declares `logging` (every rendered error state writes one request-scoped log line with the correlation identifier the applied logger factory returns) and `errorHandling` (the error-boundary state constructs an internal error record from the caught exception through the applied error-handling factory). Neither is required to apply the blueprint; a project without a logging companion still ships every state region, it just does not emit a per-state log line.
|
|
80
|
+
|
|
81
|
+
## Consumers
|
|
82
|
+
|
|
83
|
+
- `application-forms-wizard` (T-3 of this round) consumes the empty-list state as its "no in-progress forms" surface; the wizard's empty branch delegates to this blueprint's TAC-2301 state machine.
|
|
84
|
+
- `application-account-settings` (T-4 of this round) consumes the access-denied path (forbidden and permission-denied) for its scope-gated settings sections and the empty-list state for its empty-history surfaces.
|
|
85
|
+
|
|
86
|
+
## Composition with application-spa
|
|
87
|
+
|
|
88
|
+
`application-spa` REQ-006 ships empty, loading, error, banner and alert components as part of its component library. This blueprint composes with SPA; the topic-ownership boundary lives in `docs/topics.md`. SPA owns the tab-title convention and the state-visual tokens; this sibling owns the state list, the recovery-action router and the runtime enforcement pack.
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
{
|
|
2
|
+
"slug": "application-empty-error-states",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"category": "application",
|
|
5
|
+
"suggestedCompanions": [
|
|
6
|
+
{
|
|
7
|
+
"role": "logging",
|
|
8
|
+
"reason": "Every rendered error state writes one request-scoped log line with the correlation identifier; a logging companion supplies the factory the pipeline calls."
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
"role": "errorHandling",
|
|
12
|
+
"reason": "The error-boundary state constructs an internal error record from the caught exception; an error-handling companion supplies the factory and the boundary."
|
|
13
|
+
}
|
|
14
|
+
],
|
|
15
|
+
"contributions": [
|
|
16
|
+
{
|
|
17
|
+
"id": "application-empty-error-states-REQ-001",
|
|
18
|
+
"kind": "req",
|
|
19
|
+
"path": "requirements/application-empty-error-states-req-001.json"
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
"id": "application-empty-error-states-REQ-002",
|
|
23
|
+
"kind": "req",
|
|
24
|
+
"path": "requirements/application-empty-error-states-req-002.json"
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
"id": "application-empty-error-states-REQ-003",
|
|
28
|
+
"kind": "req",
|
|
29
|
+
"path": "requirements/application-empty-error-states-req-003.json"
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
"id": "application-empty-error-states-REQ-004",
|
|
33
|
+
"kind": "req",
|
|
34
|
+
"path": "requirements/application-empty-error-states-req-004.json"
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
"id": "application-empty-error-states-REQ-005",
|
|
38
|
+
"kind": "req",
|
|
39
|
+
"path": "requirements/application-empty-error-states-req-005.json"
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
"id": "application-empty-error-states-US-22101",
|
|
43
|
+
"kind": "us",
|
|
44
|
+
"path": "user-stories/application-empty-error-states-us-22101.json"
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
"id": "application-empty-error-states-US-22102",
|
|
48
|
+
"kind": "us",
|
|
49
|
+
"path": "user-stories/application-empty-error-states-us-22102.json"
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
"id": "application-empty-error-states-US-22103",
|
|
53
|
+
"kind": "us",
|
|
54
|
+
"path": "user-stories/application-empty-error-states-us-22103.json"
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
"id": "application-empty-error-states-US-22104",
|
|
58
|
+
"kind": "us",
|
|
59
|
+
"path": "user-stories/application-empty-error-states-us-22104.json"
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
"id": "application-empty-error-states-US-22105",
|
|
63
|
+
"kind": "us",
|
|
64
|
+
"path": "user-stories/application-empty-error-states-us-22105.json"
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
"id": "application-empty-error-states-US-22106",
|
|
68
|
+
"kind": "us",
|
|
69
|
+
"path": "user-stories/application-empty-error-states-us-22106.json"
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
"id": "application-empty-error-states-US-22107",
|
|
73
|
+
"kind": "us",
|
|
74
|
+
"path": "user-stories/application-empty-error-states-us-22107.json"
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
"id": "application-empty-error-states-US-22108",
|
|
78
|
+
"kind": "us",
|
|
79
|
+
"path": "user-stories/application-empty-error-states-us-22108.json"
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
"id": "TAC-2301-application-empty-error-states-state-machine",
|
|
83
|
+
"kind": "tac",
|
|
84
|
+
"path": "tacs/tac-2301-application-empty-error-states-state-machine.json"
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
"id": "TAC-2302-application-empty-error-states-recovery-router",
|
|
88
|
+
"kind": "tac",
|
|
89
|
+
"path": "tacs/tac-2302-application-empty-error-states-recovery-router.json"
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
"id": "TAC-2303-application-empty-error-states-offline-buffer",
|
|
93
|
+
"kind": "tac",
|
|
94
|
+
"path": "tacs/tac-2303-application-empty-error-states-offline-buffer.json"
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
"id": "ADR-2301-application-empty-error-states-status-contract",
|
|
98
|
+
"kind": "adr",
|
|
99
|
+
"path": "adrs/adr-2301-application-empty-error-states-status-contract.json",
|
|
100
|
+
"recommendedDefault": true,
|
|
101
|
+
"standardsTraceClause": "RFC 9110"
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
"id": "ADR-2302-application-empty-error-states-stack-trace-visibility",
|
|
105
|
+
"kind": "adr",
|
|
106
|
+
"path": "adrs/adr-2302-application-empty-error-states-stack-trace-visibility.json",
|
|
107
|
+
"recommendedDefault": true,
|
|
108
|
+
"elicited": true,
|
|
109
|
+
"standardsTraceClause": "OWASP ASVS V7 error handling"
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
"id": "ADR-2303-application-empty-error-states-offline-strategy",
|
|
113
|
+
"kind": "adr",
|
|
114
|
+
"path": "adrs/adr-2303-application-empty-error-states-offline-strategy.json",
|
|
115
|
+
"elicited": true,
|
|
116
|
+
"standardsTraceClause": "generic enterprise practice"
|
|
117
|
+
}
|
|
118
|
+
]
|
|
119
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"adrId": "ADR-2301-application-empty-error-states-status-contract",
|
|
3
|
+
"prdId": "PRD-001",
|
|
4
|
+
"tadId": "TAD-001",
|
|
5
|
+
"version": "1.0.0",
|
|
6
|
+
"status": "accepted",
|
|
7
|
+
"title": "HTTP status to rendered state mapping follows RFC 9110 semantics",
|
|
8
|
+
"context": "The blueprint dispatches states from HTTP responses. There are three plausible mappings from status to rendered state: honour RFC 9110 semantics verbatim (404 to not-found, 403 to forbidden, 5xx to server-error, empty 200 to empty-list or no-search-results depending on the endpoint kind); collapse all client errors into a single generic client-error state; or lean on a bespoke response-body flag the server includes to name the state. The first is the least-surprising choice for a shelf blueprint whose surfaces will be composed with vendor libraries that emit plain HTTP; the second loses the affordances (parent-surface link on 404, request-access on 403) that make the state useful; the third couples the client tightly to a server contract the shelf does not otherwise mint.",
|
|
9
|
+
"decision": "Adopt RFC 9110 semantics verbatim as the state-machine's status mapping. 404 dispatches not-found; 403 dispatches forbidden by default and permission-denied when the response body carries a class-level cause string; 5xx dispatches server-error. An empty 200 response body on a listing endpoint dispatches empty-list; an empty 200 on a search endpoint (identified by a q query parameter or an FBS-declared search route) dispatches no-search-results. This mapping is the recommendedDefault per the ADR contribution field.",
|
|
10
|
+
"consequences": "Projects composing REST APIs that already answer RFC 9110 status codes get the state dispatch for free. Projects using an RPC-style API layer must wrap their transport in a small adapter that raises the plain status code. The state machine remains stable across vendor libraries (fetch, axios, tRPC clients, GraphQL error-code conventions that project the transport-level status) because the contract is on the status number the machine reads, not on a bespoke body flag.",
|
|
11
|
+
"alternativesConsidered": [
|
|
12
|
+
{
|
|
13
|
+
"name": "Collapse client errors into one generic state",
|
|
14
|
+
"summary": "Route every 4xx into a single client-error state with a generic recovery.",
|
|
15
|
+
"reasonNotChosen": "Loses the four recovery-shape specialisations (parent-surface on 404, request-access on 403, retry on 5xx, clear-filters on no-search-results) that make the state actionable and forces every recovery through a generic retry."
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"name": "Bespoke response-body state-name field",
|
|
19
|
+
"summary": "Require every response body to carry a stateName string the machine reads.",
|
|
20
|
+
"reasonNotChosen": "Couples the shelf blueprint tightly to a server contract the shelf does not otherwise mint; a vendor library returning plain HTTP would be unsupported by default."
|
|
21
|
+
}
|
|
22
|
+
],
|
|
23
|
+
"createdAt": "2026-09-06T15:40:00Z",
|
|
24
|
+
"updatedAt": "2026-09-06T15:40:00Z"
|
|
25
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"adrId": "ADR-2302-application-empty-error-states-stack-trace-visibility",
|
|
3
|
+
"prdId": "PRD-001",
|
|
4
|
+
"tadId": "TAD-001",
|
|
5
|
+
"version": "1.0.0",
|
|
6
|
+
"status": "accepted",
|
|
7
|
+
"title": "The server-error state hides stack traces, source paths and environment-variable keys in production",
|
|
8
|
+
"context": "The 5xx state is the most tempting surface for a debug leak because a stack trace is the first thing a developer would like on-screen when something breaks. In production the same surface is a probing target for an attacker: a stack trace names framework versions and internal frame layouts; a source path names filesystem structure; an environment-variable key shape names the deploy environment's configuration surface. Staging environments legitimately want the debug detail; production does not.",
|
|
9
|
+
"decision": "In production the server-error state renders a plain summary line and a retry recovery hook only. The rendered surface refuses any word matching the sensitive-pattern list: backtrace-frame prefixes (\"at <fn>(<file>:<line>:<col>)\" and variants), source paths (leading /, ./, ../), environment-variable key shape (NAME= or process.env.NAME references), and framework-internal frame prefixes. In non-production environments (staging, local) the elicited stack-trace-visible parameter may flip the guard off; the pack still fires on staging so a leak that reaches production is caught before ship. recommendedDefault is true; elicited is true so the operator can flip the guard for staging or for a build that renders the debug region behind a role gate.",
|
|
10
|
+
"consequences": "Projects on the recommended default get the least-privilege posture with no configuration. Projects that want a debug region in staging author the elicited toggle and add a role-gated debug region behind an operator scope. The pack fires on both branches with the appropriate expectation. A production build that ships with the toggle flipped on refuses the ship gate through this pack's AC-22103-1.",
|
|
11
|
+
"alternativesConsidered": [
|
|
12
|
+
{
|
|
13
|
+
"name": "Always render the stack trace",
|
|
14
|
+
"summary": "Ship the full stack trace in every environment, on the theory that the operator will see it before an attacker does.",
|
|
15
|
+
"reasonNotChosen": "In practice an attacker triggers 5xx surfaces at will (bad payloads, malformed routes); the stack trace ships to their browser too. The debug value in production is negligible compared to the leak."
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"name": "Server-side redaction only",
|
|
19
|
+
"summary": "Rely on the server to strip the stack trace before it reaches the client.",
|
|
20
|
+
"reasonNotChosen": "The client-side error boundary also renders 5xx surfaces from caught JS exceptions that never touched the server; a server-side redactor cannot cover the client boundary."
|
|
21
|
+
}
|
|
22
|
+
],
|
|
23
|
+
"createdAt": "2026-09-06T15:40:00Z",
|
|
24
|
+
"updatedAt": "2026-09-06T15:40:00Z"
|
|
25
|
+
}
|