rcf-lite 0.29.0 → 0.31.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 +133 -0
- package/blueprints/application-account-settings/contributions/requirements/application-account-settings-req-001.json +1 -1
- package/blueprints/application-account-settings/contributions/requirements/application-account-settings-req-002.json +1 -1
- package/blueprints/application-account-settings/contributions/requirements/application-account-settings-req-003.json +1 -1
- package/blueprints/application-account-settings/contributions/requirements/application-account-settings-req-004.json +1 -1
- package/blueprints/application-account-settings/contributions/requirements/application-account-settings-req-005.json +1 -1
- package/blueprints/application-account-settings/contributions/requirements/application-account-settings-req-006.json +1 -1
- package/blueprints/application-account-settings/contributions/requirements/application-account-settings-req-007.json +1 -1
- package/blueprints/application-account-settings/contributions/requirements/application-account-settings-req-009.json +1 -1
- package/blueprints/application-account-settings/contributions/tacs/tac-2601-application-account-settings-shell.json +4 -4
- package/blueprints/application-account-settings/contributions/tacs/tac-2602-application-account-settings-capability-discovery.json +2 -2
- package/blueprints/application-account-settings/contributions/tacs/tac-2603-application-account-settings-hosted-ui-bridge.json +2 -2
- package/blueprints/application-account-settings/contributions/tacs/tac-2604-application-account-settings-session-store.json +7 -7
- package/blueprints/application-account-settings/contributions/user-stories/application-account-settings-us-25105.json +3 -15
- package/blueprints/application-account-settings/contributions/user-stories/application-account-settings-us-25106.json +2 -10
- package/blueprints/application-account-settings/contributions/user-stories/application-account-settings-us-25111.json +3 -6
- package/blueprints/application-account-settings/contributions/user-stories/application-account-settings-us-25112.json +4 -4
- package/blueprints/application-admin-console/contributions/requirements/application-admin-console-req-001.json +1 -1
- package/blueprints/application-admin-console/contributions/requirements/application-admin-console-req-002.json +1 -1
- package/blueprints/application-admin-console/contributions/requirements/application-admin-console-req-003.json +1 -1
- package/blueprints/application-admin-console/contributions/requirements/application-admin-console-req-004.json +1 -1
- package/blueprints/application-admin-console/contributions/requirements/application-admin-console-req-005.json +1 -1
- package/blueprints/application-admin-console/contributions/requirements/application-admin-console-req-006.json +1 -1
- package/blueprints/application-admin-console/contributions/requirements/application-admin-console-req-007.json +1 -1
- package/blueprints/application-admin-console/contributions/requirements/application-admin-console-req-008.json +1 -1
- package/blueprints/application-admin-console/contributions/requirements/application-admin-console-req-009.json +1 -1
- package/blueprints/application-admin-console/contributions/requirements/application-admin-console-req-014.json +1 -1
- package/blueprints/application-admin-console/contributions/tacs/tac-2201-application-admin-console-shell.json +4 -4
- package/blueprints/application-admin-console/contributions/tacs/tac-2202-application-admin-console-capability-discovery.json +7 -7
- package/blueprints/application-admin-console/contributions/tacs/tac-2203-application-admin-console-permission-matrix.json +2 -2
- package/blueprints/application-admin-console/contributions/tacs/tac-2204-application-admin-console-audit-view.json +2 -2
- package/blueprints/application-admin-console/contributions/tacs/tac-2214-application-admin-console-access-gated-signin-surface.json +3 -2
- package/blueprints/application-admin-console/contributions/user-stories/application-admin-console-us-21107.json +2 -2
- package/blueprints/application-admin-console/contributions/user-stories/application-admin-console-us-21111.json +3 -11
- package/blueprints/application-admin-console/contributions/user-stories/application-admin-console-us-21112.json +4 -4
- package/blueprints/application-admin-console/contributions/user-stories/application-admin-console-us-21815.json +2 -2
- package/blueprints/application-admin-console/contributions/user-stories/application-admin-console-us-21816.json +2 -2
- package/blueprints/application-api-rest/contributions/requirements/application-api-rest-req-001.json +1 -1
- package/blueprints/application-api-rest/contributions/requirements/application-api-rest-req-002.json +1 -2
- package/blueprints/application-api-rest/contributions/requirements/application-api-rest-req-004.json +1 -1
- package/blueprints/application-api-rest/contributions/requirements/application-api-rest-req-008.json +1 -1
- package/blueprints/application-api-rest/contributions/requirements/application-api-rest-req-016.json +1 -1
- package/blueprints/application-api-rest/contributions/tacs/tac-301-application-api-rest-request-pipeline.json +4 -4
- package/blueprints/application-api-rest/contributions/tacs/tac-302-application-api-rest-auth-middleware.json +4 -4
- package/blueprints/application-api-rest/contributions/tacs/tac-303-application-api-rest-contract-surface.json +4 -4
- package/blueprints/application-api-rest/contributions/tacs/tac-304-application-api-rest-resource-layer.json +4 -4
- package/blueprints/application-api-rest/contributions/tacs/tac-305-application-api-rest-observability.json +4 -4
- package/blueprints/application-api-rest/contributions/tacs/tac-306-application-api-rest-operability.json +4 -4
- package/blueprints/application-api-rest/contributions/user-stories/application-api-rest-us-2102.json +1 -1
- package/blueprints/application-api-rest/contributions/user-stories/application-api-rest-us-2103.json +1 -1
- package/blueprints/application-api-rest/contributions/user-stories/application-api-rest-us-2104.json +4 -4
- package/blueprints/application-api-rest/contributions/user-stories/application-api-rest-us-2105.json +2 -2
- package/blueprints/application-api-rest/contributions/user-stories/application-api-rest-us-2108.json +1 -1
- package/blueprints/application-api-rest/contributions/user-stories/application-api-rest-us-2110.json +1 -1
- package/blueprints/application-api-rest/contributions/user-stories/application-api-rest-us-2111.json +1 -1
- package/blueprints/application-api-rest/contributions/user-stories/application-api-rest-us-2118.json +1 -1
- package/blueprints/application-api-rest/contributions/user-stories/application-api-rest-us-2119.json +2 -2
- package/blueprints/application-charts/contributions/tacs/tac-1901-application-charts-render-shell.json +4 -4
- package/blueprints/application-charts/contributions/tacs/tac-1902-application-charts-keyboard-traversal.json +4 -4
- package/blueprints/application-charts/contributions/user-stories/application-charts-us-18105.json +1 -1
- package/blueprints/application-dashboard/contributions/tacs/tac-2001-application-dashboard-tile-grid.json +4 -4
- package/blueprints/application-dashboard/contributions/tacs/tac-2002-application-dashboard-filter-chrome.json +4 -4
- package/blueprints/application-dashboard/contributions/tacs/tac-2003-application-dashboard-export-handle.json +2 -2
- package/blueprints/application-dashboard/contributions/user-stories/application-dashboard-us-19106.json +1 -1
- package/blueprints/application-datatable/contributions/tacs/tac-1801-application-datatable-shell.json +4 -4
- package/blueprints/application-datatable/contributions/tacs/tac-1802-application-datatable-query-adapter.json +4 -4
- package/blueprints/application-datatable/contributions/tacs/tac-1803-application-datatable-selection-model.json +2 -2
- package/blueprints/application-datatable/contributions/user-stories/application-datatable-us-17101.json +1 -1
- package/blueprints/application-datatable/contributions/user-stories/application-datatable-us-17102.json +1 -1
- package/blueprints/application-datatable/contributions/user-stories/application-datatable-us-17103.json +1 -1
- package/blueprints/application-datatable/contributions/user-stories/application-datatable-us-17105.json +1 -1
- package/blueprints/application-empty-error-states/contributions/requirements/application-empty-error-states-req-001.json +1 -1
- package/blueprints/application-empty-error-states/contributions/requirements/application-empty-error-states-req-002.json +1 -1
- package/blueprints/application-empty-error-states/contributions/requirements/application-empty-error-states-req-003.json +1 -1
- package/blueprints/application-empty-error-states/contributions/requirements/application-empty-error-states-req-004.json +1 -1
- package/blueprints/application-empty-error-states/contributions/requirements/application-empty-error-states-req-005.json +2 -2
- package/blueprints/application-empty-error-states/contributions/requirements/application-empty-error-states-req-006.json +1 -1
- package/blueprints/application-empty-error-states/contributions/requirements/application-empty-error-states-req-007.json +2 -2
- package/blueprints/application-empty-error-states/contributions/tacs/tac-2301-application-empty-error-states-state-machine.json +5 -5
- package/blueprints/application-empty-error-states/contributions/tacs/tac-2302-application-empty-error-states-recovery-router.json +2 -2
- package/blueprints/application-empty-error-states/contributions/tacs/tac-2303-application-empty-error-states-offline-buffer.json +5 -5
- package/blueprints/application-error-handling/contributions/tacs/tac-1701-application-error-handling-boundary.json +6 -6
- package/blueprints/application-error-handling/contributions/tacs/tac-1702-application-error-handling-record-factory.json +4 -4
- package/blueprints/application-error-handling/contributions/user-stories/application-error-handling-us-16101.json +1 -1
- package/blueprints/application-error-handling/contributions/user-stories/application-error-handling-us-16107.json +4 -4
- package/blueprints/application-file-upload/contributions/requirements/application-file-upload-req-001.json +1 -1
- package/blueprints/application-file-upload/contributions/requirements/application-file-upload-req-002.json +1 -1
- package/blueprints/application-file-upload/contributions/requirements/application-file-upload-req-003.json +1 -1
- package/blueprints/application-file-upload/contributions/requirements/application-file-upload-req-004.json +1 -1
- package/blueprints/application-file-upload/contributions/requirements/application-file-upload-req-005.json +1 -1
- package/blueprints/application-file-upload/contributions/requirements/application-file-upload-req-006.json +2 -2
- package/blueprints/application-file-upload/contributions/requirements/application-file-upload-req-007.json +2 -2
- package/blueprints/application-file-upload/contributions/tacs/tac-2401-application-file-upload-input.json +7 -7
- package/blueprints/application-file-upload/contributions/tacs/tac-2402-application-file-upload-transport.json +8 -8
- package/blueprints/application-file-upload/contributions/tacs/tac-2403-application-file-upload-progress-announcer.json +11 -11
- package/blueprints/application-file-upload/contributions/user-stories/application-file-upload-us-23102.json +1 -1
- package/blueprints/application-file-upload/contributions/user-stories/application-file-upload-us-23105.json +1 -1
- package/blueprints/application-forms-wizard/contributions/requirements/application-forms-wizard-req-001.json +1 -1
- package/blueprints/application-forms-wizard/contributions/requirements/application-forms-wizard-req-002.json +1 -1
- package/blueprints/application-forms-wizard/contributions/requirements/application-forms-wizard-req-003.json +1 -1
- package/blueprints/application-forms-wizard/contributions/requirements/application-forms-wizard-req-004.json +1 -1
- package/blueprints/application-forms-wizard/contributions/requirements/application-forms-wizard-req-005.json +1 -1
- package/blueprints/application-forms-wizard/contributions/requirements/application-forms-wizard-req-006.json +2 -2
- package/blueprints/application-forms-wizard/contributions/tacs/tac-2501-application-forms-wizard-task-list.json +7 -7
- package/blueprints/application-forms-wizard/contributions/tacs/tac-2502-application-forms-wizard-error-summary.json +4 -4
- package/blueprints/application-forms-wizard/contributions/tacs/tac-2503-application-forms-wizard-draft-store.json +4 -4
- package/blueprints/application-forms-wizard/contributions/user-stories/application-forms-wizard-us-24101.json +1 -1
- package/blueprints/application-notifications-in-app/contributions/requirements/application-notifications-in-app-req-001.json +1 -1
- package/blueprints/application-notifications-in-app/contributions/requirements/application-notifications-in-app-req-002.json +1 -1
- package/blueprints/application-notifications-in-app/contributions/requirements/application-notifications-in-app-req-003.json +1 -1
- package/blueprints/application-notifications-in-app/contributions/requirements/application-notifications-in-app-req-004.json +1 -1
- package/blueprints/application-notifications-in-app/contributions/requirements/application-notifications-in-app-req-005.json +2 -2
- package/blueprints/application-notifications-in-app/contributions/requirements/application-notifications-in-app-req-006.json +2 -2
- package/blueprints/application-notifications-in-app/contributions/tacs/tac-2101-application-notifications-in-app-live-region.json +6 -6
- package/blueprints/application-notifications-in-app/contributions/tacs/tac-2102-application-notifications-in-app-centre.json +9 -9
- package/blueprints/application-notifications-in-app/contributions/tacs/tac-2103-application-notifications-in-app-preferences.json +4 -4
- package/blueprints/application-notifications-in-app/contributions/user-stories/application-notifications-in-app-us-20101.json +1 -1
- package/blueprints/application-notifications-in-app/contributions/user-stories/application-notifications-in-app-us-20102.json +1 -1
- package/blueprints/application-notifications-in-app/contributions/user-stories/application-notifications-in-app-us-20103.json +2 -2
- package/blueprints/application-notifications-in-app/contributions/user-stories/application-notifications-in-app-us-20105.json +4 -4
- package/blueprints/application-onboarding-tour/contributions/requirements/application-onboarding-tour-req-001.json +1 -1
- package/blueprints/application-onboarding-tour/contributions/requirements/application-onboarding-tour-req-002.json +1 -1
- package/blueprints/application-onboarding-tour/contributions/requirements/application-onboarding-tour-req-003.json +1 -1
- package/blueprints/application-onboarding-tour/contributions/requirements/application-onboarding-tour-req-004.json +1 -1
- package/blueprints/application-onboarding-tour/contributions/requirements/application-onboarding-tour-req-005.json +1 -1
- package/blueprints/application-onboarding-tour/contributions/requirements/application-onboarding-tour-req-006.json +1 -1
- package/blueprints/application-onboarding-tour/contributions/tacs/tac-2701-application-onboarding-tour-step-runner.json +4 -4
- package/blueprints/application-onboarding-tour/contributions/tacs/tac-2702-application-onboarding-tour-checklist-slot.json +2 -2
- package/blueprints/application-onboarding-tour/contributions/tacs/tac-2703-application-onboarding-tour-completion-store.json +2 -2
- package/blueprints/application-onboarding-tour/contributions/user-stories/application-onboarding-tour-us-26108.json +2 -2
- package/blueprints/application-spa/contributions/requirements/application-spa-req-004.json +1 -2
- package/blueprints/application-spa/contributions/requirements/application-spa-req-007.json +1 -1
- package/blueprints/application-spa/contributions/requirements/application-spa-req-014.json +1 -1
- package/blueprints/application-spa/contributions/requirements/application-spa-req-015.json +1 -1
- package/blueprints/application-spa/contributions/requirements/application-spa-req-017.json +1 -1
- package/blueprints/application-spa/contributions/requirements/application-spa-req-018.json +1 -1
- package/blueprints/application-spa/contributions/tacs/tac-201-application-spa-app-shell.json +4 -4
- package/blueprints/application-spa/contributions/tacs/tac-202-application-spa-theme-system.json +4 -4
- package/blueprints/application-spa/contributions/tacs/tac-207-application-spa-token-adherence-probe.json +6 -6
- package/blueprints/application-spa/contributions/tacs/tac-208-application-spa-icon-adherence-probe.json +6 -6
- package/blueprints/application-spa/contributions/tacs/tac-209-application-spa-csp-styled-adherence-probe.json +6 -6
- package/blueprints/application-spa/contributions/tacs/tac-210-application-spa-external-dependency-provisioning-probe.json +8 -8
- package/blueprints/application-spa/contributions/tacs/tac-211-application-spa-core-flow-e2e-probe.json +8 -8
- package/blueprints/application-spa/contributions/user-stories/application-spa-us-1101.json +2 -2
- package/blueprints/application-spa/contributions/user-stories/application-spa-us-1102.json +1 -1
- package/blueprints/application-spa/contributions/user-stories/application-spa-us-1107.json +1 -1
- package/blueprints/application-spa/contributions/user-stories/application-spa-us-1117.json +1 -1
- package/blueprints/application-spa/contributions/user-stories/application-spa-us-1129.json +4 -4
- package/blueprints/application-spa/contributions/user-stories/application-spa-us-1130.json +4 -4
- package/blueprints/application-spa/contributions/user-stories/application-spa-us-1131.json +1 -1
- package/blueprints/application-spa/contributions/user-stories/application-spa-us-1132.json +6 -6
- package/blueprints/application-spa/contributions/user-stories/application-spa-us-1133.json +5 -5
- package/blueprints/application-spa/contributions/user-stories/application-spa-us-1134.json +2 -2
- package/blueprints/delivery-ci-workflows/contributions/requirements/delivery-ci-workflows-req-001.json +1 -1
- package/blueprints/delivery-ci-workflows/contributions/requirements/delivery-ci-workflows-req-002.json +1 -1
- package/blueprints/delivery-ci-workflows/contributions/requirements/delivery-ci-workflows-req-003.json +1 -1
- package/blueprints/delivery-ci-workflows/contributions/requirements/delivery-ci-workflows-req-004.json +1 -1
- package/blueprints/delivery-ci-workflows/contributions/requirements/delivery-ci-workflows-req-005.json +1 -1
- package/blueprints/delivery-ci-workflows/contributions/requirements/delivery-ci-workflows-req-006.json +1 -1
- package/blueprints/delivery-ci-workflows/contributions/requirements/delivery-ci-workflows-req-007.json +1 -1
- package/blueprints/delivery-ci-workflows/contributions/requirements/delivery-ci-workflows-req-008.json +1 -1
- package/blueprints/delivery-ci-workflows/contributions/requirements/delivery-ci-workflows-req-009.json +1 -1
- package/blueprints/delivery-ci-workflows/contributions/requirements/delivery-ci-workflows-req-010.json +1 -1
- package/blueprints/delivery-ci-workflows/contributions/requirements/delivery-ci-workflows-req-011.json +1 -1
- package/blueprints/delivery-ci-workflows/contributions/requirements/delivery-ci-workflows-req-012.json +1 -1
- package/blueprints/delivery-ci-workflows/contributions/requirements/delivery-ci-workflows-req-013.json +1 -1
- package/blueprints/delivery-ci-workflows/contributions/requirements/delivery-ci-workflows-req-014.json +1 -1
- package/blueprints/delivery-ci-workflows/contributions/requirements/delivery-ci-workflows-req-015.json +1 -1
- package/blueprints/delivery-ci-workflows/contributions/requirements/delivery-ci-workflows-req-016.json +1 -1
- package/blueprints/delivery-ci-workflows/contributions/requirements/delivery-ci-workflows-req-017.json +1 -1
- package/blueprints/delivery-ci-workflows/contributions/requirements/delivery-ci-workflows-req-018.json +1 -1
- package/blueprints/delivery-ci-workflows/contributions/requirements/delivery-ci-workflows-req-019.json +1 -1
- package/blueprints/delivery-ci-workflows/contributions/requirements/delivery-ci-workflows-req-020.json +1 -1
- package/blueprints/delivery-ci-workflows/contributions/requirements/delivery-ci-workflows-req-021.json +1 -1
- package/blueprints/delivery-ci-workflows/contributions/requirements/delivery-ci-workflows-req-022.json +1 -1
- package/blueprints/delivery-ci-workflows/contributions/requirements/delivery-ci-workflows-req-023.json +1 -1
- package/blueprints/delivery-ci-workflows/contributions/tacs/tac-701-delivery-ci-workflows-gate-runner.json +6 -6
- package/blueprints/delivery-ci-workflows/contributions/tacs/tac-702-delivery-ci-workflows-gate-report.json +4 -4
- package/blueprints/delivery-ci-workflows/contributions/tacs/tac-703-delivery-ci-workflows-aggregate-report.json +4 -4
- package/blueprints/delivery-ci-workflows/contributions/tacs/tac-704-delivery-ci-workflows-workflow-materialiser.json +6 -6
- package/blueprints/delivery-ci-workflows/contributions/tacs/tac-705-delivery-ci-workflows-release-workflow.json +6 -6
- package/blueprints/delivery-ci-workflows/contributions/tacs/tac-706-delivery-ci-workflows-scheduled-audit.json +4 -4
- package/blueprints/delivery-ci-workflows/contributions/user-stories/delivery-ci-workflows-us-6101.json +1 -1
- package/blueprints/delivery-ci-workflows/contributions/user-stories/delivery-ci-workflows-us-6102.json +1 -1
- package/blueprints/delivery-ci-workflows/contributions/user-stories/delivery-ci-workflows-us-6103.json +1 -1
- package/blueprints/delivery-ci-workflows/contributions/user-stories/delivery-ci-workflows-us-6104.json +1 -1
- package/blueprints/delivery-ci-workflows/contributions/user-stories/delivery-ci-workflows-us-6106.json +1 -1
- package/blueprints/delivery-ci-workflows/contributions/user-stories/delivery-ci-workflows-us-6107.json +1 -1
- package/blueprints/delivery-ci-workflows/contributions/user-stories/delivery-ci-workflows-us-6109.json +1 -1
- package/blueprints/delivery-ci-workflows/contributions/user-stories/delivery-ci-workflows-us-6110.json +1 -1
- package/blueprints/delivery-ci-workflows/contributions/user-stories/delivery-ci-workflows-us-6111.json +1 -1
- package/blueprints/delivery-ci-workflows/contributions/user-stories/delivery-ci-workflows-us-6113.json +1 -1
- package/blueprints/delivery-ci-workflows/contributions/user-stories/delivery-ci-workflows-us-6115.json +1 -1
- package/blueprints/delivery-ci-workflows/contributions/user-stories/delivery-ci-workflows-us-6116.json +1 -1
- package/blueprints/delivery-ci-workflows/contributions/user-stories/delivery-ci-workflows-us-6117.json +1 -1
- package/blueprints/delivery-ci-workflows/contributions/user-stories/delivery-ci-workflows-us-6118.json +1 -1
- package/blueprints/delivery-ci-workflows/contributions/user-stories/delivery-ci-workflows-us-6119.json +1 -1
- package/blueprints/delivery-ci-workflows/contributions/user-stories/delivery-ci-workflows-us-6120.json +1 -1
- package/blueprints/delivery-ci-workflows/contributions/user-stories/delivery-ci-workflows-us-6122.json +1 -1
- package/blueprints/delivery-ci-workflows/contributions/user-stories/delivery-ci-workflows-us-6123.json +1 -1
- package/blueprints/delivery-ci-workflows/contributions/user-stories/delivery-ci-workflows-us-6124.json +1 -1
- package/blueprints/deploy-cloudflare-workers/contributions/requirements/deploy-cloudflare-workers-req-001.json +1 -1
- package/blueprints/deploy-cloudflare-workers/contributions/requirements/deploy-cloudflare-workers-req-002.json +1 -1
- package/blueprints/deploy-cloudflare-workers/contributions/requirements/deploy-cloudflare-workers-req-003.json +1 -1
- package/blueprints/deploy-cloudflare-workers/contributions/requirements/deploy-cloudflare-workers-req-004.json +1 -1
- package/blueprints/deploy-cloudflare-workers/contributions/requirements/deploy-cloudflare-workers-req-005.json +1 -1
- package/blueprints/deploy-cloudflare-workers/contributions/requirements/deploy-cloudflare-workers-req-006.json +1 -1
- package/blueprints/deploy-cloudflare-workers/contributions/requirements/deploy-cloudflare-workers-req-007.json +1 -1
- package/blueprints/deploy-cloudflare-workers/contributions/requirements/deploy-cloudflare-workers-req-008.json +1 -1
- package/blueprints/deploy-cloudflare-workers/contributions/requirements/deploy-cloudflare-workers-req-009.json +1 -1
- package/blueprints/deploy-cloudflare-workers/contributions/requirements/deploy-cloudflare-workers-req-010.json +1 -1
- package/blueprints/deploy-cloudflare-workers/contributions/requirements/deploy-cloudflare-workers-req-011.json +1 -1
- package/blueprints/deploy-cloudflare-workers/contributions/requirements/deploy-cloudflare-workers-req-012.json +1 -1
- package/blueprints/deploy-cloudflare-workers/contributions/requirements/deploy-cloudflare-workers-req-013.json +1 -1
- package/blueprints/deploy-cloudflare-workers/contributions/requirements/deploy-cloudflare-workers-req-014.json +1 -1
- package/blueprints/deploy-cloudflare-workers/contributions/tacs/tac-1301-deploy-cloudflare-workers-deploy-adapter.json +6 -6
- package/blueprints/deploy-cloudflare-workers/contributions/tacs/tac-1302-deploy-cloudflare-workers-wrangler-manifest.json +8 -8
- package/blueprints/deploy-cloudflare-workers/contributions/tacs/tac-1303-deploy-cloudflare-workers-preview-url-resolver.json +6 -6
- package/blueprints/deploy-cloudflare-workers/contributions/tacs/tac-1304-deploy-cloudflare-workers-promote-gate.json +8 -8
- package/blueprints/deploy-cloudflare-workers/contributions/tacs/tac-1305-deploy-cloudflare-workers-served-surface-verifier.json +8 -8
- package/blueprints/deploy-cloudflare-workers/contributions/tacs/tac-1306-deploy-cloudflare-workers-deploy-ci-workflows.json +8 -8
- package/blueprints/deploy-cloudflare-workers/contributions/user-stories/deploy-cloudflare-workers-us-12101.json +1 -1
- package/blueprints/deploy-cloudflare-workers/contributions/user-stories/deploy-cloudflare-workers-us-12102.json +2 -2
- package/blueprints/deploy-cloudflare-workers/contributions/user-stories/deploy-cloudflare-workers-us-12105.json +1 -1
- package/blueprints/deploy-cloudflare-workers/contributions/user-stories/deploy-cloudflare-workers-us-12109.json +1 -1
- package/blueprints/deploy-cloudflare-workers/contributions/user-stories/deploy-cloudflare-workers-us-12113.json +2 -2
- package/blueprints/deploy-cloudflare-workers/contributions/user-stories/deploy-cloudflare-workers-us-12114.json +1 -1
- package/blueprints/deploy-cloudflare-workers/contributions/user-stories/deploy-cloudflare-workers-us-12115.json +1 -1
- package/blueprints/deploy-hetzner-server/contributions/requirements/deploy-hetzner-server-req-001.json +1 -1
- package/blueprints/deploy-hetzner-server/contributions/requirements/deploy-hetzner-server-req-002.json +1 -1
- package/blueprints/deploy-hetzner-server/contributions/requirements/deploy-hetzner-server-req-003.json +1 -1
- package/blueprints/deploy-hetzner-server/contributions/requirements/deploy-hetzner-server-req-004.json +1 -1
- package/blueprints/deploy-hetzner-server/contributions/requirements/deploy-hetzner-server-req-005.json +1 -1
- package/blueprints/deploy-hetzner-server/contributions/requirements/deploy-hetzner-server-req-006.json +1 -1
- package/blueprints/deploy-hetzner-server/contributions/tacs/tac-3801-deploy-hetzner-server-provisioner.json +3 -2
- package/blueprints/deploy-hetzner-server/contributions/tacs/tac-3802-deploy-hetzner-server-manifest-schema.json +3 -2
- package/blueprints/deploy-hetzner-server/contributions/tacs/tac-3803-deploy-hetzner-server-cloud-init-template.json +3 -2
- package/blueprints/deploy-hetzner-server/contributions/tacs/tac-3804-deploy-hetzner-server-firewall-shape.json +3 -2
- package/blueprints/deploy-hetzner-server/contributions/user-stories/deploy-hetzner-server-us-37101.json +4 -4
- package/blueprints/deploy-hetzner-server/contributions/user-stories/deploy-hetzner-server-us-37102.json +3 -3
- package/blueprints/deploy-hetzner-server/contributions/user-stories/deploy-hetzner-server-us-37103.json +4 -4
- package/blueprints/deploy-hetzner-server/contributions/user-stories/deploy-hetzner-server-us-37104.json +2 -2
- package/blueprints/deploy-hetzner-server/contributions/user-stories/deploy-hetzner-server-us-37105.json +2 -2
- package/blueprints/deploy-hetzner-server/contributions/user-stories/deploy-hetzner-server-us-37106.json +3 -3
- package/blueprints/deploy-hetzner-server/contributions/user-stories/deploy-hetzner-server-us-37107.json +2 -2
- package/blueprints/deploy-hetzner-server/contributions/user-stories/deploy-hetzner-server-us-37108.json +2 -2
- package/blueprints/deploy-hetzner-server/contributions/user-stories/deploy-hetzner-server-us-37109.json +2 -2
- package/blueprints/edge-cloudflare-access/contributions/requirements/edge-cloudflare-access-req-001.json +1 -1
- package/blueprints/edge-cloudflare-access/contributions/requirements/edge-cloudflare-access-req-002.json +1 -1
- package/blueprints/edge-cloudflare-access/contributions/requirements/edge-cloudflare-access-req-003.json +1 -1
- package/blueprints/edge-cloudflare-access/contributions/requirements/edge-cloudflare-access-req-004.json +1 -1
- package/blueprints/edge-cloudflare-access/contributions/requirements/edge-cloudflare-access-req-005.json +1 -1
- package/blueprints/edge-cloudflare-access/contributions/requirements/edge-cloudflare-access-req-006.json +1 -1
- package/blueprints/edge-cloudflare-access/contributions/requirements/edge-cloudflare-access-req-007.json +1 -1
- package/blueprints/edge-cloudflare-access/contributions/tacs/tac-3501-edge-cloudflare-access-jwt-validator.json +6 -4
- package/blueprints/edge-cloudflare-access/contributions/tacs/tac-3502-edge-cloudflare-access-application-declaration.json +3 -2
- package/blueprints/edge-cloudflare-access/contributions/tacs/tac-3503-edge-cloudflare-access-policy-shape.json +3 -2
- package/blueprints/edge-cloudflare-access/contributions/tacs/tac-3504-edge-cloudflare-access-audit-sink.json +3 -2
- package/blueprints/edge-cloudflare-access/contributions/user-stories/edge-cloudflare-access-us-34101.json +1 -1
- package/blueprints/edge-cloudflare-access/contributions/user-stories/edge-cloudflare-access-us-34102.json +5 -5
- package/blueprints/edge-cloudflare-access/contributions/user-stories/edge-cloudflare-access-us-34103.json +1 -1
- package/blueprints/edge-cloudflare-access/contributions/user-stories/edge-cloudflare-access-us-34104.json +3 -3
- package/blueprints/edge-cloudflare-access/contributions/user-stories/edge-cloudflare-access-us-34105.json +1 -1
- package/blueprints/edge-cloudflare-access/contributions/user-stories/edge-cloudflare-access-us-34106.json +1 -1
- package/blueprints/edge-cloudflare-access/contributions/user-stories/edge-cloudflare-access-us-34107.json +5 -5
- package/blueprints/edge-cloudflare-access/contributions/user-stories/edge-cloudflare-access-us-34110.json +1 -1
- package/blueprints/edge-cloudflare-rate-limiting/contributions/requirements/edge-cloudflare-rate-limiting-req-001.json +1 -1
- package/blueprints/edge-cloudflare-rate-limiting/contributions/requirements/edge-cloudflare-rate-limiting-req-002.json +1 -1
- package/blueprints/edge-cloudflare-rate-limiting/contributions/requirements/edge-cloudflare-rate-limiting-req-003.json +1 -1
- package/blueprints/edge-cloudflare-rate-limiting/contributions/requirements/edge-cloudflare-rate-limiting-req-004.json +1 -1
- package/blueprints/edge-cloudflare-rate-limiting/contributions/requirements/edge-cloudflare-rate-limiting-req-005.json +1 -1
- package/blueprints/edge-cloudflare-rate-limiting/contributions/tacs/tac-3701-edge-cloudflare-rate-limiting-manifest-schema.json +6 -4
- package/blueprints/edge-cloudflare-rate-limiting/contributions/tacs/tac-3702-edge-cloudflare-rate-limiting-management-surface-doc.json +3 -2
- package/blueprints/edge-cloudflare-rate-limiting/contributions/tacs/tac-3703-edge-cloudflare-rate-limiting-drift-audit-runner.json +3 -2
- package/blueprints/edge-cloudflare-rate-limiting/contributions/user-stories/edge-cloudflare-rate-limiting-us-36101.json +2 -2
- package/blueprints/edge-cloudflare-rate-limiting/contributions/user-stories/edge-cloudflare-rate-limiting-us-36103.json +1 -1
- package/blueprints/edge-cloudflare-rate-limiting/contributions/user-stories/edge-cloudflare-rate-limiting-us-36104.json +6 -6
- package/blueprints/edge-cloudflare-rate-limiting/contributions/user-stories/edge-cloudflare-rate-limiting-us-36106.json +2 -2
- package/blueprints/edge-cloudflare-tunnel/contributions/requirements/edge-cloudflare-tunnel-req-001.json +1 -1
- package/blueprints/edge-cloudflare-tunnel/contributions/requirements/edge-cloudflare-tunnel-req-002.json +1 -1
- package/blueprints/edge-cloudflare-tunnel/contributions/requirements/edge-cloudflare-tunnel-req-003.json +1 -1
- package/blueprints/edge-cloudflare-tunnel/contributions/requirements/edge-cloudflare-tunnel-req-004.json +1 -1
- package/blueprints/edge-cloudflare-tunnel/contributions/requirements/edge-cloudflare-tunnel-req-005.json +1 -1
- package/blueprints/edge-cloudflare-tunnel/contributions/requirements/edge-cloudflare-tunnel-req-006.json +1 -1
- package/blueprints/edge-cloudflare-tunnel/contributions/requirements/edge-cloudflare-tunnel-req-007.json +1 -1
- package/blueprints/edge-cloudflare-tunnel/contributions/tacs/tac-4001-edge-cloudflare-tunnel-connector-shape.json +3 -2
- package/blueprints/edge-cloudflare-tunnel/contributions/tacs/tac-4002-edge-cloudflare-tunnel-manifest-schema.json +3 -2
- package/blueprints/edge-cloudflare-tunnel/contributions/tacs/tac-4003-edge-cloudflare-tunnel-access-binding.json +3 -2
- package/blueprints/edge-cloudflare-tunnel/contributions/tacs/tac-4004-edge-cloudflare-tunnel-zone-and-hostname-apply.json +3 -2
- package/blueprints/edge-cloudflare-tunnel/contributions/user-stories/edge-cloudflare-tunnel-us-39101.json +3 -3
- package/blueprints/edge-cloudflare-tunnel/contributions/user-stories/edge-cloudflare-tunnel-us-39102.json +2 -2
- package/blueprints/edge-cloudflare-tunnel/contributions/user-stories/edge-cloudflare-tunnel-us-39103.json +4 -4
- package/blueprints/edge-cloudflare-tunnel/contributions/user-stories/edge-cloudflare-tunnel-us-39104.json +2 -2
- package/blueprints/edge-cloudflare-tunnel/contributions/user-stories/edge-cloudflare-tunnel-us-39105.json +2 -2
- package/blueprints/edge-cloudflare-tunnel/contributions/user-stories/edge-cloudflare-tunnel-us-39106.json +5 -5
- package/blueprints/edge-cloudflare-tunnel/contributions/user-stories/edge-cloudflare-tunnel-us-39107.json +2 -2
- package/blueprints/edge-cloudflare-tunnel/contributions/user-stories/edge-cloudflare-tunnel-us-39108.json +3 -3
- package/blueprints/edge-cloudflare-tunnel/contributions/user-stories/edge-cloudflare-tunnel-us-39109.json +4 -4
- package/blueprints/edge-cloudflare-tunnel/contributions/user-stories/edge-cloudflare-tunnel-us-39110.json +3 -3
- package/blueprints/edge-cloudflare-turnstile/contributions/requirements/edge-cloudflare-turnstile-req-001.json +1 -1
- package/blueprints/edge-cloudflare-turnstile/contributions/requirements/edge-cloudflare-turnstile-req-002.json +1 -1
- package/blueprints/edge-cloudflare-turnstile/contributions/requirements/edge-cloudflare-turnstile-req-003.json +1 -1
- package/blueprints/edge-cloudflare-turnstile/contributions/requirements/edge-cloudflare-turnstile-req-004.json +1 -1
- package/blueprints/edge-cloudflare-turnstile/contributions/requirements/edge-cloudflare-turnstile-req-005.json +1 -1
- package/blueprints/edge-cloudflare-turnstile/contributions/tacs/tac-3601-edge-cloudflare-turnstile-widget-mount.json +3 -2
- package/blueprints/edge-cloudflare-turnstile/contributions/tacs/tac-3602-edge-cloudflare-turnstile-server-verifier.json +9 -6
- package/blueprints/edge-cloudflare-turnstile/contributions/tacs/tac-3603-edge-cloudflare-turnstile-magic-link-hook.json +3 -2
- package/blueprints/edge-cloudflare-turnstile/contributions/user-stories/edge-cloudflare-turnstile-us-35101.json +3 -3
- package/blueprints/edge-cloudflare-turnstile/contributions/user-stories/edge-cloudflare-turnstile-us-35102.json +4 -4
- package/blueprints/edge-cloudflare-turnstile/contributions/user-stories/edge-cloudflare-turnstile-us-35103.json +6 -6
- package/blueprints/edge-cloudflare-turnstile/contributions/user-stories/edge-cloudflare-turnstile-us-35104.json +2 -2
- package/blueprints/edge-cloudflare-turnstile/contributions/user-stories/edge-cloudflare-turnstile-us-35105.json +1 -1
- package/blueprints/email-smtp-resend/contributions/requirements/email-smtp-resend-req-001.json +1 -1
- package/blueprints/email-smtp-resend/contributions/requirements/email-smtp-resend-req-002.json +1 -1
- package/blueprints/email-smtp-resend/contributions/requirements/email-smtp-resend-req-003.json +1 -1
- package/blueprints/email-smtp-resend/contributions/requirements/email-smtp-resend-req-004.json +1 -1
- package/blueprints/email-smtp-resend/contributions/requirements/email-smtp-resend-req-005.json +1 -1
- package/blueprints/email-smtp-resend/contributions/requirements/email-smtp-resend-req-006.json +1 -1
- package/blueprints/email-smtp-resend/contributions/tacs/tac-401-email-smtp-resend-send-adapter.json +8 -8
- package/blueprints/email-smtp-resend/contributions/tacs/tac-402-email-smtp-resend-webhook-verifier.json +10 -10
- package/blueprints/email-smtp-resend/contributions/user-stories/email-smtp-resend-us-4101.json +1 -1
- package/blueprints/email-smtp-resend/contributions/user-stories/email-smtp-resend-us-4102.json +1 -1
- package/blueprints/email-smtp-resend/contributions/user-stories/email-smtp-resend-us-4103.json +1 -1
- package/blueprints/email-smtp-resend/contributions/user-stories/email-smtp-resend-us-4105.json +1 -1
- package/blueprints/email-smtp-resend/contributions/user-stories/email-smtp-resend-us-4106.json +2 -2
- package/blueprints/jobs-background/contributions/requirements/jobs-background-req-001.json +1 -1
- package/blueprints/jobs-background/contributions/requirements/jobs-background-req-002.json +1 -1
- package/blueprints/jobs-background/contributions/requirements/jobs-background-req-003.json +1 -1
- package/blueprints/jobs-background/contributions/requirements/jobs-background-req-004.json +1 -1
- package/blueprints/jobs-background/contributions/requirements/jobs-background-req-005.json +1 -1
- package/blueprints/jobs-background/contributions/requirements/jobs-background-req-006.json +1 -1
- package/blueprints/jobs-background/contributions/tacs/tac-3101-jobs-background-job-definition.json +4 -4
- package/blueprints/jobs-background/contributions/tacs/tac-3102-jobs-background-scheduler.json +6 -6
- package/blueprints/jobs-background/contributions/tacs/tac-3103-jobs-background-run-log.json +6 -6
- package/blueprints/jobs-background/contributions/user-stories/jobs-background-us-30101.json +1 -1
- package/blueprints/jobs-background/contributions/user-stories/jobs-background-us-30102.json +3 -3
- package/blueprints/jobs-background/contributions/user-stories/jobs-background-us-30103.json +1 -1
- package/blueprints/jobs-background/contributions/user-stories/jobs-background-us-30104.json +4 -4
- package/blueprints/jobs-background/contributions/user-stories/jobs-background-us-30105.json +1 -1
- package/blueprints/jobs-background/contributions/user-stories/jobs-background-us-30106.json +1 -1
- package/blueprints/jobs-background/contributions/user-stories/jobs-background-us-30107.json +1 -1
- package/blueprints/jobs-background/contributions/user-stories/jobs-background-us-30108.json +1 -1
- package/blueprints/jobs-background/contributions/user-stories/jobs-background-us-30109.json +1 -1
- package/blueprints/messaging-queue-cloudflare/contributions/requirements/messaging-queue-cloudflare-req-001.json +1 -1
- package/blueprints/messaging-queue-cloudflare/contributions/requirements/messaging-queue-cloudflare-req-002.json +1 -1
- package/blueprints/messaging-queue-cloudflare/contributions/requirements/messaging-queue-cloudflare-req-003.json +1 -1
- package/blueprints/messaging-queue-cloudflare/contributions/requirements/messaging-queue-cloudflare-req-004.json +1 -1
- package/blueprints/messaging-queue-cloudflare/contributions/requirements/messaging-queue-cloudflare-req-005.json +1 -1
- package/blueprints/messaging-queue-cloudflare/contributions/requirements/messaging-queue-cloudflare-req-006.json +1 -1
- package/blueprints/messaging-queue-cloudflare/contributions/tacs/tac-3001-messaging-queue-cloudflare-producer-facade.json +6 -6
- package/blueprints/messaging-queue-cloudflare/contributions/tacs/tac-3002-messaging-queue-cloudflare-consumer-registration.json +2 -2
- package/blueprints/messaging-queue-cloudflare/contributions/tacs/tac-3003-messaging-queue-cloudflare-event-sink.json +2 -2
- package/blueprints/messaging-queue-cloudflare/contributions/user-stories/messaging-queue-cloudflare-us-29101.json +1 -1
- package/blueprints/messaging-queue-cloudflare/contributions/user-stories/messaging-queue-cloudflare-us-29102.json +1 -1
- package/blueprints/messaging-queue-cloudflare/contributions/user-stories/messaging-queue-cloudflare-us-29103.json +1 -1
- package/blueprints/messaging-queue-cloudflare/contributions/user-stories/messaging-queue-cloudflare-us-29104.json +2 -2
- package/blueprints/messaging-queue-cloudflare/contributions/user-stories/messaging-queue-cloudflare-us-29105.json +1 -1
- package/blueprints/messaging-queue-cloudflare/contributions/user-stories/messaging-queue-cloudflare-us-29106.json +2 -2
- package/blueprints/messaging-queue-cloudflare/contributions/user-stories/messaging-queue-cloudflare-us-29107.json +1 -1
- package/blueprints/messaging-queue-cloudflare/contributions/user-stories/messaging-queue-cloudflare-us-29108.json +1 -1
- package/blueprints/object-storage-s3/contributions/requirements/object-storage-s3-req-001.json +1 -1
- package/blueprints/object-storage-s3/contributions/requirements/object-storage-s3-req-002.json +1 -1
- package/blueprints/object-storage-s3/contributions/requirements/object-storage-s3-req-003.json +1 -1
- package/blueprints/object-storage-s3/contributions/requirements/object-storage-s3-req-004.json +1 -1
- package/blueprints/object-storage-s3/contributions/requirements/object-storage-s3-req-005.json +1 -1
- package/blueprints/object-storage-s3/contributions/requirements/object-storage-s3-req-006.json +1 -1
- package/blueprints/object-storage-s3/contributions/requirements/object-storage-s3-req-101.json +1 -1
- package/blueprints/object-storage-s3/contributions/tacs/tac-2901-object-storage-s3-facade.json +6 -6
- package/blueprints/object-storage-s3/contributions/tacs/tac-2902-object-storage-s3-multipart-uploader.json +2 -2
- package/blueprints/object-storage-s3/contributions/tacs/tac-2903-object-storage-s3-event-sink.json +2 -2
- package/blueprints/object-storage-s3/contributions/tacs/tac-2904-object-storage-s3-hetzner-endpoint-helper.json +2 -2
- package/blueprints/object-storage-s3/contributions/user-stories/object-storage-s3-us-28101.json +1 -1
- package/blueprints/object-storage-s3/contributions/user-stories/object-storage-s3-us-28102.json +1 -1
- package/blueprints/object-storage-s3/contributions/user-stories/object-storage-s3-us-28103.json +2 -2
- package/blueprints/object-storage-s3/contributions/user-stories/object-storage-s3-us-28104.json +1 -1
- package/blueprints/object-storage-s3/contributions/user-stories/object-storage-s3-us-28105.json +2 -2
- package/blueprints/object-storage-s3/contributions/user-stories/object-storage-s3-us-28106.json +1 -1
- package/blueprints/object-storage-s3/contributions/user-stories/object-storage-s3-us-28110.json +1 -1
- package/blueprints/observability-essentials/contributions/requirements/observability-essentials-req-001.json +1 -1
- package/blueprints/observability-essentials/contributions/requirements/observability-essentials-req-002.json +1 -1
- package/blueprints/observability-essentials/contributions/requirements/observability-essentials-req-003.json +1 -1
- package/blueprints/observability-essentials/contributions/requirements/observability-essentials-req-004.json +1 -1
- package/blueprints/observability-essentials/contributions/requirements/observability-essentials-req-005.json +1 -1
- package/blueprints/observability-essentials/contributions/requirements/observability-essentials-req-006.json +1 -1
- package/blueprints/observability-essentials/contributions/requirements/observability-essentials-req-007.json +1 -1
- package/blueprints/observability-essentials/contributions/requirements/observability-essentials-req-008.json +1 -1
- package/blueprints/observability-essentials/contributions/requirements/observability-essentials-req-009.json +1 -1
- package/blueprints/observability-essentials/contributions/requirements/observability-essentials-req-010.json +1 -1
- package/blueprints/observability-essentials/contributions/tacs/tac-801-observability-essentials-liveness-probe.json +4 -4
- package/blueprints/observability-essentials/contributions/tacs/tac-802-observability-essentials-readiness-probe.json +12 -12
- package/blueprints/observability-essentials/contributions/tacs/tac-803-observability-essentials-status-page.json +6 -6
- package/blueprints/observability-essentials/contributions/tacs/tac-804-observability-essentials-notification-outcome.json +8 -8
- package/blueprints/observability-essentials/contributions/user-stories/observability-essentials-us-7101.json +1 -1
- package/blueprints/observability-essentials/contributions/user-stories/observability-essentials-us-7103.json +3 -3
- package/blueprints/observability-essentials/contributions/user-stories/observability-essentials-us-7106.json +2 -2
- package/blueprints/observability-essentials/contributions/user-stories/observability-essentials-us-7107.json +1 -1
- package/blueprints/observability-logging/contributions/requirements/observability-logging-req-001.json +1 -1
- package/blueprints/observability-logging/contributions/requirements/observability-logging-req-002.json +1 -1
- package/blueprints/observability-logging/contributions/requirements/observability-logging-req-003.json +1 -1
- package/blueprints/observability-logging/contributions/requirements/observability-logging-req-004.json +1 -1
- package/blueprints/observability-logging/contributions/requirements/observability-logging-req-005.json +1 -1
- package/blueprints/observability-logging/contributions/requirements/observability-logging-req-006.json +8 -2
- package/blueprints/observability-logging/contributions/tacs/tac-1601-observability-logging-logger-factory.json +6 -6
- package/blueprints/observability-logging/contributions/tacs/tac-1602-observability-logging-redaction-boundary.json +2 -2
- package/blueprints/observability-logging/contributions/user-stories/observability-logging-us-15101.json +4 -4
- package/blueprints/observability-logging/contributions/user-stories/observability-logging-us-15103.json +2 -2
- package/blueprints/observability-logging/contributions/user-stories/observability-logging-us-15104.json +2 -2
- package/blueprints/observability-logging/contributions/user-stories/observability-logging-us-15105.json +1 -1
- package/blueprints/observability-logging/contributions/user-stories/observability-logging-us-15106.json +1 -1
- package/blueprints/observability-logging/contributions/user-stories/observability-logging-us-15107.json +2 -2
- package/blueprints/observability-logging/contributions/user-stories/observability-logging-us-15108.json +1 -1
- package/blueprints/observability-logging/contributions/user-stories/observability-logging-us-15109.json +3 -3
- package/blueprints/observability-probe-endpoints/contributions/requirements/observability-probe-endpoints-req-001.json +1 -1
- package/blueprints/observability-probe-endpoints/contributions/requirements/observability-probe-endpoints-req-002.json +1 -1
- package/blueprints/observability-probe-endpoints/contributions/requirements/observability-probe-endpoints-req-003.json +1 -1
- package/blueprints/observability-probe-endpoints/contributions/requirements/observability-probe-endpoints-req-004.json +1 -1
- package/blueprints/observability-probe-endpoints/contributions/requirements/observability-probe-endpoints-req-005.json +1 -1
- package/blueprints/observability-probe-endpoints/contributions/requirements/observability-probe-endpoints-req-006.json +1 -1
- package/blueprints/observability-probe-endpoints/contributions/requirements/observability-probe-endpoints-req-007.json +1 -1
- package/blueprints/observability-probe-endpoints/contributions/requirements/observability-probe-endpoints-req-008.json +1 -1
- package/blueprints/observability-probe-endpoints/contributions/tacs/tac-1501-observability-probe-endpoints-profile-resolver.json +6 -6
- package/blueprints/observability-probe-endpoints/contributions/tacs/tac-1502-observability-probe-endpoints-handler-set.json +4 -4
- package/blueprints/observability-probe-endpoints/contributions/tacs/tac-1503-observability-probe-endpoints-listener-topology.json +6 -6
- package/blueprints/observability-probe-endpoints/contributions/tacs/tac-1504-observability-probe-endpoints-non-http-adapters.json +4 -4
- package/blueprints/observability-probe-endpoints/contributions/user-stories/observability-probe-endpoints-us-14101.json +2 -2
- package/blueprints/observability-probe-endpoints/contributions/user-stories/observability-probe-endpoints-us-14102.json +1 -1
- package/blueprints/observability-probe-endpoints/contributions/user-stories/observability-probe-endpoints-us-14105.json +3 -3
- package/blueprints/persistence-data-d1/contributions/requirements/persistence-data-d1-req-001.json +1 -1
- package/blueprints/persistence-data-d1/contributions/requirements/persistence-data-d1-req-002.json +1 -1
- package/blueprints/persistence-data-d1/contributions/requirements/persistence-data-d1-req-003.json +1 -1
- package/blueprints/persistence-data-d1/contributions/requirements/persistence-data-d1-req-004.json +1 -1
- package/blueprints/persistence-data-d1/contributions/requirements/persistence-data-d1-req-005.json +1 -1
- package/blueprints/persistence-data-d1/contributions/requirements/persistence-data-d1-req-006.json +1 -1
- package/blueprints/persistence-data-d1/contributions/requirements/persistence-data-d1-req-007.json +1 -1
- package/blueprints/persistence-data-d1/contributions/tacs/tac-1401-persistence-data-d1-facade.json +6 -6
- package/blueprints/persistence-data-d1/contributions/tacs/tac-1402-persistence-data-d1-migration-catalog.json +4 -4
- package/blueprints/persistence-data-d1/contributions/tacs/tac-1403-persistence-data-d1-deploy-gate.json +4 -4
- package/blueprints/persistence-data-d1/contributions/tacs/tac-1404-persistence-data-d1-recovery-runner.json +4 -4
- package/blueprints/persistence-data-d1/contributions/user-stories/persistence-data-d1-us-13101.json +2 -2
- package/blueprints/persistence-data-d1/contributions/user-stories/persistence-data-d1-us-13102.json +1 -1
- package/blueprints/persistence-data-d1/contributions/user-stories/persistence-data-d1-us-13107.json +2 -2
- package/blueprints/persistence-data-postgres/contributions/requirements/persistence-data-postgres-req-001.json +1 -1
- package/blueprints/persistence-data-postgres/contributions/requirements/persistence-data-postgres-req-002.json +1 -1
- package/blueprints/persistence-data-postgres/contributions/requirements/persistence-data-postgres-req-003.json +1 -1
- package/blueprints/persistence-data-postgres/contributions/requirements/persistence-data-postgres-req-004.json +1 -1
- package/blueprints/persistence-data-postgres/contributions/requirements/persistence-data-postgres-req-005.json +1 -1
- package/blueprints/persistence-data-postgres/contributions/requirements/persistence-data-postgres-req-006.json +1 -1
- package/blueprints/persistence-data-postgres/contributions/requirements/persistence-data-postgres-req-007.json +1 -1
- package/blueprints/persistence-data-postgres/contributions/tacs/tac-2801-persistence-data-postgres-facade.json +6 -6
- package/blueprints/persistence-data-postgres/contributions/tacs/tac-2802-persistence-data-postgres-migration-runner.json +4 -4
- package/blueprints/persistence-data-postgres/contributions/tacs/tac-2803-persistence-data-postgres-transaction-helper.json +2 -2
- package/blueprints/persistence-data-postgres/contributions/tacs/tac-2804-persistence-data-postgres-recovery-runner.json +4 -4
- package/blueprints/persistence-data-postgres/contributions/user-stories/persistence-data-postgres-us-27101.json +1 -1
- package/blueprints/persistence-data-postgres/contributions/user-stories/persistence-data-postgres-us-27102.json +4 -4
- package/blueprints/persistence-data-postgres/contributions/user-stories/persistence-data-postgres-us-27103.json +1 -1
- package/blueprints/persistence-data-postgres/contributions/user-stories/persistence-data-postgres-us-27104.json +2 -2
- package/blueprints/persistence-data-postgres/contributions/user-stories/persistence-data-postgres-us-27105.json +1 -1
- package/blueprints/persistence-data-postgres/contributions/user-stories/persistence-data-postgres-us-27106.json +1 -1
- package/blueprints/persistence-data-postgres/contributions/user-stories/persistence-data-postgres-us-27107.json +1 -1
- package/blueprints/persistence-data-postgres/contributions/user-stories/persistence-data-postgres-us-27108.json +1 -1
- package/blueprints/persistence-data-postgres/contributions/user-stories/persistence-data-postgres-us-27109.json +1 -1
- package/blueprints/persistence-data-postgres/contributions/user-stories/persistence-data-postgres-us-27110.json +1 -1
- package/blueprints/persistence-data-sqlite/contributions/requirements/persistence-data-sqlite-req-001.json +1 -1
- package/blueprints/persistence-data-sqlite/contributions/requirements/persistence-data-sqlite-req-002.json +1 -1
- package/blueprints/persistence-data-sqlite/contributions/requirements/persistence-data-sqlite-req-003.json +1 -1
- package/blueprints/persistence-data-sqlite/contributions/requirements/persistence-data-sqlite-req-004.json +1 -1
- package/blueprints/persistence-data-sqlite/contributions/requirements/persistence-data-sqlite-req-005.json +1 -1
- package/blueprints/persistence-data-sqlite/contributions/requirements/persistence-data-sqlite-req-006.json +1 -1
- package/blueprints/persistence-data-sqlite/contributions/requirements/persistence-data-sqlite-req-007.json +1 -1
- package/blueprints/persistence-data-sqlite/contributions/requirements/persistence-data-sqlite-req-008.json +1 -1
- package/blueprints/persistence-data-sqlite/contributions/requirements/persistence-data-sqlite-req-009.json +1 -1
- package/blueprints/persistence-data-sqlite/contributions/requirements/persistence-data-sqlite-req-010.json +1 -1
- package/blueprints/persistence-data-sqlite/contributions/requirements/persistence-data-sqlite-req-011.json +1 -1
- package/blueprints/persistence-data-sqlite/contributions/tacs/tac-601-persistence-data-sqlite-store.json +6 -6
- package/blueprints/persistence-data-sqlite/contributions/tacs/tac-602-persistence-data-sqlite-migration-runner.json +2 -2
- package/blueprints/persistence-data-sqlite/contributions/tacs/tac-603-persistence-data-sqlite-migration-catalog.json +4 -4
- package/blueprints/persistence-data-sqlite/contributions/tacs/tac-604-persistence-data-sqlite-backup-runner.json +2 -2
- package/blueprints/persistence-data-sqlite/contributions/user-stories/persistence-data-sqlite-us-5101.json +2 -2
- package/blueprints/persistence-data-sqlite/contributions/user-stories/persistence-data-sqlite-us-5103.json +1 -1
- package/blueprints/persistence-data-sqlite/contributions/user-stories/persistence-data-sqlite-us-5104.json +1 -1
- package/blueprints/persistence-data-sqlite/contributions/user-stories/persistence-data-sqlite-us-5106.json +1 -1
- package/blueprints/persistence-data-sqlite/contributions/user-stories/persistence-data-sqlite-us-5110.json +2 -2
- package/blueprints/persistence-data-sqlite/contributions/user-stories/persistence-data-sqlite-us-5111.json +1 -1
- package/blueprints/platform-cloudflare-cron-triggers/contributions/requirements/platform-cloudflare-cron-triggers-req-001.json +1 -1
- package/blueprints/platform-cloudflare-cron-triggers/contributions/requirements/platform-cloudflare-cron-triggers-req-002.json +1 -1
- package/blueprints/platform-cloudflare-cron-triggers/contributions/requirements/platform-cloudflare-cron-triggers-req-003.json +1 -1
- package/blueprints/platform-cloudflare-cron-triggers/contributions/requirements/platform-cloudflare-cron-triggers-req-004.json +1 -1
- package/blueprints/platform-cloudflare-cron-triggers/contributions/tacs/tac-3301-platform-cloudflare-cron-triggers-scheduled-handler.json +6 -1
- package/blueprints/platform-cloudflare-cron-triggers/contributions/tacs/tac-3302-platform-cloudflare-cron-triggers-expression-router.json +9 -2
- package/blueprints/platform-cloudflare-cron-triggers/contributions/tacs/tac-3303-platform-cloudflare-cron-triggers-event-sink.json +6 -1
- package/blueprints/platform-cloudflare-cron-triggers/contributions/user-stories/platform-cloudflare-cron-triggers-us-32101.json +6 -6
- package/blueprints/platform-cloudflare-cron-triggers/contributions/user-stories/platform-cloudflare-cron-triggers-us-32102.json +5 -5
- package/blueprints/platform-cloudflare-cron-triggers/contributions/user-stories/platform-cloudflare-cron-triggers-us-32103.json +3 -3
- package/blueprints/platform-cloudflare-cron-triggers/contributions/user-stories/platform-cloudflare-cron-triggers-us-32104.json +4 -4
- package/blueprints/platform-cloudflare-cron-triggers/contributions/user-stories/platform-cloudflare-cron-triggers-us-32105.json +4 -4
- package/blueprints/platform-cloudflare-cron-triggers/contributions/user-stories/platform-cloudflare-cron-triggers-us-32106.json +4 -4
- package/blueprints/platform-cloudflare-cron-triggers/contributions/user-stories/platform-cloudflare-cron-triggers-us-32107.json +3 -3
- package/blueprints/platform-cloudflare-durable-objects/contributions/requirements/platform-cloudflare-durable-objects-req-001.json +1 -1
- package/blueprints/platform-cloudflare-durable-objects/contributions/requirements/platform-cloudflare-durable-objects-req-002.json +1 -1
- package/blueprints/platform-cloudflare-durable-objects/contributions/requirements/platform-cloudflare-durable-objects-req-003.json +1 -1
- package/blueprints/platform-cloudflare-durable-objects/contributions/requirements/platform-cloudflare-durable-objects-req-004.json +1 -1
- package/blueprints/platform-cloudflare-durable-objects/contributions/requirements/platform-cloudflare-durable-objects-req-005.json +1 -1
- package/blueprints/platform-cloudflare-durable-objects/contributions/requirements/platform-cloudflare-durable-objects-req-006.json +1 -1
- package/blueprints/platform-cloudflare-durable-objects/contributions/requirements/platform-cloudflare-durable-objects-req-007.json +1 -1
- package/blueprints/platform-cloudflare-durable-objects/contributions/requirements/platform-cloudflare-durable-objects-req-008.json +1 -1
- package/blueprints/platform-cloudflare-durable-objects/contributions/tacs/tac-3401-platform-cloudflare-durable-objects-namespace-facade.json +6 -4
- package/blueprints/platform-cloudflare-durable-objects/contributions/tacs/tac-3402-platform-cloudflare-durable-objects-single-cell-shape.json +6 -4
- package/blueprints/platform-cloudflare-durable-objects/contributions/tacs/tac-3403-platform-cloudflare-durable-objects-alarm-handler.json +6 -4
- package/blueprints/platform-cloudflare-durable-objects/contributions/tacs/tac-3404-platform-cloudflare-durable-objects-websocket-hub.json +6 -4
- package/blueprints/platform-cloudflare-durable-objects/contributions/tacs/tac-3405-platform-cloudflare-durable-objects-event-sink.json +3 -2
- package/blueprints/platform-cloudflare-durable-objects/contributions/user-stories/platform-cloudflare-durable-objects-us-33101.json +5 -5
- package/blueprints/platform-cloudflare-durable-objects/contributions/user-stories/platform-cloudflare-durable-objects-us-33102.json +4 -4
- package/blueprints/platform-cloudflare-durable-objects/contributions/user-stories/platform-cloudflare-durable-objects-us-33103.json +5 -5
- package/blueprints/platform-cloudflare-durable-objects/contributions/user-stories/platform-cloudflare-durable-objects-us-33104.json +5 -5
- package/blueprints/platform-cloudflare-durable-objects/contributions/user-stories/platform-cloudflare-durable-objects-us-33105.json +5 -5
- package/blueprints/platform-cloudflare-durable-objects/contributions/user-stories/platform-cloudflare-durable-objects-us-33106.json +4 -4
- package/blueprints/platform-cloudflare-durable-objects/contributions/user-stories/platform-cloudflare-durable-objects-us-33107.json +3 -3
- package/blueprints/platform-cloudflare-durable-objects/contributions/user-stories/platform-cloudflare-durable-objects-us-33108.json +5 -5
- package/blueprints/platform-cloudflare-durable-objects/contributions/user-stories/platform-cloudflare-durable-objects-us-33109.json +3 -3
- package/blueprints/platform-cloudflare-durable-objects/contributions/user-stories/platform-cloudflare-durable-objects-us-33110.json +4 -4
- package/blueprints/platform-cloudflare-durable-objects/contributions/user-stories/platform-cloudflare-durable-objects-us-33111.json +3 -3
- package/blueprints/platform-cloudflare-durable-objects/contributions/user-stories/platform-cloudflare-durable-objects-us-33112.json +3 -3
- package/blueprints/platform-cloudflare-durable-objects/contributions/user-stories/platform-cloudflare-durable-objects-us-33113.json +5 -5
- package/blueprints/platform-cloudflare-kv/contributions/requirements/platform-cloudflare-kv-req-001.json +1 -1
- package/blueprints/platform-cloudflare-kv/contributions/requirements/platform-cloudflare-kv-req-002.json +1 -1
- package/blueprints/platform-cloudflare-kv/contributions/requirements/platform-cloudflare-kv-req-003.json +1 -1
- package/blueprints/platform-cloudflare-kv/contributions/requirements/platform-cloudflare-kv-req-004.json +1 -1
- package/blueprints/platform-cloudflare-kv/contributions/requirements/platform-cloudflare-kv-req-005.json +1 -1
- package/blueprints/platform-cloudflare-kv/contributions/requirements/platform-cloudflare-kv-req-006.json +1 -1
- package/blueprints/platform-cloudflare-kv/contributions/requirements/platform-cloudflare-kv-req-007.json +1 -1
- package/blueprints/platform-cloudflare-kv/contributions/tacs/tac-3201-platform-cloudflare-kv-facade.json +3 -2
- package/blueprints/platform-cloudflare-kv/contributions/tacs/tac-3202-platform-cloudflare-kv-cache-aside.json +3 -2
- package/blueprints/platform-cloudflare-kv/contributions/tacs/tac-3203-platform-cloudflare-kv-event-sink.json +3 -2
- package/blueprints/platform-cloudflare-kv/contributions/user-stories/platform-cloudflare-kv-us-31101.json +4 -4
- package/blueprints/platform-cloudflare-kv/contributions/user-stories/platform-cloudflare-kv-us-31102.json +3 -3
- package/blueprints/platform-cloudflare-kv/contributions/user-stories/platform-cloudflare-kv-us-31103.json +4 -4
- package/blueprints/platform-cloudflare-kv/contributions/user-stories/platform-cloudflare-kv-us-31104.json +4 -4
- package/blueprints/platform-cloudflare-kv/contributions/user-stories/platform-cloudflare-kv-us-31105.json +4 -4
- package/blueprints/platform-cloudflare-kv/contributions/user-stories/platform-cloudflare-kv-us-31106.json +3 -3
- package/blueprints/platform-cloudflare-kv/contributions/user-stories/platform-cloudflare-kv-us-31107.json +3 -3
- package/blueprints/platform-cloudflare-kv/contributions/user-stories/platform-cloudflare-kv-us-31108.json +3 -3
- package/blueprints/platform-cloudflare-kv/contributions/user-stories/platform-cloudflare-kv-us-31109.json +4 -4
- package/blueprints/platform-cloudflare-kv/contributions/user-stories/platform-cloudflare-kv-us-31110.json +5 -5
- package/blueprints/platform-cloudflare-kv/contributions/user-stories/platform-cloudflare-kv-us-31111.json +5 -5
- package/blueprints/platform-docker-compose-host/contributions/requirements/platform-docker-compose-host-req-001.json +1 -1
- package/blueprints/platform-docker-compose-host/contributions/requirements/platform-docker-compose-host-req-002.json +1 -1
- package/blueprints/platform-docker-compose-host/contributions/requirements/platform-docker-compose-host-req-003.json +1 -1
- package/blueprints/platform-docker-compose-host/contributions/requirements/platform-docker-compose-host-req-004.json +1 -1
- package/blueprints/platform-docker-compose-host/contributions/requirements/platform-docker-compose-host-req-005.json +1 -1
- package/blueprints/platform-docker-compose-host/contributions/requirements/platform-docker-compose-host-req-006.json +1 -1
- package/blueprints/platform-docker-compose-host/contributions/requirements/platform-docker-compose-host-req-007.json +1 -1
- package/blueprints/platform-docker-compose-host/contributions/tacs/tac-3901-platform-docker-compose-host-compose-layout.json +3 -2
- package/blueprints/platform-docker-compose-host/contributions/tacs/tac-3902-platform-docker-compose-host-secrets-mount.json +3 -2
- package/blueprints/platform-docker-compose-host/contributions/tacs/tac-3903-platform-docker-compose-host-healthcheck-lint.json +3 -2
- package/blueprints/platform-docker-compose-host/contributions/tacs/tac-3904-platform-docker-compose-host-reverse-proxy-artefact.json +3 -2
- package/blueprints/platform-docker-compose-host/contributions/user-stories/platform-docker-compose-host-us-38101.json +5 -5
- package/blueprints/platform-docker-compose-host/contributions/user-stories/platform-docker-compose-host-us-38102.json +4 -4
- package/blueprints/platform-docker-compose-host/contributions/user-stories/platform-docker-compose-host-us-38103.json +4 -4
- package/blueprints/platform-docker-compose-host/contributions/user-stories/platform-docker-compose-host-us-38104.json +4 -4
- package/blueprints/platform-docker-compose-host/contributions/user-stories/platform-docker-compose-host-us-38105.json +3 -3
- package/blueprints/platform-docker-compose-host/contributions/user-stories/platform-docker-compose-host-us-38106.json +3 -3
- package/blueprints/platform-docker-compose-host/contributions/user-stories/platform-docker-compose-host-us-38107.json +3 -3
- package/blueprints/platform-docker-compose-host/contributions/user-stories/platform-docker-compose-host-us-38108.json +3 -3
- package/blueprints/platform-docker-compose-host/contributions/user-stories/platform-docker-compose-host-us-38109.json +3 -3
- package/blueprints/platform-docker-compose-host/contributions/user-stories/platform-docker-compose-host-us-38110.json +3 -3
- package/blueprints/security-auth-clerk/contributions/requirements/security-auth-clerk-req-001.json +1 -1
- package/blueprints/security-auth-clerk/contributions/requirements/security-auth-clerk-req-002.json +1 -1
- package/blueprints/security-auth-clerk/contributions/requirements/security-auth-clerk-req-003.json +1 -1
- package/blueprints/security-auth-clerk/contributions/requirements/security-auth-clerk-req-004.json +1 -1
- package/blueprints/security-auth-clerk/contributions/requirements/security-auth-clerk-req-006.json +1 -1
- package/blueprints/security-auth-clerk/contributions/requirements/security-auth-clerk-req-010.json +1 -1
- package/blueprints/security-auth-clerk/contributions/requirements/security-auth-clerk-req-011.json +1 -1
- package/blueprints/security-auth-clerk/contributions/tacs/tac-1001-security-auth-clerk-middleware.json +6 -6
- package/blueprints/security-auth-clerk/contributions/tacs/tac-1002-security-auth-clerk-authorisation-adapter.json +8 -3
- package/blueprints/security-auth-clerk/contributions/tacs/tac-1003-security-auth-clerk-session-verifier.json +8 -8
- package/blueprints/security-auth-clerk/contributions/user-stories/security-auth-clerk-us-9102.json +1 -1
- package/blueprints/security-auth-clerk/contributions/user-stories/security-auth-clerk-us-9108.json +1 -1
- package/blueprints/security-auth-clerk/contributions/user-stories/security-auth-clerk-us-9112.json +6 -6
- package/blueprints/security-auth-clerk/contributions/user-stories/security-auth-clerk-us-9113.json +6 -6
- package/blueprints/security-auth-keycloak/contributions/requirements/security-auth-keycloak-req-002.json +1 -1
- package/blueprints/security-auth-keycloak/contributions/requirements/security-auth-keycloak-req-003.json +1 -1
- package/blueprints/security-auth-keycloak/contributions/requirements/security-auth-keycloak-req-004.json +1 -1
- package/blueprints/security-auth-keycloak/contributions/requirements/security-auth-keycloak-req-005.json +1 -1
- package/blueprints/security-auth-keycloak/contributions/requirements/security-auth-keycloak-req-006.json +1 -1
- package/blueprints/security-auth-keycloak/contributions/requirements/security-auth-keycloak-req-011.json +1 -1
- package/blueprints/security-auth-keycloak/contributions/requirements/security-auth-keycloak-req-013.json +1 -1
- package/blueprints/security-auth-keycloak/contributions/requirements/security-auth-keycloak-req-014.json +1 -1
- package/blueprints/security-auth-keycloak/contributions/requirements/security-auth-keycloak-req-015.json +1 -1
- package/blueprints/security-auth-keycloak/contributions/requirements/security-auth-keycloak-req-016.json +1 -1
- package/blueprints/security-auth-keycloak/contributions/requirements/security-auth-keycloak-req-017.json +1 -1
- package/blueprints/security-auth-keycloak/contributions/requirements/security-auth-keycloak-req-018.json +1 -1
- package/blueprints/security-auth-keycloak/contributions/requirements/security-auth-keycloak-req-019.json +1 -1
- package/blueprints/security-auth-keycloak/contributions/tacs/tac-1201-security-auth-keycloak-discovery-client.json +10 -10
- package/blueprints/security-auth-keycloak/contributions/tacs/tac-1202-security-auth-keycloak-jwt-verifier.json +8 -8
- package/blueprints/security-auth-keycloak/contributions/tacs/tac-1203-security-auth-keycloak-introspection-client.json +8 -8
- package/blueprints/security-auth-keycloak/contributions/tacs/tac-1204-security-auth-keycloak-provider-router.json +6 -6
- package/blueprints/security-auth-keycloak/contributions/tacs/tac-1205-security-auth-keycloak-role-adapter.json +4 -4
- package/blueprints/security-auth-keycloak/contributions/user-stories/security-auth-keycloak-us-11102.json +1 -1
- package/blueprints/security-auth-keycloak/contributions/user-stories/security-auth-keycloak-us-11103.json +2 -2
- package/blueprints/security-auth-keycloak/contributions/user-stories/security-auth-keycloak-us-11104.json +1 -1
- package/blueprints/security-auth-keycloak/contributions/user-stories/security-auth-keycloak-us-11106.json +3 -3
- package/blueprints/security-auth-keycloak/contributions/user-stories/security-auth-keycloak-us-11111.json +2 -2
- package/blueprints/security-auth-keycloak/contributions/user-stories/security-auth-keycloak-us-11114.json +1 -1
- package/blueprints/security-auth-keycloak/contributions/user-stories/security-auth-keycloak-us-11115.json +5 -5
- package/blueprints/security-auth-keycloak/contributions/user-stories/security-auth-keycloak-us-11116.json +7 -7
- package/blueprints/security-auth-keycloak/contributions/user-stories/security-auth-keycloak-us-11117.json +7 -7
- package/blueprints/security-auth-keycloak/contributions/user-stories/security-auth-keycloak-us-11118.json +7 -7
- package/blueprints/security-auth-keycloak/contributions/user-stories/security-auth-keycloak-us-11119.json +7 -7
- package/blueprints/security-auth-keycloak/contributions/user-stories/security-auth-keycloak-us-11120.json +6 -6
- package/blueprints/security-auth-magic-link/contributions/requirements/security-auth-magic-link-req-002.json +1 -1
- package/blueprints/security-auth-magic-link/contributions/requirements/security-auth-magic-link-req-003.json +1 -1
- package/blueprints/security-auth-magic-link/contributions/requirements/security-auth-magic-link-req-004.json +1 -1
- package/blueprints/security-auth-magic-link/contributions/requirements/security-auth-magic-link-req-005.json +1 -1
- package/blueprints/security-auth-magic-link/contributions/requirements/security-auth-magic-link-req-008.json +1 -1
- package/blueprints/security-auth-magic-link/contributions/requirements/security-auth-magic-link-req-009.json +1 -1
- package/blueprints/security-auth-magic-link/contributions/requirements/security-auth-magic-link-req-010.json +1 -1
- package/blueprints/security-auth-magic-link/contributions/requirements/security-auth-magic-link-req-011.json +1 -1
- package/blueprints/security-auth-magic-link/contributions/tacs/tac-501-security-auth-magic-link-manager.json +6 -6
- package/blueprints/security-auth-magic-link/contributions/tacs/tac-502-security-auth-magic-link-session-manager.json +6 -6
- package/blueprints/security-auth-magic-link/contributions/tacs/tac-503-security-auth-magic-link-login-routes.json +10 -10
- package/blueprints/security-auth-magic-link/contributions/tacs/tac-504-security-auth-magic-link-email-delivery-adapter.json +2 -2
- package/blueprints/security-auth-magic-link/contributions/tacs/tac-505-security-auth-magic-link-principal-registry.json +2 -2
- package/blueprints/security-auth-magic-link/contributions/user-stories/security-auth-magic-link-us-3111.json +2 -2
- package/blueprints/security-auth-oauth2/contributions/requirements/security-auth-oauth2-req-002.json +1 -1
- package/blueprints/security-auth-oauth2/contributions/requirements/security-auth-oauth2-req-003.json +1 -1
- package/blueprints/security-auth-oauth2/contributions/requirements/security-auth-oauth2-req-005.json +1 -1
- package/blueprints/security-auth-oauth2/contributions/requirements/security-auth-oauth2-req-006.json +1 -1
- package/blueprints/security-auth-oauth2/contributions/requirements/security-auth-oauth2-req-008.json +1 -1
- package/blueprints/security-auth-oauth2/contributions/requirements/security-auth-oauth2-req-009.json +1 -1
- package/blueprints/security-auth-oauth2/contributions/requirements/security-auth-oauth2-req-011.json +1 -1
- package/blueprints/security-auth-oauth2/contributions/requirements/security-auth-oauth2-req-012.json +1 -1
- package/blueprints/security-auth-oauth2/contributions/requirements/security-auth-oauth2-req-013.json +1 -1
- package/blueprints/security-auth-oauth2/contributions/tacs/tac-1101-security-auth-oauth2-flow-controller.json +24 -14
- package/blueprints/security-auth-oauth2/contributions/tacs/tac-1102-security-auth-oauth2-provider-adapter.json +4 -4
- package/blueprints/security-auth-oauth2/contributions/tacs/tac-1103-security-auth-oauth2-session-bridge.json +10 -10
- package/blueprints/security-auth-oauth2/contributions/tacs/tac-1104-security-auth-oauth2-provider-selector.json +8 -3
- package/blueprints/security-auth-oauth2/contributions/user-stories/security-auth-oauth2-us-10111.json +1 -1
- package/blueprints/security-auth-oauth2/contributions/user-stories/security-auth-oauth2-us-10112.json +1 -1
- package/blueprints/security-auth-oauth2/contributions/user-stories/security-auth-oauth2-us-10114.json +5 -5
- package/blueprints/security-secrets-management/contributions/requirements/security-secrets-management-req-001.json +1 -1
- package/blueprints/security-secrets-management/contributions/requirements/security-secrets-management-req-002.json +1 -1
- package/blueprints/security-secrets-management/contributions/requirements/security-secrets-management-req-003.json +1 -1
- package/blueprints/security-secrets-management/contributions/requirements/security-secrets-management-req-004.json +1 -1
- package/blueprints/security-secrets-management/contributions/requirements/security-secrets-management-req-005.json +1 -1
- package/blueprints/security-secrets-management/contributions/requirements/security-secrets-management-req-006.json +1 -1
- package/blueprints/security-secrets-management/contributions/requirements/security-secrets-management-req-007.json +1 -1
- package/blueprints/security-secrets-management/contributions/requirements/security-secrets-management-req-008.json +1 -1
- package/blueprints/security-secrets-management/contributions/requirements/security-secrets-management-req-009.json +1 -1
- package/blueprints/security-secrets-management/contributions/tacs/tac-901-security-secrets-management-manager-client.json +8 -8
- package/blueprints/security-secrets-management/contributions/tacs/tac-902-security-secrets-management-manifest.json +4 -4
- package/blueprints/security-secrets-management/contributions/tacs/tac-903-security-secrets-management-env-reflector.json +4 -4
- package/blueprints/security-secrets-management/contributions/tacs/tac-904-security-secrets-management-rotation-gate.json +8 -8
- package/blueprints/security-secrets-management/contributions/tacs/tac-905-security-secrets-management-agent-cli.json +4 -4
- package/fixtures/canary-manifest.json +9 -9
- package/guidance/define-draft-shapes.md +15 -10
- package/guidance/define-litmus.md +102 -0
- package/guidance/manifest.json +2 -1
- package/package.json +1 -1
- package/rcf/adrs/adr-4131-gates-bite-ack-recorded-override.json +30 -0
- package/rcf/adrs/adr-4137-standalone-theme-persistence.json +30 -0
- package/rcf/adrs/adr-4138-tree-wide-checks-before-scope-shortcircuit.json +35 -0
- package/rcf/code-nodes/cn-753.json +19 -0
- package/rcf/code-nodes/cn-754.json +17 -0
- package/rcf/code-nodes/cn-755.json +14 -0
- package/rcf/code-nodes/cn-756.json +15 -0
- package/rcf/code-nodes/cn-757.json +21 -0
- package/rcf/code-nodes/cn-758.json +16 -0
- package/rcf/code-nodes/cn-759.json +21 -0
- package/rcf/code-nodes/cn-760.json +19 -0
- package/rcf/code-nodes/cn-761.json +16 -0
- package/rcf/code-nodes/cn-762.json +18 -0
- package/rcf/code-nodes/cn-763.json +18 -0
- package/rcf/code-nodes/cn-764.json +15 -0
- package/rcf/code-nodes/cn-765.json +23 -0
- package/rcf/code-nodes/cn-766.json +17 -0
- package/rcf/code-nodes/cn-767.json +17 -0
- package/rcf/code-nodes/cn-768.json +19 -0
- package/rcf/code-nodes/cn-769.json +17 -0
- package/rcf/code-nodes/cn-770.json +18 -0
- package/rcf/code-nodes/cn-771.json +14 -0
- package/rcf/code-nodes/cn-772.json +14 -0
- package/rcf/code-nodes/cn-773.json +16 -0
- package/rcf/code-nodes/cn-774.json +20 -0
- package/rcf/code-nodes/cn-775.json +15 -0
- package/rcf/code-nodes/cn-776.json +17 -0
- package/rcf/code-nodes/cn-777.json +21 -0
- package/rcf/fbs/fbs-202.json +85 -9
- package/rcf/fbs/fbs-203.json +12 -4
- package/rcf/requirements/req-002.json +2 -2
- package/rcf/requirements/req-173.json +2 -2
- package/rcf/requirements/req-174.json +2 -2
- package/rcf/requirements/req-175.json +2 -2
- package/rcf/requirements/req-177.json +31 -0
- package/rcf/requirements/req-178.json +31 -0
- package/rcf/requirements/req-179.json +31 -0
- package/rcf/tacs/tac-001.json +7 -7
- package/rcf/tacs/tac-002.json +23 -23
- package/rcf/tacs/tac-003.json +5 -5
- package/rcf/tacs/tac-004.json +9 -9
- package/rcf/tacs/tac-005.json +7 -7
- package/rcf/tacs/tac-006.json +21 -21
- package/rcf/tacs/tac-007.json +7 -7
- package/rcf/tacs/tac-008.json +7 -7
- package/rcf/tacs/tac-4101-feedback-cli.json +5 -5
- package/rcf/tacs/tac-4102-feedback-store.json +9 -9
- package/rcf/tacs/tac-4103-feedback-redact.json +5 -5
- package/rcf/tacs/tac-4104-feedback-fingerprint.json +3 -3
- package/rcf/tacs/tac-4105-feedback-render.json +7 -7
- package/rcf/tacs/tac-4106-feedback-destination.json +5 -5
- package/rcf/tacs/tac-4107-feedback-gh.json +7 -7
- package/rcf/tacs/tac-4108-feedback-hook.json +7 -7
- package/rcf/tacs/tac-4121-define-ledgers.json +3 -2
- package/rcf/tacs/tac-4122-define-gates.json +36 -3
- package/rcf/tacs/tac-4123-define-readiness.json +29 -3
- package/rcf/tacs/tac-4125-build-bundle-refuse-override-skip.json +43 -0
- package/rcf/tacs/tac-4126-define-validate-findings.json +32 -0
- package/rcf/tacs/tac-4128-define-guidance.json +8 -2
- package/rcf/tacs/tac-4129-define-questions.json +3 -3
- package/rcf/tacs/tac-4134-wespa-host-fixture.json +9 -9
- package/rcf/test-suites/ts-007.json +1 -1
- package/rcf/test-suites/ts-215.json +64 -1
- package/rcf/test-suites/ts-216.json +18 -2
- package/rcf/test-suites/ts-219.json +10 -2
- package/rcf/test-suites/ts-220.json +18 -2
- package/rcf/test-suites/ts-222.json +4 -4
- package/rcf/test-suites/ts-225.json +10 -2
- package/rcf/test-suites/ts-228.json +4 -4
- package/rcf/test-suites/ts-229.json +49 -3
- package/rcf/test-suites/ts-230.json +100 -0
- package/rcf/test-suites/ts-231.json +119 -0
- package/rcf/test-suites/ts-232.json +109 -0
- package/rcf/test-suites/ts-233.json +61 -0
- package/rcf/test-suites/ts-234.json +53 -0
- package/rcf/test-suites/ts-235.json +53 -0
- package/rcf/test-suites/ts-236.json +44 -0
- package/rcf/user-stories/us-17302.json +36 -1
- package/rcf/user-stories/us-17401.json +11 -1
- package/rcf/user-stories/us-17402.json +6 -1
- package/rcf/user-stories/us-17403.json +11 -1
- package/rcf/user-stories/us-17404.json +66 -0
- package/rcf/user-stories/us-17405.json +66 -0
- package/rcf/user-stories/us-17406.json +51 -0
- package/rcf/user-stories/us-17503.json +2 -2
- package/rcf/user-stories/us-17504.json +46 -0
- package/rcf/user-stories/us-17702.json +51 -0
- package/rcf/user-stories/us-17802.json +40 -0
- package/rcf/user-stories/us-17902.json +46 -0
- package/rcf/user-stories/us-205.json +6 -1
- package/rcf/user-stories/us-206.json +25 -4
- package/rcf/user-stories/us-207.json +36 -0
- package/releases/releases.yaml +21 -1
- package/src/blueprint/consistency-lint.js +72 -3
- package/src/cli/build.js +206 -3
- package/src/cli/create.js +22 -2
- package/src/cli/freeze.js +68 -18
- package/src/cli/ledger.js +96 -4
- package/src/cli/readiness.js +151 -36
- package/src/cli/validate.js +8 -0
- package/src/core/errors/index.js +7 -1
- package/src/core/store/writer.js +181 -13
- package/src/define/concern-catalogue.js +130 -0
- package/src/define/freeze-record.js +74 -0
- package/src/define/ledgers.js +86 -7
- package/src/define/probe-runner.js +55 -0
- package/src/define/validate-findings.js +256 -0
- package/src/mcp/tools.js +1 -1
- package/src/query/gates.js +1235 -67
- package/src/query/index.js +6 -1
- package/src/query/readiness.js +179 -2
- package/src/query/refuse-on-admissibility.js +137 -4
- package/src/ruleset/ruleset.json +35 -0
- package/src/view/html-page.js +14 -2
- package/src/view/page-init.js +149 -8
- package/src/view/style.css +97 -18
- package/src/view/view-index.js +22 -0
package/src/query/gates.js
CHANGED
|
@@ -46,6 +46,7 @@
|
|
|
46
46
|
import { computeQueue } from '../build/queue.js';
|
|
47
47
|
import { isOptedOut } from '../req-baseline/opt-out.js';
|
|
48
48
|
import { BRIEF_KINDS, parseResolvedBy } from '../define/ledgers.js';
|
|
49
|
+
import { applicableConcernsForShapes } from '../define/concern-catalogue.js';
|
|
49
50
|
|
|
50
51
|
/** Canonical stage order (proposal §3.2). */
|
|
51
52
|
export const STAGE_ORDER = /** @type {const} */ (['D1', 'D2', 'D3', 'D4', 'D5', 'D6', 'D7', 'D8']);
|
|
@@ -113,26 +114,37 @@ export const CHECK_PERSONA = /** @type {const} */ ({
|
|
|
113
114
|
'brief:kinds': 'productOwner',
|
|
114
115
|
'brief:openQuestions': 'productOwner',
|
|
115
116
|
'brief:profile': 'productOwner',
|
|
116
|
-
// D2 Skeleton: resolvedBy + reqIntent are PO; reqShape, tadPersistence, deployAdr are engineer.
|
|
117
|
+
// D2 Skeleton: resolvedBy + reqIntent are PO; reqShape, tadPersistence, deployAdr, standardsCited are engineer.
|
|
117
118
|
'skeleton:resolvedBy': 'productOwner',
|
|
118
119
|
'skeleton:reqIntent': 'productOwner',
|
|
119
120
|
'skeleton:reqShape': 'engineer',
|
|
120
121
|
'skeleton:tadPersistence': 'engineer',
|
|
121
122
|
'skeleton:deployAdr': 'engineer',
|
|
123
|
+
'skeleton:standardsCited': 'engineer',
|
|
122
124
|
// D3 Shapes: every check is engineer (shapes are the engineer's first act after hand-over).
|
|
123
125
|
'shapes:tacHasInterface': 'engineer',
|
|
124
126
|
'shapes:kindVocabulary': 'engineer',
|
|
125
127
|
'shapes:draftSettled': 'engineer',
|
|
126
|
-
|
|
128
|
+
'shapes:templateMarkers': 'engineer',
|
|
129
|
+
'shapes:entityJoin': 'engineer',
|
|
130
|
+
'shapes:pathsResolve': 'engineer',
|
|
131
|
+
// D4 Stories: reqHasUs is PO ("what does someone do with this?"); the floors, closed sets and ownerRef resolution are engineer.
|
|
127
132
|
'stories:reqHasUs': 'productOwner',
|
|
128
133
|
'stories:usFloors': 'engineer',
|
|
129
|
-
|
|
134
|
+
'stories:closedSets': 'engineer',
|
|
135
|
+
'stories:ownerRefResolves': 'engineer',
|
|
136
|
+
// D5 Crosscut: TAD + concern-ledger content and the catalogue walk are engineering.
|
|
130
137
|
'crosscut:securityArchitecture': 'engineer',
|
|
131
138
|
'crosscut:operationalConcerns': 'engineer',
|
|
132
139
|
'crosscut:concernsResolved': 'engineer',
|
|
133
|
-
|
|
140
|
+
'crosscut:catalogue': 'engineer',
|
|
141
|
+
// D6 Consistency: schema validity, probes and the four scans are engineer.
|
|
134
142
|
'consistency:validateClean': 'engineer',
|
|
135
143
|
'consistency:probeCount': 'engineer',
|
|
144
|
+
'consistency:contradictions': 'engineer',
|
|
145
|
+
'consistency:unsatisfiable': 'engineer',
|
|
146
|
+
'consistency:duplicates': 'engineer',
|
|
147
|
+
'consistency:orphanInterfaces': 'engineer',
|
|
136
148
|
// D7 Decisions: enumeration is PO (the PO answers or lets the default stand);
|
|
137
149
|
// zero-open is the engineer's hand-over condition.
|
|
138
150
|
'decisions:wellFormed': 'productOwner',
|
|
@@ -161,16 +173,27 @@ export const CHECK_QUESTION = /** @type {const} */ ({
|
|
|
161
173
|
'skeleton:reqShape': 'Every requirement in scope carries a shape classification.',
|
|
162
174
|
'skeleton:tadPersistence': 'TAD data architecture lists dataStores and coreEntities for persistence REQs.',
|
|
163
175
|
'skeleton:deployAdr': 'Exactly one Deploy target or Deploy deferral ADR exists.',
|
|
176
|
+
'skeleton:standardsCited': 'Every registered standards pack is cited, applied or waived.',
|
|
164
177
|
'shapes:tacHasInterface': 'Every TAC in scope has at least one interface.',
|
|
165
178
|
'shapes:kindVocabulary': 'Every interface kind is in the closed vocabulary.',
|
|
166
179
|
'shapes:draftSettled': 'Every draft interface has been settled (the [draft] marker is removed).',
|
|
180
|
+
'shapes:templateMarkers': 'Every interface description carries the per-kind markers (recordShape fields:, httpRoute method/path/request/response/errors, and so on).',
|
|
181
|
+
'shapes:entityJoin': 'Every core entity is named by exactly one recordShape.',
|
|
182
|
+
'shapes:pathsResolve': 'Every path: token in an interface description resolves on disk or the description is authoredAt D3.',
|
|
167
183
|
'stories:reqHasUs': 'What does someone do with this requirement?',
|
|
168
184
|
'stories:usFloors': 'Every story in scope meets the class, tacIds and testability floors.',
|
|
185
|
+
'stories:closedSets': 'Every acceptance criterion that invites a set of values names the set or points to an owner.',
|
|
186
|
+
'stories:ownerRefResolves': 'Every ownerRef on an acceptance criterion resolves to an interface on the owning TAC.',
|
|
169
187
|
'crosscut:securityArchitecture': 'TAD.securityArchitecture is present when an auth or httpApi REQ exists.',
|
|
170
188
|
'crosscut:operationalConcerns': 'TAD.operationalConcerns is present when a deployed-scope AC exists.',
|
|
171
189
|
'crosscut:concernsResolved': 'Every concern-ledger entry on a REQ in scope is applied or waived.',
|
|
190
|
+
'crosscut:catalogue': 'Every applicable crosscut concern for a REQ in scope has a concern-ledger entry applied or waived.',
|
|
172
191
|
'consistency:validateClean': 'Validate is clean tree-wide.',
|
|
173
192
|
'consistency:probeCount': 'Zero open probe-ledger entries.',
|
|
193
|
+
'consistency:contradictions': 'No two acceptance criteria on one story share a when clause with a negated then.',
|
|
194
|
+
'consistency:unsatisfiable': 'Every then names a field some recordShape defines.',
|
|
195
|
+
'consistency:duplicates': 'No two acceptance criteria across stories share an identical description.',
|
|
196
|
+
'consistency:orphanInterfaces': 'Every interface is reached by an AC ownerRef or a REQ deliveredBy.',
|
|
174
197
|
'decisions:wellFormed': 'Every decision is enumerated (question, two or more options, a default).',
|
|
175
198
|
'decisions:allAnswered': 'Zero decisions are open.',
|
|
176
199
|
'freeze:priorGates': 'Every prior stage passed or is acknowledged at the current hash.',
|
|
@@ -280,6 +303,146 @@ export function parseCoreEntityDraft(entity) {
|
|
|
280
303
|
return hasDraftMarker(/** @type {any} */ (entity).description);
|
|
281
304
|
}
|
|
282
305
|
|
|
306
|
+
/**
|
|
307
|
+
* Per-kind required marker tokens on `interfaces[].description` for
|
|
308
|
+
* the `shapes:templateMarkers` D3 bite check (ADR-4131, spec section 4
|
|
309
|
+
* row "D3 template parser"). A marker is "present" when a line of the
|
|
310
|
+
* description matches the marker's own regex: a `<name>:` prefix for
|
|
311
|
+
* `fields:`, `instances:`, `payload:`, `usage:` and `format:`; a
|
|
312
|
+
* `method`, `path`, `request`, `response`, `errors` or `protocol`
|
|
313
|
+
* token on an httpRoute, uiRoute or port (word-bounded, case-sensitive,
|
|
314
|
+
* tolerating a trailing colon or whitespace); `other` requires a
|
|
315
|
+
* non-empty description after the optional `[draft]` prefix (its
|
|
316
|
+
* "note"). The regexes are deliberately permissive so a plain
|
|
317
|
+
* `method: POST` and a bullet list `- method: POST` both qualify, and
|
|
318
|
+
* so a `[draft]` prefix never masks the marker scan.
|
|
319
|
+
*/
|
|
320
|
+
const INTERFACE_TEMPLATE_MARKERS = /** @type {const} */ ({
|
|
321
|
+
recordShape: [{ name: 'fields', re: /(^|\n)\s*(?:[-*]\s*)?fields\s*:/ }],
|
|
322
|
+
httpRoute: [
|
|
323
|
+
{ name: 'method', re: /(^|\n|\s)method\s*[:=]/ },
|
|
324
|
+
{ name: 'path', re: /(^|\n|\s)path\s*[:=]/ },
|
|
325
|
+
{ name: 'request', re: /(^|\n|\s)request\s*[:=]/ },
|
|
326
|
+
{ name: 'response', re: /(^|\n|\s)response\s*[:=]/ },
|
|
327
|
+
{ name: 'errors', re: /(^|\n|\s)errors\s*[:=]/ },
|
|
328
|
+
],
|
|
329
|
+
fixture: [{ name: 'instances', re: /(^|\n)\s*(?:[-*]\s*)?instances\s*:/ }],
|
|
330
|
+
event: [{ name: 'payload', re: /(^|\n)\s*(?:[-*]\s*)?payload\s*:/ }],
|
|
331
|
+
cliCommand: [{ name: 'usage', re: /(^|\n)\s*(?:[-*]\s*)?usage\s*:/ }],
|
|
332
|
+
uiRoute: [{ name: 'path', re: /(^|\n|\s)path\s*[:=]/ }],
|
|
333
|
+
port: [{ name: 'protocol', re: /(^|\n|\s)protocol\s*[:=]/ }],
|
|
334
|
+
fileFormat: [{ name: 'format', re: /(^|\n)\s*(?:[-*]\s*)?format\s*:/ }],
|
|
335
|
+
other: [],
|
|
336
|
+
});
|
|
337
|
+
|
|
338
|
+
/**
|
|
339
|
+
* Strip a leading `[draft]` marker from a description so the marker
|
|
340
|
+
* scan sees the real text underneath. Pure.
|
|
341
|
+
*
|
|
342
|
+
* @param {string} desc
|
|
343
|
+
* @returns {string}
|
|
344
|
+
*/
|
|
345
|
+
function stripDraftPrefix(desc) {
|
|
346
|
+
return desc.replace(/^\s*\[draft\]\s*/, '');
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
/**
|
|
350
|
+
* ADR-4131 (0.30.0 PR 5): per-kind marker presence on an interface.
|
|
351
|
+
* Returns `{ kind, missing: string[] }` naming the markers that are
|
|
352
|
+
* absent from `iface.description`. For `other` the "note" is any
|
|
353
|
+
* non-empty description after the optional `[draft]` prefix. For an
|
|
354
|
+
* interface whose kind is outside INTERFACE_KINDS the function returns
|
|
355
|
+
* `{ kind, missing: [] }` so the caller can treat vocabulary errors
|
|
356
|
+
* through `shapes:kindVocabulary` alone.
|
|
357
|
+
*
|
|
358
|
+
* @param {unknown} iface
|
|
359
|
+
* @returns {{ kind: string|null, missing: string[] }}
|
|
360
|
+
*/
|
|
361
|
+
export function parseInterfaceTemplate(iface) {
|
|
362
|
+
if (!iface || typeof iface !== 'object') return { kind: null, missing: [] };
|
|
363
|
+
const kind = typeof (/** @type {any} */ (iface).kind) === 'string' ? /** @type {any} */ (iface).kind : null;
|
|
364
|
+
const descRaw = typeof (/** @type {any} */ (iface).description) === 'string'
|
|
365
|
+
? /** @type {any} */ (iface).description
|
|
366
|
+
: '';
|
|
367
|
+
const desc = stripDraftPrefix(descRaw);
|
|
368
|
+
if (kind === 'other') {
|
|
369
|
+
const note = desc.trim();
|
|
370
|
+
return { kind, missing: note.length === 0 ? ['note'] : [] };
|
|
371
|
+
}
|
|
372
|
+
const markers = /** @type {any} */ (INTERFACE_TEMPLATE_MARKERS)[kind];
|
|
373
|
+
if (!Array.isArray(markers)) return { kind, missing: [] };
|
|
374
|
+
const missing = [];
|
|
375
|
+
for (const marker of markers) {
|
|
376
|
+
if (!marker.re.test(desc)) missing.push(marker.name);
|
|
377
|
+
}
|
|
378
|
+
return { kind, missing };
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
/**
|
|
382
|
+
* Known bare repo filenames the slash-or-extension rule would otherwise
|
|
383
|
+
* silently skip (ruling R6 2026-10-05). A `path: Dockerfile` on an
|
|
384
|
+
* interface description names a real file at the repo root, so the
|
|
385
|
+
* `shapes:pathsResolve` check should see it. Exported so the tests can
|
|
386
|
+
* assert the list verbatim; a bare word outside this set still fails
|
|
387
|
+
* the slash-or-extension rule as before.
|
|
388
|
+
*/
|
|
389
|
+
export const BARE_PATH_WHITELIST = /** @type {const} */ ([
|
|
390
|
+
'Dockerfile',
|
|
391
|
+
'Containerfile',
|
|
392
|
+
'Makefile',
|
|
393
|
+
'LICENSE',
|
|
394
|
+
'Procfile',
|
|
395
|
+
'Justfile',
|
|
396
|
+
'Rakefile',
|
|
397
|
+
'Gemfile',
|
|
398
|
+
'CODEOWNERS',
|
|
399
|
+
]);
|
|
400
|
+
const BARE_PATH_WHITELIST_SET = new Set(BARE_PATH_WHITELIST);
|
|
401
|
+
|
|
402
|
+
/**
|
|
403
|
+
* Rough `path:` token scanner for an interface description. Returns
|
|
404
|
+
* every candidate path token the description names so the CLI can
|
|
405
|
+
* resolve them on disk and the gate can decide `shapes:pathsResolve`
|
|
406
|
+
* against the resolved map (ADR-4131). A candidate is any text that
|
|
407
|
+
* follows a `path:` or `path =` marker and looks like a repo-relative
|
|
408
|
+
* path (contains a `/` or ends with a file extension, or is one of the
|
|
409
|
+
* known bare repo names in BARE_PATH_WHITELIST per ruling R6
|
|
410
|
+
* 2026-10-05, no scheme). The scanner is deliberately conservative: an
|
|
411
|
+
* http URL, a bare word outside the whitelist, a glob or a template
|
|
412
|
+
* placeholder is not a candidate. Exported for the CLI's resolve-on-disk
|
|
413
|
+
* pass.
|
|
414
|
+
*
|
|
415
|
+
* @param {string} description
|
|
416
|
+
* @returns {string[]}
|
|
417
|
+
*/
|
|
418
|
+
export function extractInterfacePathTokens(description) {
|
|
419
|
+
if (typeof description !== 'string' || description.length === 0) return [];
|
|
420
|
+
const text = stripDraftPrefix(description);
|
|
421
|
+
const out = [];
|
|
422
|
+
const re = /\bpath\s*[:=]\s*["'`]?([^\s"'`,;)\]]+)/g;
|
|
423
|
+
let m;
|
|
424
|
+
while ((m = re.exec(text)) !== null) {
|
|
425
|
+
const token = m[1];
|
|
426
|
+
if (!token) continue;
|
|
427
|
+
if (/^[a-z]+:\/\//i.test(token)) continue;
|
|
428
|
+
if (token.startsWith('{') || token.startsWith('<') || token.includes('*')) continue;
|
|
429
|
+
// Skip HTTP / UI route-ish tokens: a leading slash with no file
|
|
430
|
+
// extension is a route path (an httpRoute or uiRoute's `path:`
|
|
431
|
+
// marker), not a repo path. A legitimate file path lands as
|
|
432
|
+
// `src/x.js` or `packages/rcf-lite/CHANGELOG.md`; those don't
|
|
433
|
+
// start with `/`.
|
|
434
|
+
if (token.startsWith('/') && !/\.[a-zA-Z0-9]+$/.test(token)) continue;
|
|
435
|
+
// Ruling R6 2026-10-05: whitelist the usual bare repo names.
|
|
436
|
+
if (BARE_PATH_WHITELIST_SET.has(token)) {
|
|
437
|
+
out.push(token);
|
|
438
|
+
continue;
|
|
439
|
+
}
|
|
440
|
+
if (!/\//.test(token) && !/\.[a-zA-Z0-9]+$/.test(token)) continue;
|
|
441
|
+
out.push(token);
|
|
442
|
+
}
|
|
443
|
+
return out;
|
|
444
|
+
}
|
|
445
|
+
|
|
283
446
|
/** Warn-with-ack stages in 0.29.0 (ADR-4122). */
|
|
284
447
|
const WARN_WITH_ACK = new Set(['D3', 'D5', 'D6']);
|
|
285
448
|
|
|
@@ -297,6 +460,23 @@ export function stagePolicy(stage) {
|
|
|
297
460
|
return WARN_WITH_ACK.has(stage) ? 'warnWithAck' : 'blocking';
|
|
298
461
|
}
|
|
299
462
|
|
|
463
|
+
/**
|
|
464
|
+
* ADR-4131 (0.30.0 PR 5): the three gates that accept a recorded
|
|
465
|
+
* `--ack` override. `stagePolicy(stage)` returns `warnWithAck` for
|
|
466
|
+
* D3/D5/D6 and `blocking` for everything else (ruling R4 2026-10-05
|
|
467
|
+
* retired the pre-R4 wording that said `stagePolicy` kept returning
|
|
468
|
+
* `blocking` for every stage); `ackable(stage)` is the companion
|
|
469
|
+
* signal the readiness and freeze CLIs read to decide whether a
|
|
470
|
+
* failing stage honours an acknowledgement at the current hash. True
|
|
471
|
+
* for D3, D5 and D6; false for everything else.
|
|
472
|
+
*
|
|
473
|
+
* @param {string} stage
|
|
474
|
+
* @returns {boolean}
|
|
475
|
+
*/
|
|
476
|
+
export function ackable(stage) {
|
|
477
|
+
return WARN_WITH_ACK.has(stage);
|
|
478
|
+
}
|
|
479
|
+
|
|
300
480
|
/**
|
|
301
481
|
* Scaffold TODO placeholder marker: uppercase "TODO" followed by a
|
|
302
482
|
* colon, matching every scaffold string `rcf init` and `rcf define
|
|
@@ -313,6 +493,192 @@ const TODO_RE = /\bTODO:/;
|
|
|
313
493
|
/** Bracketed AC-class prefix (Baz decision 6, proposal §3.2 D4). */
|
|
314
494
|
const AC_CLASS_RE = /^\[(happy|edge|failure|must-not|non-functional)\]/;
|
|
315
495
|
|
|
496
|
+
/**
|
|
497
|
+
* Enumeration cues for `stories:closedSets` (spec section 4 row 'D4
|
|
498
|
+
* closed-set and ownerRef as findings', 0.30.0 PR 6). An AC description
|
|
499
|
+
* that contains any of these cues outside a quoted string, with no
|
|
500
|
+
* inline bracketed list or ownerRef, invites an unlisted value and
|
|
501
|
+
* fails the check. The cues are matched case-insensitively against the
|
|
502
|
+
* raw description (minus any leading [class] marker and any
|
|
503
|
+
* double-quoted substrings).
|
|
504
|
+
*/
|
|
505
|
+
const CLOSED_SET_CUES = Object.freeze([
|
|
506
|
+
'one of',
|
|
507
|
+
'any of',
|
|
508
|
+
'the following',
|
|
509
|
+
'types of',
|
|
510
|
+
'status is',
|
|
511
|
+
]);
|
|
512
|
+
// Word-boundary matchers for each cue so a longer word that happens
|
|
513
|
+
// to contain the cue as a substring (e.g. "status issue" containing
|
|
514
|
+
// "status is") does not trip the gate.
|
|
515
|
+
const CLOSED_SET_CUE_RES = Object.freeze(
|
|
516
|
+
CLOSED_SET_CUES.map((cue) => new RegExp(`\\b${cue.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')}\\b`, 'i')),
|
|
517
|
+
);
|
|
518
|
+
|
|
519
|
+
/**
|
|
520
|
+
* Inline bracketed list regex for the closed-sets check: a square-
|
|
521
|
+
* bracketed group whose contents look like a list of two or more
|
|
522
|
+
* tokens separated by commas, slashes or pipes. A bare `[happy]`
|
|
523
|
+
* class marker is NOT a list (one token, no separator); `[a, b]`,
|
|
524
|
+
* `[a | b | c]` and `[a/b]` are.
|
|
525
|
+
*/
|
|
526
|
+
const INLINE_LIST_RE = /\[[^\]\n]*[,|\/][^\]\n]*\]/;
|
|
527
|
+
|
|
528
|
+
/**
|
|
529
|
+
* ownerRef marker: a cheap presence check for the structured
|
|
530
|
+
* `{ tacId, field: "interfaces[<name>]" }` pointer. True when the AC
|
|
531
|
+
* carries an ownerRef object (consistency-lint and PR 6 both read the
|
|
532
|
+
* same field).
|
|
533
|
+
*
|
|
534
|
+
* @param {unknown} ac
|
|
535
|
+
* @returns {boolean}
|
|
536
|
+
*/
|
|
537
|
+
function acHasOwnerRef(ac) {
|
|
538
|
+
const ref = ac && typeof ac === 'object' ? /** @type {any} */ (ac).ownerRef : null;
|
|
539
|
+
if (!ref || typeof ref !== 'object') return false;
|
|
540
|
+
// R11 (spec section 17, 2026-10-03): an ownerRef may name a TAC
|
|
541
|
+
// (via tacId) OR an ADR (via adrId). Pre-R11 code only recognised
|
|
542
|
+
// tacId; the ADR branch was dropped silently.
|
|
543
|
+
return typeof ref.tacId === 'string' || typeof ref.adrId === 'string';
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
/**
|
|
547
|
+
* Strip double-quoted substrings so a quoted cue inside the AC text
|
|
548
|
+
* does not fire the closed-sets check (shared with D6's negation guard
|
|
549
|
+
* convention). Matches `"..."` with no embedded unescaped double
|
|
550
|
+
* quote; the regex is deliberately permissive. The strip is only for
|
|
551
|
+
* the cue scan; the inline-list scan reads the full description.
|
|
552
|
+
*
|
|
553
|
+
* @param {string} desc
|
|
554
|
+
* @returns {string}
|
|
555
|
+
*/
|
|
556
|
+
function stripQuotedSubstrings(desc) {
|
|
557
|
+
return desc.replace(/"[^"\n]*"/g, '');
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
/**
|
|
561
|
+
* True when the AC description carries an enumeration cue outside a
|
|
562
|
+
* quoted substring, with no inline bracketed list and no ownerRef
|
|
563
|
+
* pointer. Pure.
|
|
564
|
+
*
|
|
565
|
+
* @param {unknown} ac
|
|
566
|
+
* @returns {boolean}
|
|
567
|
+
*/
|
|
568
|
+
function failsClosedSets(ac) {
|
|
569
|
+
const descRaw = ac && typeof ac === 'object' ? /** @type {any} */ (ac).description : null;
|
|
570
|
+
if (typeof descRaw !== 'string' || descRaw.length === 0) return false;
|
|
571
|
+
if (acHasOwnerRef(ac)) return false;
|
|
572
|
+
const descNoClass = descRaw.replace(AC_CLASS_RE, '').trim();
|
|
573
|
+
if (INLINE_LIST_RE.test(descNoClass)) return false;
|
|
574
|
+
const descForCues = stripQuotedSubstrings(descNoClass);
|
|
575
|
+
for (const re of CLOSED_SET_CUE_RES) {
|
|
576
|
+
if (re.test(descForCues)) return true;
|
|
577
|
+
}
|
|
578
|
+
return false;
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
/**
|
|
582
|
+
* Parse an `interfaces[<name>]` field pointer into its interface
|
|
583
|
+
* name. Accepts any non-empty name between the brackets (interface
|
|
584
|
+
* names routinely carry dots, slashes and spaces); returns null for
|
|
585
|
+
* an unparseable pointer.
|
|
586
|
+
*
|
|
587
|
+
* @param {unknown} field
|
|
588
|
+
* @returns {string | null}
|
|
589
|
+
*/
|
|
590
|
+
function parseOwnerRefInterfaceField(field) {
|
|
591
|
+
if (typeof field !== 'string') return null;
|
|
592
|
+
const m = field.match(/^interfaces\[([^\]\n]+)\]$/);
|
|
593
|
+
return m ? m[1] : null;
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
/**
|
|
597
|
+
* R11 field grammar (spec section 17, 2026-10-03). An `ownerRef` or
|
|
598
|
+
* object-form `deliveredBy` `{ tacId | adrId, field }` resolves when
|
|
599
|
+
* `field` names an existing field path on the owning document in
|
|
600
|
+
* bracket grammar:
|
|
601
|
+
*
|
|
602
|
+
* - `interfaces[<name>]` resolves when `doc.interfaces[].name` matches.
|
|
603
|
+
* - `responsibilities[<n>]` resolves when `doc.responsibilities[n]`
|
|
604
|
+
* exists (non-negative integer index, zero-based).
|
|
605
|
+
* - `dependencies[<name>]` resolves when `doc.dependencies[].name` matches.
|
|
606
|
+
* - `alternativesConsidered[<n>]` resolves when the ADR has an
|
|
607
|
+
* alternative at that index.
|
|
608
|
+
* - A bare schema field name (`purpose`, `internalStructure`,
|
|
609
|
+
* `decision`, `name`, `context`, `consequences`, `tradeoffs`,
|
|
610
|
+
* `notes`, `description`, `responsibilities`, `dependencies`,
|
|
611
|
+
* `interfaces`, `alternativesConsidered`) resolves when the
|
|
612
|
+
* document carries a non-empty value under that key.
|
|
613
|
+
*
|
|
614
|
+
* Dotted grammar (`interfaces.name`, `responsibilities.foo`) is NOT
|
|
615
|
+
* accepted: callers of the R11 widening MUST rewrite to bracket
|
|
616
|
+
* grammar first. A path that does not match any arm returns false.
|
|
617
|
+
*
|
|
618
|
+
* `AC-17405-2` is unchanged in effect: `interfaces[loan]` on a TAC
|
|
619
|
+
* carrying an interface named `loan` resolves; `interfaces[missing]`
|
|
620
|
+
* fails.
|
|
621
|
+
*
|
|
622
|
+
* @param {unknown} doc - the owning TAC or ADR document.
|
|
623
|
+
* @param {unknown} field - the ownerRef/deliveredBy field string.
|
|
624
|
+
* @returns {boolean}
|
|
625
|
+
*/
|
|
626
|
+
export function resolveOwnerRefField(doc, field) {
|
|
627
|
+
if (!doc || typeof doc !== 'object') return false;
|
|
628
|
+
if (typeof field !== 'string' || field.length === 0) return false;
|
|
629
|
+
const d = /** @type {any} */ (doc);
|
|
630
|
+
// interfaces[<name>] -- preserved from the 0.29.0 helper.
|
|
631
|
+
const ifaceMatch = field.match(/^interfaces\[([^\]\n]+)\]$/);
|
|
632
|
+
if (ifaceMatch) {
|
|
633
|
+
const name = ifaceMatch[1];
|
|
634
|
+
return Array.isArray(d.interfaces)
|
|
635
|
+
&& d.interfaces.some((iface) => iface && typeof iface === 'object' && iface.name === name);
|
|
636
|
+
}
|
|
637
|
+
// dependencies[<name>] (TAC.dependencies[].name).
|
|
638
|
+
const depMatch = field.match(/^dependencies\[([^\]\n]+)\]$/);
|
|
639
|
+
if (depMatch) {
|
|
640
|
+
const name = depMatch[1];
|
|
641
|
+
return Array.isArray(d.dependencies)
|
|
642
|
+
&& d.dependencies.some((dep) => dep && typeof dep === 'object' && dep.name === name);
|
|
643
|
+
}
|
|
644
|
+
// responsibilities[<n>] (zero-based integer index on the strings array).
|
|
645
|
+
const respMatch = field.match(/^responsibilities\[(\d+)\]$/);
|
|
646
|
+
if (respMatch) {
|
|
647
|
+
const idx = Number(respMatch[1]);
|
|
648
|
+
return Array.isArray(d.responsibilities) && idx < d.responsibilities.length
|
|
649
|
+
&& typeof d.responsibilities[idx] === 'string'
|
|
650
|
+
&& d.responsibilities[idx].length > 0;
|
|
651
|
+
}
|
|
652
|
+
// alternativesConsidered[<n>] (ADR).
|
|
653
|
+
const altMatch = field.match(/^alternativesConsidered\[(\d+)\]$/);
|
|
654
|
+
if (altMatch) {
|
|
655
|
+
const idx = Number(altMatch[1]);
|
|
656
|
+
return Array.isArray(d.alternativesConsidered) && idx < d.alternativesConsidered.length
|
|
657
|
+
&& d.alternativesConsidered[idx] && typeof d.alternativesConsidered[idx] === 'object';
|
|
658
|
+
}
|
|
659
|
+
// Bare schema field name. Must be in the TAC/ADR schema and present
|
|
660
|
+
// and non-empty on the document. The accepted set covers the schema
|
|
661
|
+
// fields the spec names and the extras TAC/ADR carry; a field name
|
|
662
|
+
// outside the set returns false.
|
|
663
|
+
const BARE_FIELDS = new Set([
|
|
664
|
+
// TAC fields.
|
|
665
|
+
'purpose', 'internalStructure', 'tradeoffs', 'notes', 'name',
|
|
666
|
+
'responsibilities', 'interfaces', 'dependencies',
|
|
667
|
+
// ADR fields.
|
|
668
|
+
'decision', 'context', 'consequences', 'title',
|
|
669
|
+
'alternativesConsidered',
|
|
670
|
+
// Common.
|
|
671
|
+
'description',
|
|
672
|
+
]);
|
|
673
|
+
if (!BARE_FIELDS.has(field)) return false;
|
|
674
|
+
const v = d[field];
|
|
675
|
+
if (v == null) return false;
|
|
676
|
+
if (typeof v === 'string') return v.length > 0;
|
|
677
|
+
if (Array.isArray(v)) return v.length > 0;
|
|
678
|
+
if (typeof v === 'object') return Object.keys(v).length > 0;
|
|
679
|
+
return true;
|
|
680
|
+
}
|
|
681
|
+
|
|
316
682
|
/**
|
|
317
683
|
* Parse the leading bracketed class marker on `ac.description`.
|
|
318
684
|
* Returns the class token, or null when no marker is present.
|
|
@@ -417,6 +783,43 @@ function asSet(scope) {
|
|
|
417
783
|
return scope instanceof Set ? scope : new Set(scope ?? []);
|
|
418
784
|
}
|
|
419
785
|
|
|
786
|
+
/**
|
|
787
|
+
* ADR-4138 (DEFINE step 3 rulings R2, R5, R7 2026-10-05 and ruling R13
|
|
788
|
+
* 2026-10-05 PR 292 follow-up): run every tree-wide check for a stage
|
|
789
|
+
* and either return a stage envelope carrying only the tree-wide
|
|
790
|
+
* findings (plus the scope placeholder) folded through `foldState`, or
|
|
791
|
+
* null when every tree-wide check passed, letting the stage proceed to
|
|
792
|
+
* its own scope early-return or full checks list.
|
|
793
|
+
*
|
|
794
|
+
* The helper governs every tree-wide check: `shapes:draftSettled`
|
|
795
|
+
* (R2), `shapes:entityJoin` (R5), `skeleton:standardsCited` (R7),
|
|
796
|
+
* `skeleton:deployAdr` (R13), `crosscut:securityArchitecture` (R13)
|
|
797
|
+
* and `crosscut:operationalConcerns` (R13). Delta-only checks
|
|
798
|
+
* (templateMarkers, pathsResolve, closedSets, ownerRefResolves) are
|
|
799
|
+
* untouched: they stay on the stage's own full-checks path. The
|
|
800
|
+
* ack-at-current-hash fold is delegated to `foldState` so one
|
|
801
|
+
* implementation owns the acknowledgement rule and the failing
|
|
802
|
+
* envelope carries no stale `notApplicable` reason text (the pre-R13
|
|
803
|
+
* copy of the stage's notApplicable message misled the readiness CLI
|
|
804
|
+
* print line, which reads `stage.reason` on every state).
|
|
805
|
+
*
|
|
806
|
+
* @param {string} stage
|
|
807
|
+
* @param {string} gate
|
|
808
|
+
* @param {Array<{name: string, check: object}>} treeWideChecks
|
|
809
|
+
* @param {object} freezeCtx
|
|
810
|
+
* @returns {{ stage: string, gate: string, state: 'failing' | 'acknowledged', checks: object[] } | null}
|
|
811
|
+
*/
|
|
812
|
+
function treeWideFailureEnvelope(stage, gate, treeWideChecks, freezeCtx) {
|
|
813
|
+
const anyFailing = treeWideChecks.some(({ check }) => !check.ok);
|
|
814
|
+
if (!anyFailing) return null;
|
|
815
|
+
const checks = [makeCheck(`stage:${stage}:scope`, 'delta', 0, [])];
|
|
816
|
+
for (const { check } of treeWideChecks) checks.push(check);
|
|
817
|
+
// Delegate to foldState: it owns the warn-with-ack fold rule
|
|
818
|
+
// (ADR-4122). The returned envelope carries { state: 'failing' } or
|
|
819
|
+
// { state: 'acknowledged' } and no reason field.
|
|
820
|
+
return foldState(stage, gate, checks, freezeCtx);
|
|
821
|
+
}
|
|
822
|
+
|
|
420
823
|
// ---------------------------------------------------------------------------
|
|
421
824
|
// D1 -- Brief intake and ledger (blocking in 0.29.0).
|
|
422
825
|
// ---------------------------------------------------------------------------
|
|
@@ -435,6 +838,11 @@ function asSet(scope) {
|
|
|
435
838
|
* @property {{ skipReviewFor?: string } | undefined} profile parsed profile switches (light shape)
|
|
436
839
|
* @property {string | null | undefined} currentTreeHash for warn-with-ack acknowledgement match
|
|
437
840
|
* @property {Array<{ state: string }> | undefined} priorStages D8 reads earlier stage states from this
|
|
841
|
+
* @property {Set<string> | undefined} resolvedPaths ADR-4131 (0.30.0 PR 5): set of repo-relative paths the CLI
|
|
842
|
+
* already resolved on disk; `shapes:pathsResolve` reads this to decide
|
|
843
|
+
* whether a `path:` token on an interface description resolves. Empty or
|
|
844
|
+
* undefined means no path is known-resolved, so every candidate token
|
|
845
|
+
* fails unless the interface description carries `authoredAt: D3`.
|
|
438
846
|
*/
|
|
439
847
|
|
|
440
848
|
/**
|
|
@@ -521,6 +929,81 @@ export function checkD1Brief(ctx) {
|
|
|
521
929
|
/** Kinds whose resolution D2 checks: capability / constraint / entity / actor / externalSystem / surface. */
|
|
522
930
|
const D2_RESOLVING_KINDS = new Set(['capability', 'constraint', 'entity', 'actor', 'externalSystem', 'surface']);
|
|
523
931
|
|
|
932
|
+
/**
|
|
933
|
+
* Compute the `skeleton:deployAdr` check (engineer, tree-wide). Pure.
|
|
934
|
+
* Ruling R13 2026-10-05 (ADR-4138 extended, PR 292 follow-up): exactly
|
|
935
|
+
* one Deploy target or Deploy deferral ADR exists tree-wide (detected
|
|
936
|
+
* by title prefix per proposal section 11). The check runs ahead of
|
|
937
|
+
* the D2 scope early-return so a narrowed scope that excludes every
|
|
938
|
+
* REQ / PRD / TAD / brief statement still reports a missing (or
|
|
939
|
+
* doubled) Deploy ADR.
|
|
940
|
+
*
|
|
941
|
+
* @param {StageContext} ctx
|
|
942
|
+
* @returns {ReturnType<typeof makeCheck>}
|
|
943
|
+
*/
|
|
944
|
+
function computeDeployAdrCheck(ctx) {
|
|
945
|
+
const tree = ctx.tree;
|
|
946
|
+
const deployAdrs = (tree.adrs ?? []).filter((a) => {
|
|
947
|
+
const t = typeof a?.title === 'string' ? a.title : '';
|
|
948
|
+
return t.startsWith('Deploy target:') || t.startsWith('Deploy deferral:');
|
|
949
|
+
});
|
|
950
|
+
const deployFail = [];
|
|
951
|
+
if (deployAdrs.length === 0) deployFail.push({ id: 'ADR:deploy', why: 'no Deploy target or Deploy deferral ADR found (title-prefix scan)' });
|
|
952
|
+
else if (deployAdrs.length > 1) deployFail.push({ id: 'ADR:deploy', why: `${deployAdrs.length} Deploy ADRs found; expected exactly one` });
|
|
953
|
+
return makeCheck('skeleton:deployAdr', 'tree', 1, deployFail);
|
|
954
|
+
}
|
|
955
|
+
|
|
956
|
+
/**
|
|
957
|
+
* Compute the `skeleton:standardsCited` check (engineer, tree-wide).
|
|
958
|
+
* Pure. Every standards pack registered through `rcf define standards`
|
|
959
|
+
* (manifest.standards[].slug) is cited in a REQ `rationale` or an ADR,
|
|
960
|
+
* or satisfied by a concern-ledger entry keyed `standards:<pack>` whose
|
|
961
|
+
* disposition is `applied` or `waived`. Ruling R8 2026-10-05: both
|
|
962
|
+
* `applied` and `waived` satisfy the check (an `applied` entry means the
|
|
963
|
+
* pack was adopted, which is at least as strong as a citation). Ruling
|
|
964
|
+
* R7 2026-10-05: the check runs tree-wide regardless of the D2 scope
|
|
965
|
+
* early-return, through the shared ADR-4138 helper.
|
|
966
|
+
*
|
|
967
|
+
* @param {StageContext} ctx
|
|
968
|
+
* @returns {ReturnType<typeof makeCheck>}
|
|
969
|
+
*/
|
|
970
|
+
function computeStandardsCitedCheck(ctx) {
|
|
971
|
+
const tree = ctx.tree;
|
|
972
|
+
const standardsList = Array.isArray(tree.manifest?.standards)
|
|
973
|
+
? /** @type {any[]} */ (tree.manifest.standards)
|
|
974
|
+
: [];
|
|
975
|
+
/** @type {Array<{ id: string, why: string }>} */
|
|
976
|
+
const standardsFail = [];
|
|
977
|
+
if (standardsList.length > 0) {
|
|
978
|
+
const reqRationales = (tree.requirements ?? [])
|
|
979
|
+
.map((r) => (typeof r?.rationale === 'string' ? r.rationale : ''))
|
|
980
|
+
.join('\n');
|
|
981
|
+
const adrDocs = (tree.adrs ?? []).map((a) => {
|
|
982
|
+
try { return JSON.stringify(a); } catch { return ''; }
|
|
983
|
+
}).join('\n');
|
|
984
|
+
const concernsBody = /** @type {any} */ (ctx.ledgers?.concerns);
|
|
985
|
+
const concernList = Array.isArray(concernsBody?.concerns) ? concernsBody.concerns : [];
|
|
986
|
+
const satisfierSlugs = new Set();
|
|
987
|
+
for (const entry of concernList) {
|
|
988
|
+
if (!entry || typeof entry.concern !== 'string') continue;
|
|
989
|
+
const disposition = typeof entry.disposition === 'string' ? entry.disposition : null;
|
|
990
|
+
// Ruling R8 2026-10-05: both applied and waived satisfy standardsCited.
|
|
991
|
+
if (disposition !== 'applied' && disposition !== 'waived') continue;
|
|
992
|
+
const m = entry.concern.match(/^standards:(.+)$/);
|
|
993
|
+
if (m) satisfierSlugs.add(m[1]);
|
|
994
|
+
}
|
|
995
|
+
for (const pack of standardsList) {
|
|
996
|
+
const slug = typeof pack?.slug === 'string' ? pack.slug : null;
|
|
997
|
+
if (!slug) continue;
|
|
998
|
+
if (satisfierSlugs.has(slug)) continue;
|
|
999
|
+
if (reqRationales.includes(slug)) continue;
|
|
1000
|
+
if (adrDocs.includes(slug)) continue;
|
|
1001
|
+
standardsFail.push({ id: `standards:${slug}`, why: 'uncited, unapplied and unwaived' });
|
|
1002
|
+
}
|
|
1003
|
+
}
|
|
1004
|
+
return makeCheck('skeleton:standardsCited', 'tree', Math.max(standardsList.length, 1), standardsFail);
|
|
1005
|
+
}
|
|
1006
|
+
|
|
524
1007
|
/**
|
|
525
1008
|
* D2 -- Requirements and architecture skeleton.
|
|
526
1009
|
*
|
|
@@ -539,7 +1022,25 @@ export function checkD2Skeleton(ctx) {
|
|
|
539
1022
|
const prdInScope = tree.prd && scope.has(tree.prd.prdId ?? '');
|
|
540
1023
|
const tadInScope = tree.tad && scope.has(tree.tad.tadId ?? '');
|
|
541
1024
|
|
|
1025
|
+
// Ruling R7 2026-10-05 (ADR-4138) and R13 2026-10-05 (ADR-4138
|
|
1026
|
+
// extended, PR 292 follow-up): skeleton:standardsCited and
|
|
1027
|
+
// skeleton:deployAdr are tree-wide checks; evaluate them before any
|
|
1028
|
+
// scope early-return so a narrowed D2 scope that excludes every
|
|
1029
|
+
// REQ/PRD/TAD/brief statement still reports an uncited pack or a
|
|
1030
|
+
// missing Deploy ADR.
|
|
1031
|
+
const standardsCheck = computeStandardsCitedCheck(ctx);
|
|
1032
|
+
const deployAdrCheck = computeDeployAdrCheck(ctx);
|
|
1033
|
+
|
|
542
1034
|
if (resolvingStmts.length === 0 && reqInScope.length === 0 && !prdInScope && !tadInScope) {
|
|
1035
|
+
const treeWideFailure = treeWideFailureEnvelope(
|
|
1036
|
+
'D2', gate,
|
|
1037
|
+
[
|
|
1038
|
+
{ name: 'skeleton:standardsCited', check: standardsCheck },
|
|
1039
|
+
{ name: 'skeleton:deployAdr', check: deployAdrCheck },
|
|
1040
|
+
],
|
|
1041
|
+
{ currentTreeHash: ctx.currentTreeHash ?? null, freezeGates: /** @type {any} */ (ctx.freeze?.gates) },
|
|
1042
|
+
);
|
|
1043
|
+
if (treeWideFailure) return treeWideFailure;
|
|
543
1044
|
return notApplicable('D2', gate, 'no resolving brief statements and no REQ / PRD / TAD in scope');
|
|
544
1045
|
}
|
|
545
1046
|
|
|
@@ -611,15 +1112,17 @@ export function checkD2Skeleton(ctx) {
|
|
|
611
1112
|
checks.push(makeCheck('skeleton:tadPersistence', 'tree', persistenceReq ? 2 : 0, tadFail));
|
|
612
1113
|
|
|
613
1114
|
// Check 4: exactly one deploy or deferral ADR tree-wide. Cheap
|
|
614
|
-
// detection by title prefix (proposal §11 assumption).
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
1115
|
+
// detection by title prefix (proposal §11 assumption). Ruling R13
|
|
1116
|
+
// 2026-10-05: tree-wide by definition; computed by
|
|
1117
|
+
// computeDeployAdrCheck so the same check is reused ahead of the
|
|
1118
|
+
// scope early-return (ADR-4138 extended).
|
|
1119
|
+
checks.push(deployAdrCheck);
|
|
1120
|
+
|
|
1121
|
+
// Check 5 (0.30.0 PR 6, ruling R7+R8 2026-10-05): skeleton:standardsCited
|
|
1122
|
+
// (engineer, over tree). Computed by `computeStandardsCitedCheck` so the
|
|
1123
|
+
// same check runs ahead of the scope early-return (R7) and so the R8
|
|
1124
|
+
// behaviour (applied | waived | cited all satisfy) lives in one place.
|
|
1125
|
+
checks.push(standardsCheck);
|
|
623
1126
|
|
|
624
1127
|
return foldState('D2', gate, checks, {
|
|
625
1128
|
currentTreeHash: ctx.currentTreeHash ?? null,
|
|
@@ -634,6 +1137,98 @@ export function checkD2Skeleton(ctx) {
|
|
|
634
1137
|
/** Set form of INTERFACE_KINDS for O(1) checks. */
|
|
635
1138
|
const INTERFACE_KINDS_SET = new Set(INTERFACE_KINDS);
|
|
636
1139
|
|
|
1140
|
+
/**
|
|
1141
|
+
* Compute the `shapes:draftSettled` check (engineer, tree-wide). Pure.
|
|
1142
|
+
* Ruling R2 2026-10-05 (ADR-4138): a `[draft]` marker on any TAC
|
|
1143
|
+
* purpose, any interface description or any coreEntities[].description
|
|
1144
|
+
* fails the check regardless of the D3 scope's own early-return. The
|
|
1145
|
+
* three id forms are `<tacId>`, `<tacId>:<name>` and `TAD.entity:<name>`.
|
|
1146
|
+
*
|
|
1147
|
+
* @param {StageContext} ctx
|
|
1148
|
+
* @returns {ReturnType<typeof makeCheck>}
|
|
1149
|
+
*/
|
|
1150
|
+
function computeDraftSettledCheck(ctx) {
|
|
1151
|
+
const tree = ctx.tree;
|
|
1152
|
+
const tacs = tree.tacs ?? [];
|
|
1153
|
+
const coreEntities = Array.isArray(tree.tad?.dataArchitecture?.coreEntities)
|
|
1154
|
+
? /** @type {any[]} */ (tree.tad.dataArchitecture.coreEntities)
|
|
1155
|
+
: [];
|
|
1156
|
+
/** @type {Array<{ id: string, why: string }>} */
|
|
1157
|
+
const draftFindings = [];
|
|
1158
|
+
let totalInterfaces = 0;
|
|
1159
|
+
for (const tac of tacs) {
|
|
1160
|
+
if (parseTacPurposeDraft(tac)) {
|
|
1161
|
+
draftFindings.push({ id: tac.tacId, why: 'draft TAC purpose pre-populated at L1, not yet settled' });
|
|
1162
|
+
}
|
|
1163
|
+
for (const iface of tac.interfaces ?? []) {
|
|
1164
|
+
totalInterfaces += 1;
|
|
1165
|
+
if (parseInterfaceDraft(iface)) {
|
|
1166
|
+
draftFindings.push({ id: `${tac.tacId}:${iface?.name ?? '(unnamed)'}`, why: 'draft interface pre-populated at L1, not yet settled' });
|
|
1167
|
+
}
|
|
1168
|
+
}
|
|
1169
|
+
}
|
|
1170
|
+
for (const entity of coreEntities) {
|
|
1171
|
+
if (parseCoreEntityDraft(entity)) {
|
|
1172
|
+
draftFindings.push({ id: `TAD.entity:${entity?.name ?? '(unnamed)'}`, why: 'draft core entity pre-populated at L1, not yet settled' });
|
|
1173
|
+
}
|
|
1174
|
+
}
|
|
1175
|
+
const totalDraftHomes = tacs.length + totalInterfaces + coreEntities.length;
|
|
1176
|
+
return makeCheck('shapes:draftSettled', 'tree', Math.max(totalDraftHomes, 1), draftFindings);
|
|
1177
|
+
}
|
|
1178
|
+
|
|
1179
|
+
/**
|
|
1180
|
+
* Compute the `shapes:entityJoin` check (engineer, tree-wide). Pure.
|
|
1181
|
+
* Ruling R5 2026-10-05 (ADR-4138): every entry in
|
|
1182
|
+
* `TAD.dataArchitecture.coreEntities` must be named by exactly one
|
|
1183
|
+
* `recordShape` across the whole tree (matching on the recordShape's
|
|
1184
|
+
* `name` field or an `entity:` line in its description, with a
|
|
1185
|
+
* `[draft]` prefix stripped before the scan). The check runs ahead of
|
|
1186
|
+
* the D3 scope early-return so a narrowed scope that excludes every
|
|
1187
|
+
* recordShape still reports an unjoined entity.
|
|
1188
|
+
*
|
|
1189
|
+
* @param {StageContext} ctx
|
|
1190
|
+
* @returns {ReturnType<typeof makeCheck>}
|
|
1191
|
+
*/
|
|
1192
|
+
function computeEntityJoinCheck(ctx) {
|
|
1193
|
+
const tree = ctx.tree;
|
|
1194
|
+
const coreEntities = Array.isArray(tree.tad?.dataArchitecture?.coreEntities)
|
|
1195
|
+
? /** @type {any[]} */ (tree.tad.dataArchitecture.coreEntities)
|
|
1196
|
+
: [];
|
|
1197
|
+
/** @type {Array<{ id: string, why: string }>} */
|
|
1198
|
+
const joinFindings = [];
|
|
1199
|
+
const recordShapesByEntity = new Map();
|
|
1200
|
+
for (const tac of tree.tacs ?? []) {
|
|
1201
|
+
for (const iface of tac.interfaces ?? []) {
|
|
1202
|
+
if (iface?.kind !== 'recordShape') continue;
|
|
1203
|
+
const ownerLabel = `${tac.tacId}:${iface?.name ?? '(unnamed)'}`;
|
|
1204
|
+
const names = new Set();
|
|
1205
|
+
if (typeof iface?.name === 'string') names.add(iface.name);
|
|
1206
|
+
const desc = typeof iface?.description === 'string' ? stripDraftPrefix(iface.description) : '';
|
|
1207
|
+
const entityRe = /(^|\n)\s*(?:[-*]\s*)?entity\s*[:=]\s*["'`]?([A-Za-z_][A-Za-z0-9_]*)/g;
|
|
1208
|
+
let em;
|
|
1209
|
+
while ((em = entityRe.exec(desc)) !== null) {
|
|
1210
|
+
if (em[2]) names.add(em[2]);
|
|
1211
|
+
}
|
|
1212
|
+
for (const name of names) {
|
|
1213
|
+
const owners = recordShapesByEntity.get(name) ?? [];
|
|
1214
|
+
owners.push(ownerLabel);
|
|
1215
|
+
recordShapesByEntity.set(name, owners);
|
|
1216
|
+
}
|
|
1217
|
+
}
|
|
1218
|
+
}
|
|
1219
|
+
for (const entity of coreEntities) {
|
|
1220
|
+
const name = typeof entity?.name === 'string' ? entity.name : null;
|
|
1221
|
+
if (!name) continue;
|
|
1222
|
+
const owners = recordShapesByEntity.get(name) ?? [];
|
|
1223
|
+
if (owners.length === 0) {
|
|
1224
|
+
joinFindings.push({ id: `TAD.entity:${name}`, why: 'no record shape' });
|
|
1225
|
+
} else if (owners.length > 1) {
|
|
1226
|
+
joinFindings.push({ id: `TAD.entity:${name}`, why: `${owners.length} record shapes` });
|
|
1227
|
+
}
|
|
1228
|
+
}
|
|
1229
|
+
return makeCheck('shapes:entityJoin', 'tree', coreEntities.length, joinFindings);
|
|
1230
|
+
}
|
|
1231
|
+
|
|
637
1232
|
/**
|
|
638
1233
|
* D3 -- Interface contracts and shapes. 0.29.0 runs the cheap
|
|
639
1234
|
* presence, closed-vocabulary and draft-marker checks
|
|
@@ -670,10 +1265,30 @@ export function checkD3Shapes(ctx) {
|
|
|
670
1265
|
const coreEntities = Array.isArray(tree.tad?.dataArchitecture?.coreEntities)
|
|
671
1266
|
? /** @type {any[]} */ (tree.tad.dataArchitecture.coreEntities)
|
|
672
1267
|
: [];
|
|
673
|
-
const draftEntities = coreEntities.filter(parseCoreEntityDraft);
|
|
674
1268
|
|
|
675
|
-
|
|
676
|
-
|
|
1269
|
+
// Ruling R2+R5 2026-10-05 (ADR-4138): shapes:draftSettled and
|
|
1270
|
+
// shapes:entityJoin are tree-wide checks; evaluate them before any
|
|
1271
|
+
// scope early-return so a narrowed D3 scope that excludes every TAC
|
|
1272
|
+
// and shaped REQ still reports a [draft] anywhere in the tree and an
|
|
1273
|
+
// unjoined core entity.
|
|
1274
|
+
const draftCheck = computeDraftSettledCheck(ctx);
|
|
1275
|
+
const entityJoinCheck = computeEntityJoinCheck(ctx);
|
|
1276
|
+
|
|
1277
|
+
if (tacsInScope.length === 0 && shapedReqInScope.length === 0) {
|
|
1278
|
+
const treeWideFailure = treeWideFailureEnvelope(
|
|
1279
|
+
'D3', gate,
|
|
1280
|
+
[
|
|
1281
|
+
{ name: 'shapes:draftSettled', check: draftCheck },
|
|
1282
|
+
{ name: 'shapes:entityJoin', check: entityJoinCheck },
|
|
1283
|
+
],
|
|
1284
|
+
{ currentTreeHash: ctx.currentTreeHash ?? null, freezeGates: /** @type {any} */ (ctx.freeze?.gates) },
|
|
1285
|
+
);
|
|
1286
|
+
if (treeWideFailure) return treeWideFailure;
|
|
1287
|
+
// Ruling R2 2026-10-05: `[draft]` is tree-wide (not a D3 scope
|
|
1288
|
+
// input), so the pre-R2 reason trailer "and no [draft] core entity
|
|
1289
|
+
// in scope" was stale -- the applicability condition is just the
|
|
1290
|
+
// two local-scope sets.
|
|
1291
|
+
return notApplicable('D3', gate, 'no TAC and no shaped REQ (httpApi/persistence/auth) in scope');
|
|
677
1292
|
}
|
|
678
1293
|
|
|
679
1294
|
const checks = [];
|
|
@@ -687,40 +1302,90 @@ export function checkD3Shapes(ctx) {
|
|
|
687
1302
|
noIfaceTacs.map((t) => ({ id: t.tacId, why: 'no interfaces authored' })),
|
|
688
1303
|
));
|
|
689
1304
|
|
|
690
|
-
// Check 2: every interface kind is in the closed vocabulary
|
|
691
|
-
//
|
|
692
|
-
// carries the `[draft]` marker. A draft shape is entry material
|
|
693
|
-
// the agent pre-populates after L1; the engineer removes the
|
|
694
|
-
// marker when the shape is settled. `tacHasInterface` and
|
|
695
|
-
// `kindVocabulary` apply equally to drafts.
|
|
1305
|
+
// Check 2: every interface kind is in the closed vocabulary (over
|
|
1306
|
+
// delta; drafts included).
|
|
696
1307
|
let totalInterfaces = 0;
|
|
697
1308
|
const badKinds = [];
|
|
698
|
-
const draftFindings = [];
|
|
699
1309
|
for (const tac of tacsInScope) {
|
|
700
|
-
if (parseTacPurposeDraft(tac)) {
|
|
701
|
-
draftFindings.push({ id: tac.tacId, why: 'draft TAC purpose pre-populated at L1, not yet settled' });
|
|
702
|
-
}
|
|
703
1310
|
for (const iface of tac.interfaces ?? []) {
|
|
704
1311
|
totalInterfaces += 1;
|
|
705
1312
|
const kind = iface?.kind;
|
|
706
1313
|
if (typeof kind !== 'string' || !INTERFACE_KINDS_SET.has(kind)) {
|
|
707
1314
|
badKinds.push({ id: `${tac.tacId}:${iface?.name ?? '(unnamed)'}`, why: `unknown interface kind ${JSON.stringify(kind)}` });
|
|
708
1315
|
}
|
|
709
|
-
|
|
710
|
-
|
|
1316
|
+
}
|
|
1317
|
+
}
|
|
1318
|
+
checks.push(makeCheck('shapes:kindVocabulary', 'delta', totalInterfaces, badKinds));
|
|
1319
|
+
|
|
1320
|
+
// Check 3: shapes:draftSettled. Ruling R2 2026-10-05: tree-wide (a
|
|
1321
|
+
// [draft] anywhere is unfinished work). Computed by
|
|
1322
|
+
// computeDraftSettledCheck so the same check is reused ahead of the
|
|
1323
|
+
// scope early-return.
|
|
1324
|
+
checks.push(draftCheck);
|
|
1325
|
+
|
|
1326
|
+
// ADR-4131 (0.30.0 PR 5): three D3 bite checks follow.
|
|
1327
|
+
// Check 4: shapes:templateMarkers (engineer, over delta). For every
|
|
1328
|
+
// interface on an in-scope TAC, parseInterfaceTemplate reports which
|
|
1329
|
+
// per-kind markers are missing from the description; a draft marker
|
|
1330
|
+
// is stripped before the scan so a [draft] recordShape without
|
|
1331
|
+
// `fields:` fails exactly as a settled one. An interface whose kind
|
|
1332
|
+
// is outside INTERFACE_KINDS is left to shapes:kindVocabulary (the
|
|
1333
|
+
// marker map returns `{missing: []}` for an unknown kind so this
|
|
1334
|
+
// check does not double-report the vocabulary miss).
|
|
1335
|
+
/** @type {Array<{ id: string, why: string }>} */
|
|
1336
|
+
const templateFindings = [];
|
|
1337
|
+
for (const tac of tacsInScope) {
|
|
1338
|
+
for (const iface of tac.interfaces ?? []) {
|
|
1339
|
+
const result = parseInterfaceTemplate(iface);
|
|
1340
|
+
if (!result.kind) continue;
|
|
1341
|
+
for (const marker of result.missing) {
|
|
1342
|
+
templateFindings.push({
|
|
1343
|
+
id: `${tac.tacId}:${iface?.name ?? '(unnamed)'}`,
|
|
1344
|
+
why: `missing marker ${marker}`,
|
|
1345
|
+
});
|
|
711
1346
|
}
|
|
712
1347
|
}
|
|
713
1348
|
}
|
|
714
|
-
|
|
715
|
-
|
|
1349
|
+
checks.push(makeCheck('shapes:templateMarkers', 'delta', totalInterfaces, templateFindings));
|
|
1350
|
+
|
|
1351
|
+
// Check 5: shapes:entityJoin. Ruling R5 2026-10-05: tree-wide by
|
|
1352
|
+
// definition. Computed by computeEntityJoinCheck so the same check
|
|
1353
|
+
// is reused ahead of the scope early-return (ADR-4138).
|
|
1354
|
+
checks.push(entityJoinCheck);
|
|
1355
|
+
|
|
1356
|
+
// Check 6: shapes:pathsResolve (engineer, over delta). Any path:
|
|
1357
|
+
// token on an in-scope interface description must either resolve
|
|
1358
|
+
// against `resolvedPaths` (the CLI's on-disk pass) or the
|
|
1359
|
+
// description must carry an `authoredAt: D3` marker (the engineer
|
|
1360
|
+
// owns the path even when the file is yet to land). The marker is
|
|
1361
|
+
// a token in the description text (`authoredAt: D3` or
|
|
1362
|
+
// `authoredAt = D3`), not a separate schema field; the TAC schema
|
|
1363
|
+
// keeps interfaces to { name, kind, description }. Over delta,
|
|
1364
|
+
// one failing entry per unresolved (tacId:name, path) pair.
|
|
1365
|
+
const resolvedPaths = ctx.resolvedPaths instanceof Set ? ctx.resolvedPaths : new Set();
|
|
1366
|
+
/** @type {Array<{ id: string, why: string }>} */
|
|
1367
|
+
const pathFindings = [];
|
|
1368
|
+
let totalPathChecks = 0;
|
|
1369
|
+
for (const tac of tacsInScope) {
|
|
1370
|
+
for (const iface of tac.interfaces ?? []) {
|
|
1371
|
+
const desc = typeof iface?.description === 'string' ? iface.description : '';
|
|
1372
|
+
const tokens = extractInterfacePathTokens(desc);
|
|
1373
|
+
if (tokens.length === 0) continue;
|
|
1374
|
+
const authoredAtD3 = /\bauthoredAt\s*[:=]\s*["'`]?D3\b/.test(stripDraftPrefix(desc));
|
|
1375
|
+
for (const token of tokens) {
|
|
1376
|
+
totalPathChecks += 1;
|
|
1377
|
+
if (authoredAtD3) continue;
|
|
1378
|
+
if (resolvedPaths.has(token)) continue;
|
|
1379
|
+
pathFindings.push({
|
|
1380
|
+
id: `${tac.tacId}:${iface?.name ?? '(unnamed)'}`,
|
|
1381
|
+
why: `path does not resolve: ${token}`,
|
|
1382
|
+
});
|
|
1383
|
+
}
|
|
1384
|
+
}
|
|
716
1385
|
}
|
|
717
|
-
//
|
|
718
|
-
//
|
|
719
|
-
|
|
720
|
-
// coreEntities list.
|
|
721
|
-
const totalDraftHomes = tacsInScope.length + totalInterfaces + coreEntities.length;
|
|
722
|
-
checks.push(makeCheck('shapes:kindVocabulary', 'delta', totalInterfaces, badKinds));
|
|
723
|
-
checks.push(makeCheck('shapes:draftSettled', 'delta', totalDraftHomes, draftFindings));
|
|
1386
|
+
// Keep total >= 1 so the chip prints a sensible ratio when no
|
|
1387
|
+
// interface in scope names a path.
|
|
1388
|
+
checks.push(makeCheck('shapes:pathsResolve', 'delta', Math.max(totalPathChecks, 1), pathFindings));
|
|
724
1389
|
|
|
725
1390
|
return foldState('D3', gate, checks, {
|
|
726
1391
|
currentTreeHash: ctx.currentTreeHash ?? null,
|
|
@@ -801,6 +1466,72 @@ export function checkD4Stories(ctx) {
|
|
|
801
1466
|
}
|
|
802
1467
|
checks.push(makeCheck('stories:usFloors', 'delta', usInScope.length, usFail));
|
|
803
1468
|
|
|
1469
|
+
// Check 3 (0.30.0 PR 6): stories:closedSets (engineer, over delta).
|
|
1470
|
+
// Every AC on a US in scope whose description contains an enumeration
|
|
1471
|
+
// cue (one of | any of | the following | types of | status is)
|
|
1472
|
+
// without an inline bracketed list of two or more tokens AND without
|
|
1473
|
+
// an ownerRef fails. The quoted-cue guard strips `"..."` substrings
|
|
1474
|
+
// before the cue scan so prose that quotes a cue does not fire the
|
|
1475
|
+
// check.
|
|
1476
|
+
/** @type {Array<{ id: string, why: string }>} */
|
|
1477
|
+
const closedSetFindings = [];
|
|
1478
|
+
let totalClosedSetAcs = 0;
|
|
1479
|
+
for (const us of usInScope) {
|
|
1480
|
+
const acs = Array.isArray(us.acceptanceCriteria) ? us.acceptanceCriteria : [];
|
|
1481
|
+
for (const ac of acs) {
|
|
1482
|
+
if (typeof ac?.description !== 'string' || ac.description.length === 0) continue;
|
|
1483
|
+
totalClosedSetAcs += 1;
|
|
1484
|
+
if (failsClosedSets(ac)) {
|
|
1485
|
+
closedSetFindings.push({
|
|
1486
|
+
id: ac.id ?? us.usId,
|
|
1487
|
+
why: 'enumeration cue without a closed set',
|
|
1488
|
+
});
|
|
1489
|
+
}
|
|
1490
|
+
}
|
|
1491
|
+
}
|
|
1492
|
+
checks.push(makeCheck('stories:closedSets', 'delta', totalClosedSetAcs, closedSetFindings));
|
|
1493
|
+
|
|
1494
|
+
// Check 4 (0.30.0 PR 6): stories:ownerRefResolves (engineer, over
|
|
1495
|
+
// delta plus tree for ownerRef targets). Every AC on a US in scope
|
|
1496
|
+
// whose ownerRef is set must point to an interface by name on the
|
|
1497
|
+
// named TAC. Ids `<acId>:<field>`; why 'ownerRef does not resolve'.
|
|
1498
|
+
/** @type {Array<{ id: string, why: string }>} */
|
|
1499
|
+
const ownerRefFindings = [];
|
|
1500
|
+
let totalOwnerRefAcs = 0;
|
|
1501
|
+
// R11 (spec section 17, 2026-10-03): the ownerRef field grammar
|
|
1502
|
+
// widens beyond `interfaces[<name>]` to every bracket-grammar path
|
|
1503
|
+
// that names an existing field on the owning TAC or ADR. The owner
|
|
1504
|
+
// may now be a TAC (via tacId) or an ADR (via adrId); the resolver
|
|
1505
|
+
// handles the bracket forms (`interfaces[<name>]`,
|
|
1506
|
+
// `responsibilities[<n>]`, `dependencies[<name>]`,
|
|
1507
|
+
// `alternativesConsidered[<n>]`) and bare schema fields (`purpose`,
|
|
1508
|
+
// `internalStructure`, `decision`, etc.). A path that does not
|
|
1509
|
+
// match any arm still fails. AC-17405-2 is unchanged in effect.
|
|
1510
|
+
for (const us of usInScope) {
|
|
1511
|
+
const acs = Array.isArray(us.acceptanceCriteria) ? us.acceptanceCriteria : [];
|
|
1512
|
+
for (const ac of acs) {
|
|
1513
|
+
if (!acHasOwnerRef(ac)) continue;
|
|
1514
|
+
totalOwnerRefAcs += 1;
|
|
1515
|
+
const ref = /** @type {any} */ (ac).ownerRef;
|
|
1516
|
+
let owner = null;
|
|
1517
|
+
if (typeof ref.tacId === 'string') {
|
|
1518
|
+
owner = (tree.tacs ?? []).find((t) => t?.tacId === ref.tacId) ?? null;
|
|
1519
|
+
} else if (typeof ref.adrId === 'string') {
|
|
1520
|
+
owner = (tree.adrs ?? []).find((a) => a?.adrId === ref.adrId) ?? null;
|
|
1521
|
+
}
|
|
1522
|
+
const resolves = !!(owner && resolveOwnerRefField(owner, ref.field));
|
|
1523
|
+
if (!resolves) {
|
|
1524
|
+
ownerRefFindings.push({
|
|
1525
|
+
id: `${ac.id ?? us.usId}:${ref.field ?? '(no field)'}`,
|
|
1526
|
+
why: 'ownerRef does not resolve',
|
|
1527
|
+
});
|
|
1528
|
+
}
|
|
1529
|
+
}
|
|
1530
|
+
}
|
|
1531
|
+
// Keep total >= 1 so the chip prints a sensible ratio when no AC in
|
|
1532
|
+
// scope carries an ownerRef.
|
|
1533
|
+
checks.push(makeCheck('stories:ownerRefResolves', 'delta', Math.max(totalOwnerRefAcs, 1), ownerRefFindings));
|
|
1534
|
+
|
|
804
1535
|
return foldState('D4', gate, checks, {
|
|
805
1536
|
currentTreeHash: ctx.currentTreeHash ?? null,
|
|
806
1537
|
freezeGates: /** @type {any} */ (ctx.freeze?.gates),
|
|
@@ -812,27 +1543,17 @@ export function checkD4Stories(ctx) {
|
|
|
812
1543
|
// ---------------------------------------------------------------------------
|
|
813
1544
|
|
|
814
1545
|
/**
|
|
815
|
-
*
|
|
816
|
-
*
|
|
817
|
-
*
|
|
818
|
-
*
|
|
819
|
-
*
|
|
1546
|
+
* Compute the `crosscut:securityArchitecture` check (engineer,
|
|
1547
|
+
* tree-wide). Pure. Ruling R13 2026-10-05 (ADR-4138 extended): if the
|
|
1548
|
+
* tree carries any REQ with shape `auth` or `httpApi`, TAD.securityArchitecture
|
|
1549
|
+
* must be non-empty. Runs ahead of the D5 scope early-return so a
|
|
1550
|
+
* narrowed scope that excludes the auth REQ still reports the finding.
|
|
820
1551
|
*
|
|
821
1552
|
* @param {StageContext} ctx
|
|
1553
|
+
* @returns {ReturnType<typeof makeCheck>}
|
|
822
1554
|
*/
|
|
823
|
-
|
|
824
|
-
const gate = STAGE_GATES.D5;
|
|
825
|
-
const scope = asSet(ctx.scope);
|
|
1555
|
+
function computeSecurityArchitectureCheck(ctx) {
|
|
826
1556
|
const tree = ctx.tree;
|
|
827
|
-
const reqInScope = (tree.requirements ?? []).filter((r) => scope.has(r.reqId));
|
|
828
|
-
|
|
829
|
-
if (reqInScope.length === 0) {
|
|
830
|
-
return notApplicable('D5', gate, 'no REQ in scope');
|
|
831
|
-
}
|
|
832
|
-
|
|
833
|
-
const checks = [];
|
|
834
|
-
|
|
835
|
-
// Check 1: TAD.securityArchitecture non-empty when any REQ carries shape 'auth' or 'httpApi'.
|
|
836
1557
|
const authApi = (tree.requirements ?? []).some((r) => {
|
|
837
1558
|
const s = r.shapeClassification?.shapes ?? [];
|
|
838
1559
|
return s.includes('auth') || s.includes('httpApi');
|
|
@@ -845,11 +1566,22 @@ export function checkD5Crosscut(ctx) {
|
|
|
845
1566
|
secFail.push({ id: 'TAD.securityArchitecture', why: 'empty while auth or httpApi REQ exists' });
|
|
846
1567
|
}
|
|
847
1568
|
}
|
|
848
|
-
|
|
1569
|
+
return makeCheck('crosscut:securityArchitecture', 'tree', authApi ? 1 : 0, secFail);
|
|
1570
|
+
}
|
|
849
1571
|
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
1572
|
+
/**
|
|
1573
|
+
* Compute the `crosscut:operationalConcerns` check (engineer,
|
|
1574
|
+
* tree-wide). Pure. Ruling R13 2026-10-05 (ADR-4138 extended): if any
|
|
1575
|
+
* AC description tree-wide carries the `[deployed]` marker, then
|
|
1576
|
+
* TAD.operationalConcerns must be non-empty. Runs ahead of the D5
|
|
1577
|
+
* scope early-return.
|
|
1578
|
+
*
|
|
1579
|
+
* @param {StageContext} ctx
|
|
1580
|
+
* @returns {ReturnType<typeof makeCheck>}
|
|
1581
|
+
*/
|
|
1582
|
+
function computeOperationalConcernsCheck(ctx) {
|
|
1583
|
+
const tree = ctx.tree;
|
|
1584
|
+
const tad = /** @type {any} */ (tree.tad ?? {});
|
|
853
1585
|
const hasDeployedAc = (tree.userStories ?? []).some((us) => (us.acceptanceCriteria ?? []).some((ac) => typeof ac?.description === 'string' && ac.description.includes('[deployed]')));
|
|
854
1586
|
const opFail = [];
|
|
855
1587
|
if (hasDeployedAc) {
|
|
@@ -858,7 +1590,59 @@ export function checkD5Crosscut(ctx) {
|
|
|
858
1590
|
opFail.push({ id: 'TAD.operationalConcerns', why: 'empty while deployed-scope AC exists' });
|
|
859
1591
|
}
|
|
860
1592
|
}
|
|
861
|
-
|
|
1593
|
+
return makeCheck('crosscut:operationalConcerns', 'tree', hasDeployedAc ? 1 : 0, opFail);
|
|
1594
|
+
}
|
|
1595
|
+
|
|
1596
|
+
/**
|
|
1597
|
+
* D5 -- Cross-cutting weave. 0.29.0 runs cheap presence checks.
|
|
1598
|
+
*
|
|
1599
|
+
* SEAM 0.30: full concern catalogue with per-shape applicability;
|
|
1600
|
+
* per-(concern, REQ) pair enumeration; TAD securityArchitecture and
|
|
1601
|
+
* operationalConcerns structure checks beyond presence.
|
|
1602
|
+
*
|
|
1603
|
+
* @param {StageContext} ctx
|
|
1604
|
+
*/
|
|
1605
|
+
export function checkD5Crosscut(ctx) {
|
|
1606
|
+
const gate = STAGE_GATES.D5;
|
|
1607
|
+
const scope = asSet(ctx.scope);
|
|
1608
|
+
const tree = ctx.tree;
|
|
1609
|
+
const reqInScope = (tree.requirements ?? []).filter((r) => scope.has(r.reqId));
|
|
1610
|
+
|
|
1611
|
+
// Ruling R13 2026-10-05 (ADR-4138 extended, PR 292 follow-up):
|
|
1612
|
+
// crosscut:securityArchitecture and crosscut:operationalConcerns are
|
|
1613
|
+
// tree-wide checks; evaluate them before any scope early-return so a
|
|
1614
|
+
// narrowed D5 scope that excludes the triggering REQ or AC still
|
|
1615
|
+
// reports an empty TAD.securityArchitecture / TAD.operationalConcerns.
|
|
1616
|
+
const securityCheck = computeSecurityArchitectureCheck(ctx);
|
|
1617
|
+
const operationalCheck = computeOperationalConcernsCheck(ctx);
|
|
1618
|
+
|
|
1619
|
+
if (reqInScope.length === 0) {
|
|
1620
|
+
const treeWideFailure = treeWideFailureEnvelope(
|
|
1621
|
+
'D5', gate,
|
|
1622
|
+
[
|
|
1623
|
+
{ name: 'crosscut:securityArchitecture', check: securityCheck },
|
|
1624
|
+
{ name: 'crosscut:operationalConcerns', check: operationalCheck },
|
|
1625
|
+
],
|
|
1626
|
+
{ currentTreeHash: ctx.currentTreeHash ?? null, freezeGates: /** @type {any} */ (ctx.freeze?.gates) },
|
|
1627
|
+
);
|
|
1628
|
+
if (treeWideFailure) return treeWideFailure;
|
|
1629
|
+
return notApplicable('D5', gate, 'no REQ in scope');
|
|
1630
|
+
}
|
|
1631
|
+
|
|
1632
|
+
const checks = [];
|
|
1633
|
+
|
|
1634
|
+
// Check 1: TAD.securityArchitecture non-empty when any REQ carries
|
|
1635
|
+
// shape 'auth' or 'httpApi'. Ruling R13 2026-10-05: tree-wide;
|
|
1636
|
+
// computed by computeSecurityArchitectureCheck so the same check is
|
|
1637
|
+
// reused ahead of the scope early-return (ADR-4138 extended).
|
|
1638
|
+
checks.push(securityCheck);
|
|
1639
|
+
|
|
1640
|
+
// Check 2: TAD.operationalConcerns non-empty when any AC description
|
|
1641
|
+
// carries the '[deployed]' marker (a cheap presence signal that
|
|
1642
|
+
// proposal §3.2 D5 lists as 'deployed-scope AC'). Ruling R13
|
|
1643
|
+
// 2026-10-05: tree-wide; computed by computeOperationalConcernsCheck
|
|
1644
|
+
// so the same check is reused ahead of the scope early-return.
|
|
1645
|
+
checks.push(operationalCheck);
|
|
862
1646
|
|
|
863
1647
|
// Check 3: no open concern-ledger entry on a REQ in scope.
|
|
864
1648
|
const concerns = /** @type {any} */ (ctx.ledgers?.concerns);
|
|
@@ -871,6 +1655,52 @@ export function checkD5Crosscut(ctx) {
|
|
|
871
1655
|
openInScope.map((c) => ({ id: `concern:${c.id}`, why: `open concern on ${c.reqId}: ${c.concern}` })),
|
|
872
1656
|
));
|
|
873
1657
|
|
|
1658
|
+
// Check 4 (0.30.0 PR 6): crosscut:catalogue (engineer, over tree).
|
|
1659
|
+
// For every REQ in scope, enumerate applicable (reqShape, concern)
|
|
1660
|
+
// pairs via src/define/concern-catalogue.js; each pair needs a
|
|
1661
|
+
// concern-ledger entry keyed <REQ>:<concern> with disposition
|
|
1662
|
+
// applied or waived (a waived entry carries a reason). Fail ids are
|
|
1663
|
+
// `<REQ>:<concern>`; the why names the missing concern. A waived
|
|
1664
|
+
// entry without a reason also fails. Keys shared with the baseline
|
|
1665
|
+
// catalogue where names coincide (today only `auth`).
|
|
1666
|
+
const entriesByKey = new Map();
|
|
1667
|
+
for (const entry of concernEntries) {
|
|
1668
|
+
if (!entry || typeof entry.reqId !== 'string' || typeof entry.concern !== 'string') continue;
|
|
1669
|
+
entriesByKey.set(`${entry.reqId}:${entry.concern}`, entry);
|
|
1670
|
+
}
|
|
1671
|
+
/** @type {Array<{ id: string, why: string }>} */
|
|
1672
|
+
const catalogueFindings = [];
|
|
1673
|
+
let totalCataloguePairs = 0;
|
|
1674
|
+
for (const req of reqInScope) {
|
|
1675
|
+
const shapes = Array.isArray(req?.shapeClassification?.shapes)
|
|
1676
|
+
? req.shapeClassification.shapes.filter((s) => typeof s === 'string')
|
|
1677
|
+
: [];
|
|
1678
|
+
const applicable = applicableConcernsForShapes(shapes);
|
|
1679
|
+
for (const concern of applicable) {
|
|
1680
|
+
totalCataloguePairs += 1;
|
|
1681
|
+
const key = `${req.reqId}:${concern}`;
|
|
1682
|
+
const entry = entriesByKey.get(key);
|
|
1683
|
+
if (!entry) {
|
|
1684
|
+
catalogueFindings.push({ id: key, why: `missing concern-ledger entry for ${concern}` });
|
|
1685
|
+
continue;
|
|
1686
|
+
}
|
|
1687
|
+
const disposition = typeof entry.disposition === 'string' ? entry.disposition : null;
|
|
1688
|
+
if (disposition !== 'applied' && disposition !== 'waived') {
|
|
1689
|
+
catalogueFindings.push({ id: key, why: `concern-ledger entry disposition is ${disposition ?? '(unset)'}` });
|
|
1690
|
+
continue;
|
|
1691
|
+
}
|
|
1692
|
+
if (disposition === 'waived') {
|
|
1693
|
+
const reason = typeof entry.reason === 'string' ? entry.reason.trim() : '';
|
|
1694
|
+
if (reason.length === 0) {
|
|
1695
|
+
catalogueFindings.push({ id: key, why: 'waived without a reason' });
|
|
1696
|
+
}
|
|
1697
|
+
}
|
|
1698
|
+
}
|
|
1699
|
+
}
|
|
1700
|
+
// Keep total >= 1 so the chip prints a sensible ratio when no REQ in
|
|
1701
|
+
// scope has applicable concerns (every REQ carries shape 'other').
|
|
1702
|
+
checks.push(makeCheck('crosscut:catalogue', 'tree', Math.max(totalCataloguePairs, 1), catalogueFindings));
|
|
1703
|
+
|
|
874
1704
|
return foldState('D5', gate, checks, {
|
|
875
1705
|
currentTreeHash: ctx.currentTreeHash ?? null,
|
|
876
1706
|
freezeGates: /** @type {any} */ (ctx.freeze?.gates),
|
|
@@ -882,14 +1712,14 @@ export function checkD5Crosscut(ctx) {
|
|
|
882
1712
|
// ---------------------------------------------------------------------------
|
|
883
1713
|
|
|
884
1714
|
/**
|
|
885
|
-
* D6 -- Consistency and satisfiability probe. 0.29.0
|
|
886
|
-
* validate-clean tree-wide check and the probe-ledger open count
|
|
887
|
-
*
|
|
888
|
-
*
|
|
889
|
-
*
|
|
890
|
-
*
|
|
891
|
-
*
|
|
892
|
-
*
|
|
1715
|
+
* D6 -- Consistency and satisfiability probe. 0.29.0 ran the
|
|
1716
|
+
* validate-clean tree-wide check and the probe-ledger open count;
|
|
1717
|
+
* 0.30.0 PR 7 (ADR-4131 extended, spec section 4 row 'D6 scans and the
|
|
1718
|
+
* injectable probe runner') adds the four mechanical scans
|
|
1719
|
+
* consistency:contradictions, consistency:unsatisfiable,
|
|
1720
|
+
* consistency:duplicates and consistency:orphanInterfaces. The probe
|
|
1721
|
+
* runner lives on the readiness compute (TAC-4123); the gate reads the
|
|
1722
|
+
* merged probes.probes[] it ends up with.
|
|
893
1723
|
*
|
|
894
1724
|
* @param {StageContext} ctx
|
|
895
1725
|
*/
|
|
@@ -933,12 +1763,350 @@ export function checkD6Consistency(ctx) {
|
|
|
933
1763
|
// uses a single representative entry regardless.
|
|
934
1764
|
checks.push(makeCheck('consistency:probeCount', 'tree', Math.max(effectiveOpen, 1), failing, effectiveOpen));
|
|
935
1765
|
|
|
1766
|
+
// ADR-4131 extended (0.30.0 PR 7): the four D6 scans.
|
|
1767
|
+
const scope = asSet(ctx.scope);
|
|
1768
|
+
const tree = ctx.tree;
|
|
1769
|
+
const usInScope = (tree.userStories ?? []).filter((us) => scope.has(us.usId));
|
|
1770
|
+
|
|
1771
|
+
// Scan 1: consistency:contradictions (engineer, over delta). Two ACs
|
|
1772
|
+
// on one story share a `when` clause and one of their `then` clauses
|
|
1773
|
+
// is a negation of the other. The quoted-cue guard strips
|
|
1774
|
+
// double-quoted substrings before the negation scan so prose that
|
|
1775
|
+
// quotes a negation inside a `then` does not fire the check.
|
|
1776
|
+
/** @type {Array<{ id: string, why: string }>} */
|
|
1777
|
+
const contradictionFindings = [];
|
|
1778
|
+
let totalStoriesScanned = 0;
|
|
1779
|
+
for (const us of usInScope) {
|
|
1780
|
+
const acs = Array.isArray(us.acceptanceCriteria) ? us.acceptanceCriteria : [];
|
|
1781
|
+
if (acs.length < 2) continue;
|
|
1782
|
+
totalStoriesScanned += 1;
|
|
1783
|
+
const parsed = acs
|
|
1784
|
+
.map((ac) => ({ ac, parts: parseWhenThen(ac?.description) }))
|
|
1785
|
+
.filter((p) => p.parts !== null);
|
|
1786
|
+
const reported = new Set();
|
|
1787
|
+
for (let i = 0; i < parsed.length; i += 1) {
|
|
1788
|
+
for (let j = i + 1; j < parsed.length; j += 1) {
|
|
1789
|
+
const a = parsed[i];
|
|
1790
|
+
const b = parsed[j];
|
|
1791
|
+
if (normaliseClause(a.parts.when) !== normaliseClause(b.parts.when)) continue;
|
|
1792
|
+
if (!thensNegateEachOther(a.parts.then, b.parts.then)) continue;
|
|
1793
|
+
const pairKey = `${us.usId}:${a.ac.id ?? '?'}:${b.ac.id ?? '?'}`;
|
|
1794
|
+
if (reported.has(pairKey)) continue;
|
|
1795
|
+
reported.add(pairKey);
|
|
1796
|
+
const idA = a.ac.id ?? us.usId;
|
|
1797
|
+
const idB = b.ac.id ?? us.usId;
|
|
1798
|
+
contradictionFindings.push({
|
|
1799
|
+
id: us.usId,
|
|
1800
|
+
why: `ACs ${idA} and ${idB} share a when clause with a negated then`,
|
|
1801
|
+
});
|
|
1802
|
+
}
|
|
1803
|
+
}
|
|
1804
|
+
}
|
|
1805
|
+
checks.push(makeCheck(
|
|
1806
|
+
'consistency:contradictions',
|
|
1807
|
+
'delta',
|
|
1808
|
+
Math.max(totalStoriesScanned, 1),
|
|
1809
|
+
contradictionFindings,
|
|
1810
|
+
));
|
|
1811
|
+
|
|
1812
|
+
// Scan 2: consistency:unsatisfiable (engineer, over delta). A `then`
|
|
1813
|
+
// naming a field that no recordShape anywhere in the tree defines
|
|
1814
|
+
// fails the AC with id `<acId>:<field>`. A field defined in a
|
|
1815
|
+
// `[draft]` recordShape counts as defined (the engineer owns the
|
|
1816
|
+
// draft; its `fields:` list is honest about what the then may name).
|
|
1817
|
+
const definedFields = collectRecordShapeFields(tree);
|
|
1818
|
+
/** @type {Array<{ id: string, why: string }>} */
|
|
1819
|
+
const unsatisfiableFindings = [];
|
|
1820
|
+
let totalThenFieldChecks = 0;
|
|
1821
|
+
for (const us of usInScope) {
|
|
1822
|
+
const acs = Array.isArray(us.acceptanceCriteria) ? us.acceptanceCriteria : [];
|
|
1823
|
+
for (const ac of acs) {
|
|
1824
|
+
const parts = parseWhenThen(ac?.description);
|
|
1825
|
+
if (!parts) continue;
|
|
1826
|
+
const fields = extractThenFieldTokens(parts.then);
|
|
1827
|
+
for (const field of fields) {
|
|
1828
|
+
totalThenFieldChecks += 1;
|
|
1829
|
+
if (definedFields.has(field)) continue;
|
|
1830
|
+
unsatisfiableFindings.push({
|
|
1831
|
+
id: `${ac.id ?? us.usId}:${field}`,
|
|
1832
|
+
why: `then names field ${field} that no recordShape defines`,
|
|
1833
|
+
});
|
|
1834
|
+
}
|
|
1835
|
+
}
|
|
1836
|
+
}
|
|
1837
|
+
checks.push(makeCheck(
|
|
1838
|
+
'consistency:unsatisfiable',
|
|
1839
|
+
'delta',
|
|
1840
|
+
Math.max(totalThenFieldChecks, 1),
|
|
1841
|
+
unsatisfiableFindings,
|
|
1842
|
+
));
|
|
1843
|
+
|
|
1844
|
+
// Scan 3: consistency:duplicates (engineer, over tree). Identical AC
|
|
1845
|
+
// descriptions across stories fail both ACs. The comparison trims
|
|
1846
|
+
// leading whitespace and the leading `[class]` marker.
|
|
1847
|
+
/** @type {Map<string, Array<{ usId: string, acId: string }>>} */
|
|
1848
|
+
const descBuckets = new Map();
|
|
1849
|
+
const allUs = tree.userStories ?? [];
|
|
1850
|
+
let totalDupAcs = 0;
|
|
1851
|
+
for (const us of allUs) {
|
|
1852
|
+
const acs = Array.isArray(us.acceptanceCriteria) ? us.acceptanceCriteria : [];
|
|
1853
|
+
for (const ac of acs) {
|
|
1854
|
+
const desc = typeof ac?.description === 'string' ? ac.description.trim() : '';
|
|
1855
|
+
if (desc.length === 0) continue;
|
|
1856
|
+
totalDupAcs += 1;
|
|
1857
|
+
const normalised = desc.replace(AC_CLASS_RE, '').trim().toLowerCase();
|
|
1858
|
+
if (normalised.length === 0) continue;
|
|
1859
|
+
const bucket = descBuckets.get(normalised) ?? [];
|
|
1860
|
+
bucket.push({ usId: us.usId, acId: ac.id ?? us.usId });
|
|
1861
|
+
descBuckets.set(normalised, bucket);
|
|
1862
|
+
}
|
|
1863
|
+
}
|
|
1864
|
+
/** @type {Array<{ id: string, why: string }>} */
|
|
1865
|
+
const duplicateFindings = [];
|
|
1866
|
+
for (const bucket of descBuckets.values()) {
|
|
1867
|
+
if (bucket.length < 2) continue;
|
|
1868
|
+
const stories = [...new Set(bucket.map((b) => b.usId))];
|
|
1869
|
+
if (stories.length < 2) continue;
|
|
1870
|
+
for (const entry of bucket) {
|
|
1871
|
+
duplicateFindings.push({
|
|
1872
|
+
id: entry.acId,
|
|
1873
|
+
why: `duplicate description (also on ${bucket.filter((b) => b.acId !== entry.acId).map((b) => b.acId).join(', ')})`,
|
|
1874
|
+
});
|
|
1875
|
+
}
|
|
1876
|
+
}
|
|
1877
|
+
checks.push(makeCheck(
|
|
1878
|
+
'consistency:duplicates',
|
|
1879
|
+
'tree',
|
|
1880
|
+
Math.max(totalDupAcs, 1),
|
|
1881
|
+
duplicateFindings,
|
|
1882
|
+
));
|
|
1883
|
+
|
|
1884
|
+
// Scan 4: consistency:orphanInterfaces (engineer, over tree). An
|
|
1885
|
+
// interface on any TAC that no AC `ownerRef` points at AND that no
|
|
1886
|
+
// REQ `deliveredBy` reaches fails. Shares the `interfaces[<name>]`
|
|
1887
|
+
// pointer grammar with D4 `stories:ownerRefResolves`. A REQ's
|
|
1888
|
+
// `deliveredBy` reaches an interface when it names the owning TAC id
|
|
1889
|
+
// (either as a `tacId` string or as a `TAC-nnnn:<name>` pointer).
|
|
1890
|
+
const reachedInterfaces = collectReachedInterfaces(tree);
|
|
1891
|
+
/** @type {Array<{ id: string, why: string }>} */
|
|
1892
|
+
const orphanFindings = [];
|
|
1893
|
+
let totalInterfacesScanned = 0;
|
|
1894
|
+
for (const tac of tree.tacs ?? []) {
|
|
1895
|
+
const list = Array.isArray(tac?.interfaces) ? tac.interfaces : [];
|
|
1896
|
+
for (const iface of list) {
|
|
1897
|
+
const name = typeof iface?.name === 'string' ? iface.name : null;
|
|
1898
|
+
if (!name) continue;
|
|
1899
|
+
totalInterfacesScanned += 1;
|
|
1900
|
+
const key = `${tac.tacId}:${name}`;
|
|
1901
|
+
if (reachedInterfaces.has(key)) continue;
|
|
1902
|
+
orphanFindings.push({
|
|
1903
|
+
id: key,
|
|
1904
|
+
why: 'no AC ownerRef and no REQ deliveredBy reaches it',
|
|
1905
|
+
});
|
|
1906
|
+
}
|
|
1907
|
+
}
|
|
1908
|
+
checks.push(makeCheck(
|
|
1909
|
+
'consistency:orphanInterfaces',
|
|
1910
|
+
'tree',
|
|
1911
|
+
Math.max(totalInterfacesScanned, 1),
|
|
1912
|
+
orphanFindings,
|
|
1913
|
+
));
|
|
1914
|
+
|
|
936
1915
|
return foldState('D6', gate, checks, {
|
|
937
1916
|
currentTreeHash: ctx.currentTreeHash ?? null,
|
|
938
1917
|
freezeGates: /** @type {any} */ (ctx.freeze?.gates),
|
|
939
1918
|
});
|
|
940
1919
|
}
|
|
941
1920
|
|
|
1921
|
+
/**
|
|
1922
|
+
* Parse an AC description into { when, then } clause strings. Accepts
|
|
1923
|
+
* the common "given ... when ... then ..." shape used across the ACs
|
|
1924
|
+
* of this codebase; returns null when the description does not carry
|
|
1925
|
+
* both a `when` and a `then` segment. The leading `[class]` marker is
|
|
1926
|
+
* stripped before the scan. The match is case-insensitive on the
|
|
1927
|
+
* keywords only; the clause bodies keep their original casing.
|
|
1928
|
+
*
|
|
1929
|
+
* @param {unknown} desc
|
|
1930
|
+
* @returns {{ when: string, then: string } | null}
|
|
1931
|
+
*/
|
|
1932
|
+
function parseWhenThen(desc) {
|
|
1933
|
+
if (typeof desc !== 'string' || desc.length === 0) return null;
|
|
1934
|
+
const stripped = desc.replace(AC_CLASS_RE, '').trim();
|
|
1935
|
+
const re = /\bwhen\b([\s\S]*?)\bthen\b([\s\S]*)$/i;
|
|
1936
|
+
const m = stripped.match(re);
|
|
1937
|
+
if (!m) return null;
|
|
1938
|
+
const when = m[1].trim();
|
|
1939
|
+
const then = m[2].trim();
|
|
1940
|
+
if (when.length === 0 || then.length === 0) return null;
|
|
1941
|
+
return { when, then };
|
|
1942
|
+
}
|
|
1943
|
+
|
|
1944
|
+
/**
|
|
1945
|
+
* Normalise a clause for the contradictions scan: lower-case, trim,
|
|
1946
|
+
* collapse whitespace. A clause is "the same" between two ACs when
|
|
1947
|
+
* their normalised forms match.
|
|
1948
|
+
*
|
|
1949
|
+
* @param {string} clause
|
|
1950
|
+
* @returns {string}
|
|
1951
|
+
*/
|
|
1952
|
+
function normaliseClause(clause) {
|
|
1953
|
+
return clause.toLowerCase().replace(/\s+/g, ' ').trim();
|
|
1954
|
+
}
|
|
1955
|
+
|
|
1956
|
+
/**
|
|
1957
|
+
* Strip double-quoted substrings and then test whether one `then`
|
|
1958
|
+
* clause is the negation of the other. "Negation" is a cheap test: one
|
|
1959
|
+
* clause begins (or carries, after a verb) a `not`, `no`, `does not`,
|
|
1960
|
+
* `is not`, `never`, `must not` token where the other clause does not;
|
|
1961
|
+
* or the two clauses are the same body with one carrying such a token.
|
|
1962
|
+
* The quoted-substring strip is the shared guard with D4.
|
|
1963
|
+
*
|
|
1964
|
+
* @param {string} a
|
|
1965
|
+
* @param {string} b
|
|
1966
|
+
* @returns {boolean}
|
|
1967
|
+
*/
|
|
1968
|
+
function thensNegateEachOther(a, b) {
|
|
1969
|
+
const aPlain = normaliseClause(stripQuotedSubstrings(a));
|
|
1970
|
+
const bPlain = normaliseClause(stripQuotedSubstrings(b));
|
|
1971
|
+
if (aPlain === bPlain) return false;
|
|
1972
|
+
const NEG_RE = /\b(?:not|no|never|does not|is not|must not|cannot|won't|will not)\b/;
|
|
1973
|
+
const aNeg = NEG_RE.test(aPlain);
|
|
1974
|
+
const bNeg = NEG_RE.test(bPlain);
|
|
1975
|
+
if (aNeg === bNeg) return false;
|
|
1976
|
+
// One side negates; test the negated body against the positive one.
|
|
1977
|
+
const positive = aNeg ? bPlain : aPlain;
|
|
1978
|
+
const negative = aNeg ? aPlain : bPlain;
|
|
1979
|
+
const negativeStripped = negative.replace(NEG_RE, '').replace(/\s+/g, ' ').trim();
|
|
1980
|
+
// A sufficiently similar body is "the same claim with a negation".
|
|
1981
|
+
// We treat the shorter being a prefix / suffix / substring of the
|
|
1982
|
+
// longer, or sharing 80% of its tokens, as "same body".
|
|
1983
|
+
if (negativeStripped.length === 0) return false;
|
|
1984
|
+
if (positive.includes(negativeStripped) || negativeStripped.includes(positive)) return true;
|
|
1985
|
+
const posTokens = new Set(positive.split(/\s+/).filter((t) => t.length > 2));
|
|
1986
|
+
const negTokens = negativeStripped.split(/\s+/).filter((t) => t.length > 2);
|
|
1987
|
+
if (negTokens.length === 0) return false;
|
|
1988
|
+
const shared = negTokens.filter((t) => posTokens.has(t)).length;
|
|
1989
|
+
return shared / negTokens.length >= 0.6;
|
|
1990
|
+
}
|
|
1991
|
+
|
|
1992
|
+
/**
|
|
1993
|
+
* Collect every field name defined by any `recordShape` interface in
|
|
1994
|
+
* the tree. A `fields:` marker in the interface description introduces
|
|
1995
|
+
* a list of field names; each name is a token on a bullet, a line, or
|
|
1996
|
+
* a comma-separated list. Draft recordShapes are included (the
|
|
1997
|
+
* engineer owns the draft and its fields: list is honest).
|
|
1998
|
+
*
|
|
1999
|
+
* @param {import('#core/store/walker.js').TreeModel} tree
|
|
2000
|
+
* @returns {Set<string>}
|
|
2001
|
+
*/
|
|
2002
|
+
function collectRecordShapeFields(tree) {
|
|
2003
|
+
const out = new Set();
|
|
2004
|
+
for (const tac of tree.tacs ?? []) {
|
|
2005
|
+
for (const iface of tac.interfaces ?? []) {
|
|
2006
|
+
if (iface?.kind !== 'recordShape') continue;
|
|
2007
|
+
const desc = typeof iface?.description === 'string' ? iface.description : '';
|
|
2008
|
+
const stripped = stripDraftPrefix(desc);
|
|
2009
|
+
// Find the `fields:` segment and read until the next `:` or end.
|
|
2010
|
+
const match = stripped.match(/(^|\n)\s*(?:[-*]\s*)?fields\s*:\s*([\s\S]*?)(?=(?:\n\s*(?:[-*]\s*)?[a-zA-Z][a-zA-Z0-9_]*\s*:)|$)/);
|
|
2011
|
+
if (!match) continue;
|
|
2012
|
+
const body = match[2];
|
|
2013
|
+
for (const token of body.split(/[\s,]+/)) {
|
|
2014
|
+
const name = token.replace(/^[-*]/, '').replace(/[:(){}\[\]]/g, '').trim();
|
|
2015
|
+
if (!name) continue;
|
|
2016
|
+
if (/^[A-Za-z_][A-Za-z0-9_]*$/.test(name)) out.add(name);
|
|
2017
|
+
}
|
|
2018
|
+
}
|
|
2019
|
+
}
|
|
2020
|
+
return out;
|
|
2021
|
+
}
|
|
2022
|
+
|
|
2023
|
+
/**
|
|
2024
|
+
* Pull field tokens out of a `then` clause. A field token is a word
|
|
2025
|
+
* that follows a verb like `set`, `write`, `include`, `return`,
|
|
2026
|
+
* `contain`, `name` or appears as the direct object of a `then`'s
|
|
2027
|
+
* verb phrase; a cheap approximation uses `then <subject> <verb>
|
|
2028
|
+
* <field>` plus `field <name>`, `<name> field` and `field: <name>`
|
|
2029
|
+
* patterns. The scan is deliberately conservative so a plain English
|
|
2030
|
+
* sentence yields a small set.
|
|
2031
|
+
*
|
|
2032
|
+
* @param {string} thenClause
|
|
2033
|
+
* @returns {string[]}
|
|
2034
|
+
*/
|
|
2035
|
+
function extractThenFieldTokens(thenClause) {
|
|
2036
|
+
if (typeof thenClause !== 'string' || thenClause.length === 0) return [];
|
|
2037
|
+
const text = stripQuotedSubstrings(thenClause);
|
|
2038
|
+
/** @type {Set<string>} */
|
|
2039
|
+
const tokens = new Set();
|
|
2040
|
+
// Pattern 1: backticked identifier (`then `balance` is set`). The
|
|
2041
|
+
// primary signal; prose that quotes a field name under backticks is
|
|
2042
|
+
// the convention this check expects.
|
|
2043
|
+
for (const m of text.matchAll(/`([A-Za-z_][A-Za-z0-9_]*)`/g)) {
|
|
2044
|
+
if (m[1]) tokens.add(m[1]);
|
|
2045
|
+
}
|
|
2046
|
+
// Pattern 2: `<name> field` (adjective-form naming). An English
|
|
2047
|
+
// "stop word" skip keeps "the field", "a field" and "its field" from
|
|
2048
|
+
// tripping the check.
|
|
2049
|
+
const STOP = new Set(['the', 'a', 'an', 'this', 'that', 'its', 'our', 'their', 'any', 'no', 'some', 'each', 'every', 'another']);
|
|
2050
|
+
for (const m of text.matchAll(/\b([A-Za-z_][A-Za-z0-9_]*)\s+field\b/g)) {
|
|
2051
|
+
const token = m[1];
|
|
2052
|
+
if (!token) continue;
|
|
2053
|
+
if (STOP.has(token.toLowerCase())) continue;
|
|
2054
|
+
tokens.add(token);
|
|
2055
|
+
}
|
|
2056
|
+
// Pattern 3: `field: <name>` or `field = <name>` (schema-like
|
|
2057
|
+
// notation inside a then clause).
|
|
2058
|
+
for (const m of text.matchAll(/\bfield\s*[:=]\s*([A-Za-z_][A-Za-z0-9_]*)/g)) {
|
|
2059
|
+
if (m[1]) tokens.add(m[1]);
|
|
2060
|
+
}
|
|
2061
|
+
return [...tokens];
|
|
2062
|
+
}
|
|
2063
|
+
|
|
2064
|
+
/**
|
|
2065
|
+
* Collect every interface the tree "reaches" from an AC `ownerRef` or
|
|
2066
|
+
* a REQ `deliveredBy` (REQ-174 companion field). The result is a Set
|
|
2067
|
+
* of `<tacId>:<name>` keys. A `deliveredBy` on a REQ can take two
|
|
2068
|
+
* shapes: an array of `TAC-nnnn:<name>` pointer strings, or an array
|
|
2069
|
+
* of plain TAC ids ("delivered by this TAC"); the second shape reaches
|
|
2070
|
+
* every interface on the named TAC.
|
|
2071
|
+
*
|
|
2072
|
+
* @param {import('#core/store/walker.js').TreeModel} tree
|
|
2073
|
+
* @returns {Set<string>}
|
|
2074
|
+
*/
|
|
2075
|
+
function collectReachedInterfaces(tree) {
|
|
2076
|
+
const out = new Set();
|
|
2077
|
+
// AC ownerRefs.
|
|
2078
|
+
for (const us of tree.userStories ?? []) {
|
|
2079
|
+
const acs = Array.isArray(us.acceptanceCriteria) ? us.acceptanceCriteria : [];
|
|
2080
|
+
for (const ac of acs) {
|
|
2081
|
+
if (!acHasOwnerRef(ac)) continue;
|
|
2082
|
+
const ref = /** @type {any} */ (ac).ownerRef;
|
|
2083
|
+
const name = parseOwnerRefInterfaceField(ref?.field);
|
|
2084
|
+
if (!name || typeof ref?.tacId !== 'string') continue;
|
|
2085
|
+
out.add(`${ref.tacId}:${name}`);
|
|
2086
|
+
}
|
|
2087
|
+
}
|
|
2088
|
+
// REQ deliveredBy (optional field; shapes above).
|
|
2089
|
+
for (const req of tree.requirements ?? []) {
|
|
2090
|
+
const deliveredBy = /** @type {any} */ (req)?.deliveredBy;
|
|
2091
|
+
if (!Array.isArray(deliveredBy)) continue;
|
|
2092
|
+
for (const entry of deliveredBy) {
|
|
2093
|
+
if (typeof entry !== 'string' || entry.length === 0) continue;
|
|
2094
|
+
const m = entry.match(/^(TAC-[A-Za-z0-9-]+):(.+)$/);
|
|
2095
|
+
if (m) {
|
|
2096
|
+
out.add(`${m[1]}:${m[2]}`);
|
|
2097
|
+
continue;
|
|
2098
|
+
}
|
|
2099
|
+
// Plain TAC id: every interface on that TAC is reached.
|
|
2100
|
+
const tac = (tree.tacs ?? []).find((t) => t?.tacId === entry);
|
|
2101
|
+
if (!tac) continue;
|
|
2102
|
+
for (const iface of tac.interfaces ?? []) {
|
|
2103
|
+
if (typeof iface?.name === 'string') out.add(`${tac.tacId}:${iface.name}`);
|
|
2104
|
+
}
|
|
2105
|
+
}
|
|
2106
|
+
}
|
|
2107
|
+
return out;
|
|
2108
|
+
}
|
|
2109
|
+
|
|
942
2110
|
// ---------------------------------------------------------------------------
|
|
943
2111
|
// D7 -- Decisions and review (blocking in 0.29.0).
|
|
944
2112
|
// ---------------------------------------------------------------------------
|