rcf-lite 0.28.4 → 0.30.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 +194 -1
- package/bin/rcf.js +4 -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 +89 -0
- package/guidance/define-intake.md +97 -0
- package/guidance/define-intent.md +107 -0
- package/guidance/define-litmus.md +102 -0
- package/guidance/discover-prototype.md +67 -0
- package/guidance/discovery-prototypes.md +69 -0
- package/guidance/harness-template.md +34 -0
- package/guidance/managed/agent-instructions-block.hash +1 -1
- package/guidance/managed/agent-instructions-block.md +34 -0
- package/guidance/manifest.json +10 -2
- package/package.json +1 -1
- package/rcf/adrs/adr-4124-define-freeze-verb.json +30 -0
- package/rcf/adrs/adr-4126-persona-tagged-blockers-two-levels.json +40 -0
- package/rcf/adrs/adr-4127-readiness-tab-order-and-register.json +40 -0
- package/rcf/adrs/adr-4129-questions-harness-driven-loop.json +25 -0
- package/rcf/adrs/adr-4130-intake-harness-split-tool-scanned.json +20 -0
- package/rcf/adrs/adr-4131-gates-bite-ack-recorded-override.json +30 -0
- package/rcf/adrs/adr-4132-prototypes-in-discovery-as-evidence.json +20 -0
- package/rcf/adrs/adr-4133-dag-dependency-depth-layout.json +40 -0
- package/rcf/adrs/adr-4134-index-json-route.json +35 -0
- package/rcf/adrs/adr-4135-readiness-po-register-and-adapter.json +35 -0
- package/rcf/adrs/adr-4136-embedding-host-fixture.json +35 -0
- package/rcf/code-nodes/cn-725.json +18 -2
- package/rcf/code-nodes/cn-726.json +10 -2
- package/rcf/code-nodes/cn-727.json +13 -4
- package/rcf/code-nodes/cn-728.json +18 -2
- package/rcf/code-nodes/cn-729.json +10 -2
- package/rcf/code-nodes/cn-730.json +13 -3
- package/rcf/code-nodes/cn-731.json +20 -0
- package/rcf/code-nodes/cn-732.json +14 -0
- package/rcf/code-nodes/cn-733.json +14 -0
- package/rcf/code-nodes/cn-734.json +14 -0
- package/rcf/code-nodes/cn-735.json +20 -0
- package/rcf/code-nodes/cn-736.json +14 -0
- package/rcf/code-nodes/cn-737.json +14 -0
- package/rcf/code-nodes/cn-738.json +14 -0
- package/rcf/code-nodes/cn-739.json +18 -0
- package/rcf/code-nodes/cn-740.json +19 -0
- package/rcf/code-nodes/cn-741.json +16 -0
- package/rcf/code-nodes/cn-742.json +16 -0
- package/rcf/code-nodes/cn-743.json +15 -0
- package/rcf/code-nodes/cn-744.json +22 -0
- package/rcf/code-nodes/cn-745.json +16 -0
- package/rcf/code-nodes/cn-746.json +14 -0
- package/rcf/code-nodes/cn-747.json +18 -0
- package/rcf/code-nodes/cn-748.json +16 -0
- package/rcf/code-nodes/cn-749.json +16 -0
- package/rcf/code-nodes/cn-750.json +15 -0
- package/rcf/code-nodes/cn-751.json +18 -0
- package/rcf/code-nodes/cn-752.json +14 -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/fbs/fbs-196.json +13 -5
- package/rcf/fbs/fbs-198.json +42 -0
- package/rcf/fbs/fbs-199.json +59 -0
- package/rcf/fbs/fbs-200.json +46 -0
- package/rcf/fbs/fbs-201.json +49 -0
- package/rcf/fbs/fbs-202.json +170 -0
- package/rcf/fbs/fbs-203.json +100 -0
- package/rcf/requirements/req-002.json +2 -2
- package/rcf/requirements/req-173.json +2 -2
- package/rcf/requirements/req-174.json +10 -4
- package/rcf/requirements/req-175.json +10 -4
- package/rcf/requirements/req-176.json +25 -0
- 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/requirements/req-180.json +31 -0
- package/rcf/requirements/req-181.json +31 -0
- package/rcf/requirements/req-182.json +25 -0
- package/rcf/requirements/req-186.json +25 -0
- package/rcf/requirements/req-187.json +31 -0
- package/rcf/requirements/req-188.json +25 -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 +16 -3
- package/rcf/tacs/tac-4122-define-gates.json +69 -5
- package/rcf/tacs/tac-4123-define-readiness.json +66 -4
- package/rcf/tacs/tac-4124-define-freeze.json +28 -0
- 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-4127-readiness-view.json +49 -0
- package/rcf/tacs/tac-4128-define-guidance.json +59 -0
- package/rcf/tacs/tac-4129-define-questions.json +45 -0
- package/rcf/tacs/tac-4130-define-intake-brief.json +35 -0
- package/rcf/tacs/tac-4131-build-dag-view.json +39 -0
- package/rcf/tacs/tac-4132-id-lookup.json +42 -0
- package/rcf/tacs/tac-4133-readiness-po-layer.json +37 -0
- package/rcf/tacs/tac-4134-wespa-host-fixture.json +54 -0
- package/rcf/test-suites/ts-016.json +3 -3
- package/rcf/test-suites/ts-215.json +148 -4
- package/rcf/test-suites/ts-216.json +19 -3
- package/rcf/test-suites/ts-218.json +78 -0
- package/rcf/test-suites/ts-219.json +70 -0
- package/rcf/test-suites/ts-220.json +78 -0
- package/rcf/test-suites/ts-221.json +78 -0
- package/rcf/test-suites/ts-222.json +100 -0
- package/rcf/test-suites/ts-223.json +94 -0
- package/rcf/test-suites/ts-224.json +70 -0
- package/rcf/test-suites/ts-225.json +78 -0
- package/rcf/test-suites/ts-226.json +158 -0
- package/rcf/test-suites/ts-227.json +38 -0
- package/rcf/test-suites/ts-228.json +86 -0
- package/rcf/test-suites/ts-229.json +83 -0
- package/rcf/test-suites/ts-230.json +76 -0
- package/rcf/test-suites/ts-231.json +104 -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/user-stories/us-17302.json +50 -0
- package/rcf/user-stories/us-17401.json +14 -2
- package/rcf/user-stories/us-17402.json +55 -0
- package/rcf/user-stories/us-17403.json +60 -0
- package/rcf/user-stories/us-17404.json +51 -0
- package/rcf/user-stories/us-17405.json +61 -0
- package/rcf/user-stories/us-17406.json +51 -0
- package/rcf/user-stories/us-17502.json +60 -0
- package/rcf/user-stories/us-17503.json +65 -0
- package/rcf/user-stories/us-17504.json +46 -0
- package/rcf/user-stories/us-17601.json +58 -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-18001.json +55 -0
- package/rcf/user-stories/us-18002.json +35 -0
- package/rcf/user-stories/us-18101.json +35 -0
- package/rcf/user-stories/us-18202.json +40 -0
- package/rcf/user-stories/us-18601.json +55 -0
- package/rcf/user-stories/us-18602.json +50 -0
- package/rcf/user-stories/us-18603.json +45 -0
- package/rcf/user-stories/us-18701.json +50 -0
- package/rcf/user-stories/us-18702.json +50 -0
- package/rcf/user-stories/us-18801.json +45 -0
- package/rcf/user-stories/us-204.json +59 -0
- package/rcf/user-stories/us-205.json +64 -0
- package/rcf/user-stories/us-206.json +54 -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/freeze.js +780 -0
- package/src/cli/help.js +12 -0
- package/src/cli/ledger.js +228 -12
- package/src/cli/questions.js +288 -0
- package/src/cli/readiness.js +393 -74
- package/src/cli/validate.js +8 -0
- package/src/cli/view.js +29 -0
- package/src/define/concern-catalogue.js +130 -0
- package/src/define/freeze-record.js +104 -15
- package/src/define/ledgers.js +210 -11
- package/src/define/probe-runner.js +55 -0
- package/src/define/validate-findings.js +256 -0
- package/src/intake/index.js +1 -1
- package/src/intake/orchestrator.js +117 -0
- package/src/mcp/tools.js +354 -0
- package/src/query/delta.js +6 -0
- package/src/query/gates.js +1258 -48
- package/src/query/index.js +22 -3
- package/src/query/questions.js +438 -0
- package/src/query/readiness.js +427 -9
- package/src/query/refuse-on-admissibility.js +137 -4
- package/src/ruleset/ruleset.json +35 -0
- package/src/server/index.js +24 -2
- package/src/server/routes.js +68 -1
- package/src/setup/identity-seed.js +17 -0
- package/src/view/build-dag.js +563 -0
- package/src/view/components/badge.js +41 -0
- package/src/view/components/diff.js +72 -0
- package/src/view/components/doc-row.js +62 -0
- package/src/view/components/empty-state.js +35 -0
- package/src/view/components/entity-selector.js +137 -0
- package/src/view/components/filter-bar.js +97 -0
- package/src/view/components/findings-list.js +49 -0
- package/src/view/components/index.js +12 -0
- package/src/view/components/pill.js +46 -0
- package/src/view/components/sub-tab-strip.js +43 -0
- package/src/view/components/toast.js +25 -0
- package/src/view/components-fixture.js +265 -0
- package/src/view/doc-renderers/architecture.js +304 -0
- package/src/view/doc-renderers/build.js +160 -0
- package/src/view/doc-renderers/index.js +2 -0
- package/src/view/doc-renderers/prd.js +35 -6
- package/src/view/html-page.js +700 -602
- package/src/view/index.js +96 -3
- package/src/view/live-client.js +39 -6
- package/src/view/needs-work.js +79 -0
- package/src/view/page-init.js +2193 -0
- package/src/view/readiness/phrasebook.js +115 -0
- package/src/view/readiness/po-layer.js +288 -0
- package/src/view/readiness/question-adapter.js +329 -0
- package/src/view/readiness/stage-legend.js +71 -0
- package/src/view/readiness.js +505 -0
- package/src/view/style.css +2017 -382
- package/src/view/test-host/embed-client.js +121 -0
- package/src/view/test-host/fixture.js +183 -0
- package/src/view/test-host/lints.js +220 -0
- package/src/view/view-index.js +323 -0
package/src/query/gates.js
CHANGED
|
@@ -45,7 +45,8 @@
|
|
|
45
45
|
|
|
46
46
|
import { computeQueue } from '../build/queue.js';
|
|
47
47
|
import { isOptedOut } from '../req-baseline/opt-out.js';
|
|
48
|
-
import { BRIEF_KINDS } from '../define/ledgers.js';
|
|
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']);
|
|
@@ -91,6 +92,329 @@ export const INTERFACE_KINDS = /** @type {const} */ ([
|
|
|
91
92
|
'port', 'fileFormat', 'fixture', 'other',
|
|
92
93
|
]);
|
|
93
94
|
|
|
95
|
+
/**
|
|
96
|
+
* Owning persona for every stage-gate check in 0.29.0 (ADR-4126).
|
|
97
|
+
*
|
|
98
|
+
* Two values: `productOwner` (the person who owns what the product
|
|
99
|
+
* must do) and `engineer` (the person who owns how it is built).
|
|
100
|
+
* There is no `either` / `shared` / `both`; a check that would need
|
|
101
|
+
* both is split, which is what happens to `skeleton:reqFields`
|
|
102
|
+
* (becomes `skeleton:reqIntent` + `skeleton:reqShape`) and
|
|
103
|
+
* `decisions:allAnswered` (becomes `decisions:wellFormed` +
|
|
104
|
+
* `decisions:allAnswered`). A failing item inherits its check's
|
|
105
|
+
* persona; there is no per-item override.
|
|
106
|
+
*
|
|
107
|
+
* The `notApplicable` placeholder (`stage:<D>:scope`) carries the
|
|
108
|
+
* per-stage fallback persona from `STAGE_FALLBACK_PERSONA` below.
|
|
109
|
+
* It is always ok so it never affects a level verdict.
|
|
110
|
+
*/
|
|
111
|
+
export const CHECK_PERSONA = /** @type {const} */ ({
|
|
112
|
+
// D1 Brief: every check is PO (the brief is the PO's statement of intent).
|
|
113
|
+
'brief:sinceFreeze': 'productOwner',
|
|
114
|
+
'brief:kinds': 'productOwner',
|
|
115
|
+
'brief:openQuestions': 'productOwner',
|
|
116
|
+
'brief:profile': 'productOwner',
|
|
117
|
+
// D2 Skeleton: resolvedBy + reqIntent are PO; reqShape, tadPersistence, deployAdr, standardsCited are engineer.
|
|
118
|
+
'skeleton:resolvedBy': 'productOwner',
|
|
119
|
+
'skeleton:reqIntent': 'productOwner',
|
|
120
|
+
'skeleton:reqShape': 'engineer',
|
|
121
|
+
'skeleton:tadPersistence': 'engineer',
|
|
122
|
+
'skeleton:deployAdr': 'engineer',
|
|
123
|
+
'skeleton:standardsCited': 'engineer',
|
|
124
|
+
// D3 Shapes: every check is engineer (shapes are the engineer's first act after hand-over).
|
|
125
|
+
'shapes:tacHasInterface': 'engineer',
|
|
126
|
+
'shapes:kindVocabulary': 'engineer',
|
|
127
|
+
'shapes:draftSettled': 'engineer',
|
|
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.
|
|
132
|
+
'stories:reqHasUs': 'productOwner',
|
|
133
|
+
'stories:usFloors': 'engineer',
|
|
134
|
+
'stories:closedSets': 'engineer',
|
|
135
|
+
'stories:ownerRefResolves': 'engineer',
|
|
136
|
+
// D5 Crosscut: TAD + concern-ledger content and the catalogue walk are engineering.
|
|
137
|
+
'crosscut:securityArchitecture': 'engineer',
|
|
138
|
+
'crosscut:operationalConcerns': 'engineer',
|
|
139
|
+
'crosscut:concernsResolved': 'engineer',
|
|
140
|
+
'crosscut:catalogue': 'engineer',
|
|
141
|
+
// D6 Consistency: schema validity, probes and the four scans are engineer.
|
|
142
|
+
'consistency:validateClean': 'engineer',
|
|
143
|
+
'consistency:probeCount': 'engineer',
|
|
144
|
+
'consistency:contradictions': 'engineer',
|
|
145
|
+
'consistency:unsatisfiable': 'engineer',
|
|
146
|
+
'consistency:duplicates': 'engineer',
|
|
147
|
+
'consistency:orphanInterfaces': 'engineer',
|
|
148
|
+
// D7 Decisions: enumeration is PO (the PO answers or lets the default stand);
|
|
149
|
+
// zero-open is the engineer's hand-over condition.
|
|
150
|
+
'decisions:wellFormed': 'productOwner',
|
|
151
|
+
'decisions:allAnswered': 'engineer',
|
|
152
|
+
// D8 Freeze: every check is mechanical / engineering.
|
|
153
|
+
'freeze:priorGates': 'engineer',
|
|
154
|
+
'freeze:acFbsOwnership': 'engineer',
|
|
155
|
+
'freeze:queueHead': 'engineer',
|
|
156
|
+
'freeze:validateClean': 'engineer',
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Per-check heading question in the owning persona's register
|
|
161
|
+
* (ADR-4126, proposal section 1.1). The text report and the
|
|
162
|
+
* Readiness tab print the question as the heading of each check's
|
|
163
|
+
* findings list. Static per check in 0.29.0; per-item plain-English
|
|
164
|
+
* wording is step 3's guided elicitation.
|
|
165
|
+
*/
|
|
166
|
+
export const CHECK_QUESTION = /** @type {const} */ ({
|
|
167
|
+
'brief:sinceFreeze': 'What has changed, or what is this project for?',
|
|
168
|
+
'brief:kinds': 'Is this a capability, a constraint, an actor, or something else?',
|
|
169
|
+
'brief:openQuestions': 'Any open questions in the brief, resolved or promoted to a decision?',
|
|
170
|
+
'brief:profile': 'How do you want to review, and who are you writing for?',
|
|
171
|
+
'skeleton:resolvedBy': 'Does this statement become a requirement, an entity, or an omission?',
|
|
172
|
+
'skeleton:reqIntent': 'What does this requirement mean and where does it sit?',
|
|
173
|
+
'skeleton:reqShape': 'Every requirement in scope carries a shape classification.',
|
|
174
|
+
'skeleton:tadPersistence': 'TAD data architecture lists dataStores and coreEntities for persistence REQs.',
|
|
175
|
+
'skeleton:deployAdr': 'Exactly one Deploy target or Deploy deferral ADR exists.',
|
|
176
|
+
'skeleton:standardsCited': 'Every registered standards pack is cited in a REQ rationale or an ADR, or waived by a concern-ledger entry.',
|
|
177
|
+
'shapes:tacHasInterface': 'Every TAC in scope has at least one interface.',
|
|
178
|
+
'shapes:kindVocabulary': 'Every interface kind is in the closed vocabulary.',
|
|
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.',
|
|
183
|
+
'stories:reqHasUs': 'What does someone do with this requirement?',
|
|
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.',
|
|
187
|
+
'crosscut:securityArchitecture': 'TAD.securityArchitecture is present when an auth or httpApi REQ exists.',
|
|
188
|
+
'crosscut:operationalConcerns': 'TAD.operationalConcerns is present when a deployed-scope AC exists.',
|
|
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.',
|
|
191
|
+
'consistency:validateClean': 'Validate is clean tree-wide.',
|
|
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.',
|
|
197
|
+
'decisions:wellFormed': 'Every decision is enumerated (question, two or more options, a default).',
|
|
198
|
+
'decisions:allAnswered': 'Zero decisions are open.',
|
|
199
|
+
'freeze:priorGates': 'Every prior stage passed or is acknowledged at the current hash.',
|
|
200
|
+
'freeze:acFbsOwnership': 'Every AC is owned by exactly one FBS.',
|
|
201
|
+
'freeze:queueHead': 'Queue head is actionable and not a placeholder.',
|
|
202
|
+
'freeze:validateClean': 'Validate is clean tree-wide.',
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Per-stage fallback persona for the `stage:<D>:scope` placeholder
|
|
207
|
+
* check that `notApplicable` envelopes carry. The placeholder is
|
|
208
|
+
* always ok so this never affects a level, but keeps "every check
|
|
209
|
+
* has a persona" true for consumers and the table test (ADR-4126
|
|
210
|
+
* decision 10).
|
|
211
|
+
*/
|
|
212
|
+
export const STAGE_FALLBACK_PERSONA = /** @type {const} */ ({
|
|
213
|
+
D1: 'productOwner',
|
|
214
|
+
D2: 'productOwner',
|
|
215
|
+
D3: 'engineer',
|
|
216
|
+
D4: 'productOwner',
|
|
217
|
+
D5: 'engineer',
|
|
218
|
+
D6: 'engineer',
|
|
219
|
+
D7: 'productOwner',
|
|
220
|
+
D8: 'engineer',
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* Look up the question heading for a check name.
|
|
225
|
+
* @param {string} name
|
|
226
|
+
* @returns {string}
|
|
227
|
+
*/
|
|
228
|
+
export function checkQuestion(name) {
|
|
229
|
+
return /** @type {any} */ (CHECK_QUESTION)[name] ?? '';
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* Look up the owning persona for a check name.
|
|
234
|
+
* @param {string} name
|
|
235
|
+
* @returns {'productOwner' | 'engineer' | null}
|
|
236
|
+
*/
|
|
237
|
+
export function checkPersona(name) {
|
|
238
|
+
const v = /** @type {any} */ (CHECK_PERSONA)[name];
|
|
239
|
+
return v === 'productOwner' || v === 'engineer' ? v : null;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* Draft marker (ADR-4126 for `TAC.interfaces[].description` in 0.29.0;
|
|
244
|
+
* REQ-188 extends it to `TAC.purpose` and `coreEntities[].description`
|
|
245
|
+
* in 0.30.0). A description that starts with `[draft]` after optional
|
|
246
|
+
* leading whitespace is pre-populated engineer entry material; the
|
|
247
|
+
* engineer removes the marker when the shape is settled. Decision 6
|
|
248
|
+
* uses the same bracket-prefix convention for AC class.
|
|
249
|
+
*/
|
|
250
|
+
const INTERFACE_DRAFT_RE = /^\[draft\]/;
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* True when a string carries the leading `[draft]` marker
|
|
254
|
+
* (whitespace tolerated). Pure string test used by every draft-home
|
|
255
|
+
* reader below.
|
|
256
|
+
*
|
|
257
|
+
* @param {unknown} value
|
|
258
|
+
* @returns {boolean}
|
|
259
|
+
*/
|
|
260
|
+
export function hasDraftMarker(value) {
|
|
261
|
+
if (typeof value !== 'string') return false;
|
|
262
|
+
return INTERFACE_DRAFT_RE.test(value.trimStart());
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
/**
|
|
266
|
+
* True when an interface's `description` carries the leading
|
|
267
|
+
* `[draft]` marker (whitespace tolerated). Thin wrapper over
|
|
268
|
+
* `hasDraftMarker` kept for ADR-4126 call sites; REQ-188 adds
|
|
269
|
+
* `parseTacPurposeDraft` and `parseCoreEntityDraft` for the two new
|
|
270
|
+
* homes.
|
|
271
|
+
*
|
|
272
|
+
* @param {unknown} iface
|
|
273
|
+
* @returns {boolean}
|
|
274
|
+
*/
|
|
275
|
+
export function parseInterfaceDraft(iface) {
|
|
276
|
+
if (!iface || typeof iface !== 'object') return false;
|
|
277
|
+
return hasDraftMarker(/** @type {any} */ (iface).description);
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
/**
|
|
281
|
+
* True when a TAC's `purpose` carries the leading `[draft]` marker
|
|
282
|
+
* (whitespace tolerated). REQ-188 draft home; the engineer removes
|
|
283
|
+
* the marker when the TAC's purpose is owned.
|
|
284
|
+
*
|
|
285
|
+
* @param {unknown} tac
|
|
286
|
+
* @returns {boolean}
|
|
287
|
+
*/
|
|
288
|
+
export function parseTacPurposeDraft(tac) {
|
|
289
|
+
if (!tac || typeof tac !== 'object') return false;
|
|
290
|
+
return hasDraftMarker(/** @type {any} */ (tac).purpose);
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
/**
|
|
294
|
+
* True when a coreEntities entry's `description` carries the
|
|
295
|
+
* leading `[draft]` marker (whitespace tolerated). REQ-188 draft
|
|
296
|
+
* home; the engineer removes the marker when the entity is owned.
|
|
297
|
+
*
|
|
298
|
+
* @param {unknown} entity
|
|
299
|
+
* @returns {boolean}
|
|
300
|
+
*/
|
|
301
|
+
export function parseCoreEntityDraft(entity) {
|
|
302
|
+
if (!entity || typeof entity !== 'object') return false;
|
|
303
|
+
return hasDraftMarker(/** @type {any} */ (entity).description);
|
|
304
|
+
}
|
|
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
|
+
* Rough `path:` token scanner for an interface description. Returns
|
|
383
|
+
* every candidate path token the description names so the CLI can
|
|
384
|
+
* resolve them on disk and the gate can decide `shapes:pathsResolve`
|
|
385
|
+
* against the resolved map (ADR-4131). A candidate is any text that
|
|
386
|
+
* follows a `path:` or `path =` marker and looks like a repo-relative
|
|
387
|
+
* path (contains a `/` or ends with a file extension, no scheme). The
|
|
388
|
+
* scanner is deliberately conservative: an http URL, a bare word, a
|
|
389
|
+
* glob or a template placeholder is not a candidate. Exported for the
|
|
390
|
+
* CLI's resolve-on-disk pass.
|
|
391
|
+
*
|
|
392
|
+
* @param {string} description
|
|
393
|
+
* @returns {string[]}
|
|
394
|
+
*/
|
|
395
|
+
export function extractInterfacePathTokens(description) {
|
|
396
|
+
if (typeof description !== 'string' || description.length === 0) return [];
|
|
397
|
+
const text = stripDraftPrefix(description);
|
|
398
|
+
const out = [];
|
|
399
|
+
const re = /\bpath\s*[:=]\s*["'`]?([^\s"'`,;)\]]+)/g;
|
|
400
|
+
let m;
|
|
401
|
+
while ((m = re.exec(text)) !== null) {
|
|
402
|
+
const token = m[1];
|
|
403
|
+
if (!token) continue;
|
|
404
|
+
if (/^[a-z]+:\/\//i.test(token)) continue;
|
|
405
|
+
if (token.startsWith('{') || token.startsWith('<') || token.includes('*')) continue;
|
|
406
|
+
// Skip HTTP / UI route-ish tokens: a leading slash with no file
|
|
407
|
+
// extension is a route path (an httpRoute or uiRoute's `path:`
|
|
408
|
+
// marker), not a repo path. A legitimate file path lands as
|
|
409
|
+
// `src/x.js` or `packages/rcf-lite/CHANGELOG.md`; those don't
|
|
410
|
+
// start with `/`.
|
|
411
|
+
if (token.startsWith('/') && !/\.[a-zA-Z0-9]+$/.test(token)) continue;
|
|
412
|
+
if (!/\//.test(token) && !/\.[a-zA-Z0-9]+$/.test(token)) continue;
|
|
413
|
+
out.push(token);
|
|
414
|
+
}
|
|
415
|
+
return out;
|
|
416
|
+
}
|
|
417
|
+
|
|
94
418
|
/** Warn-with-ack stages in 0.29.0 (ADR-4122). */
|
|
95
419
|
const WARN_WITH_ACK = new Set(['D3', 'D5', 'D6']);
|
|
96
420
|
|
|
@@ -108,6 +432,21 @@ export function stagePolicy(stage) {
|
|
|
108
432
|
return WARN_WITH_ACK.has(stage) ? 'warnWithAck' : 'blocking';
|
|
109
433
|
}
|
|
110
434
|
|
|
435
|
+
/**
|
|
436
|
+
* ADR-4131 (0.30.0 PR 5): the three gates that accept a recorded
|
|
437
|
+
* `--ack` override. `stagePolicy` keeps returning `blocking` for every
|
|
438
|
+
* stage so the readyToBuild fold stays untouched; `ackable(stage)` is
|
|
439
|
+
* the companion signal the readiness and freeze CLIs read to decide
|
|
440
|
+
* whether a failing stage honours an acknowledgement at the current
|
|
441
|
+
* hash. True for D3, D5 and D6; false for everything else.
|
|
442
|
+
*
|
|
443
|
+
* @param {string} stage
|
|
444
|
+
* @returns {boolean}
|
|
445
|
+
*/
|
|
446
|
+
export function ackable(stage) {
|
|
447
|
+
return WARN_WITH_ACK.has(stage);
|
|
448
|
+
}
|
|
449
|
+
|
|
111
450
|
/**
|
|
112
451
|
* Scaffold TODO placeholder marker: uppercase "TODO" followed by a
|
|
113
452
|
* colon, matching every scaffold string `rcf init` and `rcf define
|
|
@@ -124,6 +463,192 @@ const TODO_RE = /\bTODO:/;
|
|
|
124
463
|
/** Bracketed AC-class prefix (Baz decision 6, proposal §3.2 D4). */
|
|
125
464
|
const AC_CLASS_RE = /^\[(happy|edge|failure|must-not|non-functional)\]/;
|
|
126
465
|
|
|
466
|
+
/**
|
|
467
|
+
* Enumeration cues for `stories:closedSets` (spec section 4 row 'D4
|
|
468
|
+
* closed-set and ownerRef as findings', 0.30.0 PR 6). An AC description
|
|
469
|
+
* that contains any of these cues outside a quoted string, with no
|
|
470
|
+
* inline bracketed list or ownerRef, invites an unlisted value and
|
|
471
|
+
* fails the check. The cues are matched case-insensitively against the
|
|
472
|
+
* raw description (minus any leading [class] marker and any
|
|
473
|
+
* double-quoted substrings).
|
|
474
|
+
*/
|
|
475
|
+
const CLOSED_SET_CUES = Object.freeze([
|
|
476
|
+
'one of',
|
|
477
|
+
'any of',
|
|
478
|
+
'the following',
|
|
479
|
+
'types of',
|
|
480
|
+
'status is',
|
|
481
|
+
]);
|
|
482
|
+
// Word-boundary matchers for each cue so a longer word that happens
|
|
483
|
+
// to contain the cue as a substring (e.g. "status issue" containing
|
|
484
|
+
// "status is") does not trip the gate.
|
|
485
|
+
const CLOSED_SET_CUE_RES = Object.freeze(
|
|
486
|
+
CLOSED_SET_CUES.map((cue) => new RegExp(`\\b${cue.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')}\\b`, 'i')),
|
|
487
|
+
);
|
|
488
|
+
|
|
489
|
+
/**
|
|
490
|
+
* Inline bracketed list regex for the closed-sets check: a square-
|
|
491
|
+
* bracketed group whose contents look like a list of two or more
|
|
492
|
+
* tokens separated by commas, slashes or pipes. A bare `[happy]`
|
|
493
|
+
* class marker is NOT a list (one token, no separator); `[a, b]`,
|
|
494
|
+
* `[a | b | c]` and `[a/b]` are.
|
|
495
|
+
*/
|
|
496
|
+
const INLINE_LIST_RE = /\[[^\]\n]*[,|\/][^\]\n]*\]/;
|
|
497
|
+
|
|
498
|
+
/**
|
|
499
|
+
* ownerRef marker: a cheap presence check for the structured
|
|
500
|
+
* `{ tacId, field: "interfaces[<name>]" }` pointer. True when the AC
|
|
501
|
+
* carries an ownerRef object (consistency-lint and PR 6 both read the
|
|
502
|
+
* same field).
|
|
503
|
+
*
|
|
504
|
+
* @param {unknown} ac
|
|
505
|
+
* @returns {boolean}
|
|
506
|
+
*/
|
|
507
|
+
function acHasOwnerRef(ac) {
|
|
508
|
+
const ref = ac && typeof ac === 'object' ? /** @type {any} */ (ac).ownerRef : null;
|
|
509
|
+
if (!ref || typeof ref !== 'object') return false;
|
|
510
|
+
// R11 (spec section 17, 2026-10-03): an ownerRef may name a TAC
|
|
511
|
+
// (via tacId) OR an ADR (via adrId). Pre-R11 code only recognised
|
|
512
|
+
// tacId; the ADR branch was dropped silently.
|
|
513
|
+
return typeof ref.tacId === 'string' || typeof ref.adrId === 'string';
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
/**
|
|
517
|
+
* Strip double-quoted substrings so a quoted cue inside the AC text
|
|
518
|
+
* does not fire the closed-sets check (shared with D6's negation guard
|
|
519
|
+
* convention). Matches `"..."` with no embedded unescaped double
|
|
520
|
+
* quote; the regex is deliberately permissive. The strip is only for
|
|
521
|
+
* the cue scan; the inline-list scan reads the full description.
|
|
522
|
+
*
|
|
523
|
+
* @param {string} desc
|
|
524
|
+
* @returns {string}
|
|
525
|
+
*/
|
|
526
|
+
function stripQuotedSubstrings(desc) {
|
|
527
|
+
return desc.replace(/"[^"\n]*"/g, '');
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
/**
|
|
531
|
+
* True when the AC description carries an enumeration cue outside a
|
|
532
|
+
* quoted substring, with no inline bracketed list and no ownerRef
|
|
533
|
+
* pointer. Pure.
|
|
534
|
+
*
|
|
535
|
+
* @param {unknown} ac
|
|
536
|
+
* @returns {boolean}
|
|
537
|
+
*/
|
|
538
|
+
function failsClosedSets(ac) {
|
|
539
|
+
const descRaw = ac && typeof ac === 'object' ? /** @type {any} */ (ac).description : null;
|
|
540
|
+
if (typeof descRaw !== 'string' || descRaw.length === 0) return false;
|
|
541
|
+
if (acHasOwnerRef(ac)) return false;
|
|
542
|
+
const descNoClass = descRaw.replace(AC_CLASS_RE, '').trim();
|
|
543
|
+
if (INLINE_LIST_RE.test(descNoClass)) return false;
|
|
544
|
+
const descForCues = stripQuotedSubstrings(descNoClass);
|
|
545
|
+
for (const re of CLOSED_SET_CUE_RES) {
|
|
546
|
+
if (re.test(descForCues)) return true;
|
|
547
|
+
}
|
|
548
|
+
return false;
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
/**
|
|
552
|
+
* Parse an `interfaces[<name>]` field pointer into its interface
|
|
553
|
+
* name. Accepts any non-empty name between the brackets (interface
|
|
554
|
+
* names routinely carry dots, slashes and spaces); returns null for
|
|
555
|
+
* an unparseable pointer.
|
|
556
|
+
*
|
|
557
|
+
* @param {unknown} field
|
|
558
|
+
* @returns {string | null}
|
|
559
|
+
*/
|
|
560
|
+
function parseOwnerRefInterfaceField(field) {
|
|
561
|
+
if (typeof field !== 'string') return null;
|
|
562
|
+
const m = field.match(/^interfaces\[([^\]\n]+)\]$/);
|
|
563
|
+
return m ? m[1] : null;
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
/**
|
|
567
|
+
* R11 field grammar (spec section 17, 2026-10-03). An `ownerRef` or
|
|
568
|
+
* object-form `deliveredBy` `{ tacId | adrId, field }` resolves when
|
|
569
|
+
* `field` names an existing field path on the owning document in
|
|
570
|
+
* bracket grammar:
|
|
571
|
+
*
|
|
572
|
+
* - `interfaces[<name>]` resolves when `doc.interfaces[].name` matches.
|
|
573
|
+
* - `responsibilities[<n>]` resolves when `doc.responsibilities[n]`
|
|
574
|
+
* exists (non-negative integer index, zero-based).
|
|
575
|
+
* - `dependencies[<name>]` resolves when `doc.dependencies[].name` matches.
|
|
576
|
+
* - `alternativesConsidered[<n>]` resolves when the ADR has an
|
|
577
|
+
* alternative at that index.
|
|
578
|
+
* - A bare schema field name (`purpose`, `internalStructure`,
|
|
579
|
+
* `decision`, `name`, `context`, `consequences`, `tradeoffs`,
|
|
580
|
+
* `notes`, `description`, `responsibilities`, `dependencies`,
|
|
581
|
+
* `interfaces`, `alternativesConsidered`) resolves when the
|
|
582
|
+
* document carries a non-empty value under that key.
|
|
583
|
+
*
|
|
584
|
+
* Dotted grammar (`interfaces.name`, `responsibilities.foo`) is NOT
|
|
585
|
+
* accepted: callers of the R11 widening MUST rewrite to bracket
|
|
586
|
+
* grammar first. A path that does not match any arm returns false.
|
|
587
|
+
*
|
|
588
|
+
* `AC-17405-2` is unchanged in effect: `interfaces[loan]` on a TAC
|
|
589
|
+
* carrying an interface named `loan` resolves; `interfaces[missing]`
|
|
590
|
+
* fails.
|
|
591
|
+
*
|
|
592
|
+
* @param {unknown} doc - the owning TAC or ADR document.
|
|
593
|
+
* @param {unknown} field - the ownerRef/deliveredBy field string.
|
|
594
|
+
* @returns {boolean}
|
|
595
|
+
*/
|
|
596
|
+
export function resolveOwnerRefField(doc, field) {
|
|
597
|
+
if (!doc || typeof doc !== 'object') return false;
|
|
598
|
+
if (typeof field !== 'string' || field.length === 0) return false;
|
|
599
|
+
const d = /** @type {any} */ (doc);
|
|
600
|
+
// interfaces[<name>] -- preserved from the 0.29.0 helper.
|
|
601
|
+
const ifaceMatch = field.match(/^interfaces\[([^\]\n]+)\]$/);
|
|
602
|
+
if (ifaceMatch) {
|
|
603
|
+
const name = ifaceMatch[1];
|
|
604
|
+
return Array.isArray(d.interfaces)
|
|
605
|
+
&& d.interfaces.some((iface) => iface && typeof iface === 'object' && iface.name === name);
|
|
606
|
+
}
|
|
607
|
+
// dependencies[<name>] (TAC.dependencies[].name).
|
|
608
|
+
const depMatch = field.match(/^dependencies\[([^\]\n]+)\]$/);
|
|
609
|
+
if (depMatch) {
|
|
610
|
+
const name = depMatch[1];
|
|
611
|
+
return Array.isArray(d.dependencies)
|
|
612
|
+
&& d.dependencies.some((dep) => dep && typeof dep === 'object' && dep.name === name);
|
|
613
|
+
}
|
|
614
|
+
// responsibilities[<n>] (zero-based integer index on the strings array).
|
|
615
|
+
const respMatch = field.match(/^responsibilities\[(\d+)\]$/);
|
|
616
|
+
if (respMatch) {
|
|
617
|
+
const idx = Number(respMatch[1]);
|
|
618
|
+
return Array.isArray(d.responsibilities) && idx < d.responsibilities.length
|
|
619
|
+
&& typeof d.responsibilities[idx] === 'string'
|
|
620
|
+
&& d.responsibilities[idx].length > 0;
|
|
621
|
+
}
|
|
622
|
+
// alternativesConsidered[<n>] (ADR).
|
|
623
|
+
const altMatch = field.match(/^alternativesConsidered\[(\d+)\]$/);
|
|
624
|
+
if (altMatch) {
|
|
625
|
+
const idx = Number(altMatch[1]);
|
|
626
|
+
return Array.isArray(d.alternativesConsidered) && idx < d.alternativesConsidered.length
|
|
627
|
+
&& d.alternativesConsidered[idx] && typeof d.alternativesConsidered[idx] === 'object';
|
|
628
|
+
}
|
|
629
|
+
// Bare schema field name. Must be in the TAC/ADR schema and present
|
|
630
|
+
// and non-empty on the document. The accepted set covers the schema
|
|
631
|
+
// fields the spec names and the extras TAC/ADR carry; a field name
|
|
632
|
+
// outside the set returns false.
|
|
633
|
+
const BARE_FIELDS = new Set([
|
|
634
|
+
// TAC fields.
|
|
635
|
+
'purpose', 'internalStructure', 'tradeoffs', 'notes', 'name',
|
|
636
|
+
'responsibilities', 'interfaces', 'dependencies',
|
|
637
|
+
// ADR fields.
|
|
638
|
+
'decision', 'context', 'consequences', 'title',
|
|
639
|
+
'alternativesConsidered',
|
|
640
|
+
// Common.
|
|
641
|
+
'description',
|
|
642
|
+
]);
|
|
643
|
+
if (!BARE_FIELDS.has(field)) return false;
|
|
644
|
+
const v = d[field];
|
|
645
|
+
if (v == null) return false;
|
|
646
|
+
if (typeof v === 'string') return v.length > 0;
|
|
647
|
+
if (Array.isArray(v)) return v.length > 0;
|
|
648
|
+
if (typeof v === 'object') return Object.keys(v).length > 0;
|
|
649
|
+
return true;
|
|
650
|
+
}
|
|
651
|
+
|
|
127
652
|
/**
|
|
128
653
|
* Parse the leading bracketed class marker on `ac.description`.
|
|
129
654
|
* Returns the class token, or null when no marker is present.
|
|
@@ -156,12 +681,26 @@ export function parseAcClass(ac) {
|
|
|
156
681
|
* twentieth failure. `ok` is likewise derived from the untruncated
|
|
157
682
|
* count. The section 2.4 shape stays intact -- `failing` remains the
|
|
158
683
|
* display array; no new field is exported.
|
|
159
|
-
* @returns {{ name: string, ok: boolean, over: 'delta'|'tree', pass: number, total: number, failing: Array<{ id: string, why: string }
|
|
684
|
+
* @returns {{ name: string, ok: boolean, over: 'delta'|'tree', pass: number, total: number, failing: Array<{ id: string, why: string }>, persona: 'productOwner'|'engineer', question: string }}
|
|
160
685
|
*/
|
|
161
686
|
function makeCheck(name, over, total, failing, totalFailingCount) {
|
|
162
687
|
const nFailing = typeof totalFailingCount === 'number' ? totalFailingCount : failing.length;
|
|
163
688
|
const pass = Math.max(0, total - nFailing);
|
|
164
|
-
|
|
689
|
+
// Resolve persona + question for the check. For stage placeholders
|
|
690
|
+
// (`stage:<D>:scope`) the persona comes from STAGE_FALLBACK_PERSONA.
|
|
691
|
+
// Unknown names fall back to engineer with an empty question so
|
|
692
|
+
// consumers never see null; the table test catches any new check
|
|
693
|
+
// that forgets to register in CHECK_PERSONA / CHECK_QUESTION.
|
|
694
|
+
let persona = /** @type {any} */ (CHECK_PERSONA)[name];
|
|
695
|
+
if (!persona) {
|
|
696
|
+
const stageMatch = /^stage:(D[1-8]):scope$/.exec(name);
|
|
697
|
+
persona = stageMatch
|
|
698
|
+
? /** @type {any} */ (STAGE_FALLBACK_PERSONA)[stageMatch[1]]
|
|
699
|
+
: 'engineer';
|
|
700
|
+
}
|
|
701
|
+
const question = /** @type {any} */ (CHECK_QUESTION)[name]
|
|
702
|
+
?? (name.startsWith('stage:') ? 'No documents of this stage’s type are in scope.' : '');
|
|
703
|
+
return { name, ok: nFailing === 0, over, pass, total, failing: [...failing], persona, question };
|
|
165
704
|
}
|
|
166
705
|
|
|
167
706
|
/**
|
|
@@ -232,6 +771,11 @@ function asSet(scope) {
|
|
|
232
771
|
* @property {{ skipReviewFor?: string } | undefined} profile parsed profile switches (light shape)
|
|
233
772
|
* @property {string | null | undefined} currentTreeHash for warn-with-ack acknowledgement match
|
|
234
773
|
* @property {Array<{ state: string }> | undefined} priorStages D8 reads earlier stage states from this
|
|
774
|
+
* @property {Set<string> | undefined} resolvedPaths ADR-4131 (0.30.0 PR 5): set of repo-relative paths the CLI
|
|
775
|
+
* already resolved on disk; `shapes:pathsResolve` reads this to decide
|
|
776
|
+
* whether a `path:` token on an interface description resolves. Empty or
|
|
777
|
+
* undefined means no path is known-resolved, so every candidate token
|
|
778
|
+
* fails unless the interface description carries `authoredAt: D3`.
|
|
235
779
|
*/
|
|
236
780
|
|
|
237
781
|
/**
|
|
@@ -342,57 +886,68 @@ export function checkD2Skeleton(ctx) {
|
|
|
342
886
|
|
|
343
887
|
const checks = [];
|
|
344
888
|
|
|
345
|
-
// Check 1: every capability/constraint/entity/... statement
|
|
346
|
-
//
|
|
347
|
-
//
|
|
348
|
-
//
|
|
349
|
-
|
|
889
|
+
// Check 1 (0.30.0): every capability/constraint/entity/... statement
|
|
890
|
+
// resolves to a closed-grammar pointer in `resolvedBy`:
|
|
891
|
+
// REQ-nnn | TAD.entity:<name> | PRD.user:<name>
|
|
892
|
+
// | TAD.system:<name> | TAC-nnnn | omitted:<reason>
|
|
893
|
+
// The 0.29.0 REQ-title fallback is dropped (decision 3; a title hit
|
|
894
|
+
// becomes a suggestion the PR 2 computeQuestions surface returns).
|
|
895
|
+
// A statement with no `resolvedBy` fails; a statement with a
|
|
896
|
+
// `resolvedBy` outside the grammar fails with 'pointer does not
|
|
897
|
+
// resolve'.
|
|
898
|
+
/** @type {Array<{ id: string, why: string }>} */
|
|
899
|
+
const unresolvedFailing = [];
|
|
900
|
+
for (const s of resolvingStmts) {
|
|
350
901
|
const rb = s?.resolvedBy;
|
|
351
|
-
if (typeof rb
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
}
|
|
359
|
-
|
|
360
|
-
};
|
|
361
|
-
const unresolvedStmts = resolvingStmts.filter((s) => !resolvedByStmt(s));
|
|
902
|
+
if (typeof rb !== 'string' || rb.length === 0) {
|
|
903
|
+
unresolvedFailing.push({ id: `brief:${s.id}`, why: `${s.kind} statement has no resolvedBy` });
|
|
904
|
+
continue;
|
|
905
|
+
}
|
|
906
|
+
const parsed = parseResolvedBy(rb, tree);
|
|
907
|
+
if (!parsed.ok) {
|
|
908
|
+
unresolvedFailing.push({ id: `brief:${s.id}`, why: 'pointer does not resolve' });
|
|
909
|
+
}
|
|
910
|
+
}
|
|
362
911
|
checks.push(makeCheck(
|
|
363
912
|
'skeleton:resolvedBy',
|
|
364
913
|
'delta',
|
|
365
914
|
resolvingStmts.length,
|
|
366
|
-
|
|
915
|
+
unresolvedFailing,
|
|
367
916
|
));
|
|
368
917
|
|
|
369
|
-
//
|
|
918
|
+
// Checks 2a / 2b: the former `skeleton:reqFields` split into two
|
|
919
|
+
// homogeneous checks (ADR-4126, proposal section 1.3). Each
|
|
920
|
+
// evaluates every REQ in scope independently so a REQ with a TODO
|
|
921
|
+
// description still has its shapes reported, and vice versa.
|
|
922
|
+
const reqIntentFail = [];
|
|
370
923
|
const reqShapeFail = [];
|
|
371
924
|
for (const req of reqInScope) {
|
|
925
|
+
// reqIntent (productOwner): description without a TODO + domain
|
|
926
|
+
// (what the requirement means and where it sits).
|
|
372
927
|
if (typeof req.description !== 'string' || req.description.length === 0 || TODO_RE.test(req.description)) {
|
|
373
|
-
|
|
374
|
-
|
|
928
|
+
reqIntentFail.push({ id: req.reqId, why: 'description missing or contains TODO placeholder' });
|
|
929
|
+
} else if (typeof req.domain !== 'string' || req.domain.length === 0) {
|
|
930
|
+
reqIntentFail.push({ id: req.reqId, why: 'domain missing' });
|
|
375
931
|
}
|
|
932
|
+
// reqShape (engineer): shapeClassification.shapes classification.
|
|
376
933
|
if (!req.shapeClassification || !Array.isArray(req.shapeClassification.shapes)) {
|
|
377
934
|
reqShapeFail.push({ id: req.reqId, why: 'shapeClassification.shapes missing' });
|
|
378
|
-
continue;
|
|
379
|
-
}
|
|
380
|
-
if (typeof req.domain !== 'string' || req.domain.length === 0) {
|
|
381
|
-
reqShapeFail.push({ id: req.reqId, why: 'domain missing' });
|
|
382
935
|
}
|
|
383
936
|
}
|
|
384
|
-
checks.push(makeCheck('skeleton:
|
|
937
|
+
checks.push(makeCheck('skeleton:reqIntent', 'delta', reqInScope.length, reqIntentFail));
|
|
938
|
+
checks.push(makeCheck('skeleton:reqShape', 'delta', reqInScope.length, reqShapeFail));
|
|
385
939
|
|
|
386
|
-
// Check 3: TAD.dataStores + coreEntities present when any
|
|
940
|
+
// Check 3: TAD.dataArchitecture.dataStores + coreEntities present when any
|
|
387
941
|
// REQ exists tree-wide.
|
|
388
942
|
const persistenceReq = (tree.requirements ?? []).some((r) => Array.isArray(r?.shapeClassification?.shapes) && r.shapeClassification.shapes.includes('persistence'));
|
|
389
943
|
const tadFail = [];
|
|
390
944
|
if (persistenceReq) {
|
|
391
945
|
const tad = tree.tad ?? {};
|
|
392
|
-
const
|
|
393
|
-
const
|
|
394
|
-
|
|
395
|
-
if (
|
|
946
|
+
const dataArch = tad?.dataArchitecture ?? {};
|
|
947
|
+
const dataStores = Array.isArray(dataArch.dataStores) ? dataArch.dataStores : [];
|
|
948
|
+
const coreEntities = Array.isArray(dataArch.coreEntities) ? dataArch.coreEntities : [];
|
|
949
|
+
if (dataStores.length === 0) tadFail.push({ id: 'TAD.dataArchitecture.dataStores', why: 'TAD.dataArchitecture.dataStores empty while persistence REQ exists' });
|
|
950
|
+
if (coreEntities.length === 0) tadFail.push({ id: 'TAD.dataArchitecture.coreEntities', why: 'TAD.dataArchitecture.coreEntities empty while persistence REQ exists' });
|
|
396
951
|
}
|
|
397
952
|
checks.push(makeCheck('skeleton:tadPersistence', 'tree', persistenceReq ? 2 : 0, tadFail));
|
|
398
953
|
|
|
@@ -407,6 +962,50 @@ export function checkD2Skeleton(ctx) {
|
|
|
407
962
|
else if (deployAdrs.length > 1) deployFail.push({ id: 'ADR:deploy', why: `${deployAdrs.length} Deploy ADRs found; expected exactly one` });
|
|
408
963
|
checks.push(makeCheck('skeleton:deployAdr', 'tree', 1, deployFail));
|
|
409
964
|
|
|
965
|
+
// Check 5 (0.30.0 PR 6): skeleton:standardsCited (engineer, over
|
|
966
|
+
// tree). Every standards pack registered through `rcf define
|
|
967
|
+
// standards` (manifest.standards[].slug) is cited in a REQ
|
|
968
|
+
// `rationale` or an ADR, or waived by a concern-ledger entry keyed
|
|
969
|
+
// `standards:<pack>`. Fail ids `standards:<pack>` with 'uncited and
|
|
970
|
+
// unwaived'. Citation is a case-sensitive substring match of the
|
|
971
|
+
// slug against each REQ.rationale and each ADR document (the ADR
|
|
972
|
+
// may name a pack in its title, context, decision or consequences;
|
|
973
|
+
// the serialised document is scanned once per ADR to cover every
|
|
974
|
+
// field). A waiver entry on the concern ledger reads `concern:
|
|
975
|
+
// 'standards:<pack>'` with disposition 'applied' or 'waived'.
|
|
976
|
+
const standardsList = Array.isArray(tree.manifest?.standards)
|
|
977
|
+
? /** @type {any[]} */ (tree.manifest.standards)
|
|
978
|
+
: [];
|
|
979
|
+
/** @type {Array<{ id: string, why: string }>} */
|
|
980
|
+
const standardsFail = [];
|
|
981
|
+
if (standardsList.length > 0) {
|
|
982
|
+
const reqRationales = (tree.requirements ?? [])
|
|
983
|
+
.map((r) => (typeof r?.rationale === 'string' ? r.rationale : ''))
|
|
984
|
+
.join('\n');
|
|
985
|
+
const adrDocs = (tree.adrs ?? []).map((a) => {
|
|
986
|
+
try { return JSON.stringify(a); } catch { return ''; }
|
|
987
|
+
}).join('\n');
|
|
988
|
+
const concernsBody = /** @type {any} */ (ctx.ledgers?.concerns);
|
|
989
|
+
const concernList = Array.isArray(concernsBody?.concerns) ? concernsBody.concerns : [];
|
|
990
|
+
const waiverSlugs = new Set();
|
|
991
|
+
for (const entry of concernList) {
|
|
992
|
+
if (!entry || typeof entry.concern !== 'string') continue;
|
|
993
|
+
const disposition = typeof entry.disposition === 'string' ? entry.disposition : null;
|
|
994
|
+
if (disposition !== 'applied' && disposition !== 'waived') continue;
|
|
995
|
+
const m = entry.concern.match(/^standards:(.+)$/);
|
|
996
|
+
if (m) waiverSlugs.add(m[1]);
|
|
997
|
+
}
|
|
998
|
+
for (const pack of standardsList) {
|
|
999
|
+
const slug = typeof pack?.slug === 'string' ? pack.slug : null;
|
|
1000
|
+
if (!slug) continue;
|
|
1001
|
+
if (waiverSlugs.has(slug)) continue;
|
|
1002
|
+
if (reqRationales.includes(slug)) continue;
|
|
1003
|
+
if (adrDocs.includes(slug)) continue;
|
|
1004
|
+
standardsFail.push({ id: `standards:${slug}`, why: 'uncited and unwaived' });
|
|
1005
|
+
}
|
|
1006
|
+
}
|
|
1007
|
+
checks.push(makeCheck('skeleton:standardsCited', 'tree', Math.max(standardsList.length, 1), standardsFail));
|
|
1008
|
+
|
|
410
1009
|
return foldState('D2', gate, checks, {
|
|
411
1010
|
currentTreeHash: ctx.currentTreeHash ?? null,
|
|
412
1011
|
freezeGates: /** @type {any} */ (ctx.freeze?.gates),
|
|
@@ -421,14 +1020,20 @@ export function checkD2Skeleton(ctx) {
|
|
|
421
1020
|
const INTERFACE_KINDS_SET = new Set(INTERFACE_KINDS);
|
|
422
1021
|
|
|
423
1022
|
/**
|
|
424
|
-
* D3 -- Interface contracts and shapes. 0.29.0 runs
|
|
425
|
-
* presence
|
|
1023
|
+
* D3 -- Interface contracts and shapes. 0.29.0 runs the cheap
|
|
1024
|
+
* presence, closed-vocabulary and draft-marker checks
|
|
1025
|
+
* (`shapes:draftSettled` per ADR-4126 scans the `[draft]` prefix).
|
|
1026
|
+
* REQ-188 (0.30.0): the draft marker extends to `TAC.purpose` and
|
|
1027
|
+
* `TAD.dataArchitecture.coreEntities[].description`; `shapes:draftSettled`
|
|
1028
|
+
* enumerates all three homes with ids `<tacId>:<name>`, `<tacId>`
|
|
1029
|
+
* and `TAD.entity:<name>` respectively. `tacHasInterface` and
|
|
1030
|
+
* `kindVocabulary` apply to drafts unchanged.
|
|
426
1031
|
*
|
|
427
1032
|
* SEAM 0.30: template markers per kind (recordShape.fields:, httpRoute
|
|
428
1033
|
* method/path/request/response/errors, fixture.instances:); entity-name
|
|
429
|
-
* join across TAD.coreEntities and TAC.interfaces[];
|
|
430
|
-
* `authoredAt` path resolution. Those add checks to this
|
|
431
|
-
* fold shape stays the same.
|
|
1034
|
+
* join across TAD.dataArchitecture.coreEntities and TAC.interfaces[];
|
|
1035
|
+
* ownerRef and `authoredAt` path resolution. Those add checks to this
|
|
1036
|
+
* stage; the fold shape stays the same.
|
|
432
1037
|
*
|
|
433
1038
|
* @param {StageContext} ctx
|
|
434
1039
|
*/
|
|
@@ -443,8 +1048,17 @@ export function checkD3Shapes(ctx) {
|
|
|
443
1048
|
return shapes.includes('httpApi') || shapes.includes('persistence') || shapes.includes('auth');
|
|
444
1049
|
});
|
|
445
1050
|
|
|
446
|
-
|
|
447
|
-
|
|
1051
|
+
// Core entities on TAD.dataArchitecture come from the whole tree,
|
|
1052
|
+
// not the scope: an entity's draft marker is a tree-wide draft home
|
|
1053
|
+
// (the engineer owns every entity in one place) and reporting it
|
|
1054
|
+
// under D3 does not depend on which TAC a change touched.
|
|
1055
|
+
const coreEntities = Array.isArray(tree.tad?.dataArchitecture?.coreEntities)
|
|
1056
|
+
? /** @type {any[]} */ (tree.tad.dataArchitecture.coreEntities)
|
|
1057
|
+
: [];
|
|
1058
|
+
const draftEntities = coreEntities.filter(parseCoreEntityDraft);
|
|
1059
|
+
|
|
1060
|
+
if (tacsInScope.length === 0 && shapedReqInScope.length === 0 && draftEntities.length === 0) {
|
|
1061
|
+
return notApplicable('D3', gate, 'no TAC, no shaped REQ (httpApi/persistence/auth) and no [draft] core entity in scope');
|
|
448
1062
|
}
|
|
449
1063
|
|
|
450
1064
|
const checks = [];
|
|
@@ -459,18 +1073,139 @@ export function checkD3Shapes(ctx) {
|
|
|
459
1073
|
));
|
|
460
1074
|
|
|
461
1075
|
// Check 2: every interface kind is in the closed vocabulary.
|
|
1076
|
+
// Check 3: no description across the three draft homes still
|
|
1077
|
+
// carries the `[draft]` marker. A draft shape is entry material
|
|
1078
|
+
// the agent pre-populates after L1; the engineer removes the
|
|
1079
|
+
// marker when the shape is settled. `tacHasInterface` and
|
|
1080
|
+
// `kindVocabulary` apply equally to drafts.
|
|
462
1081
|
let totalInterfaces = 0;
|
|
463
1082
|
const badKinds = [];
|
|
1083
|
+
const draftFindings = [];
|
|
464
1084
|
for (const tac of tacsInScope) {
|
|
1085
|
+
if (parseTacPurposeDraft(tac)) {
|
|
1086
|
+
draftFindings.push({ id: tac.tacId, why: 'draft TAC purpose pre-populated at L1, not yet settled' });
|
|
1087
|
+
}
|
|
465
1088
|
for (const iface of tac.interfaces ?? []) {
|
|
466
1089
|
totalInterfaces += 1;
|
|
467
1090
|
const kind = iface?.kind;
|
|
468
1091
|
if (typeof kind !== 'string' || !INTERFACE_KINDS_SET.has(kind)) {
|
|
469
1092
|
badKinds.push({ id: `${tac.tacId}:${iface?.name ?? '(unnamed)'}`, why: `unknown interface kind ${JSON.stringify(kind)}` });
|
|
470
1093
|
}
|
|
1094
|
+
if (parseInterfaceDraft(iface)) {
|
|
1095
|
+
draftFindings.push({ id: `${tac.tacId}:${iface?.name ?? '(unnamed)'}`, why: 'draft interface pre-populated at L1, not yet settled' });
|
|
1096
|
+
}
|
|
471
1097
|
}
|
|
472
1098
|
}
|
|
1099
|
+
for (const entity of draftEntities) {
|
|
1100
|
+
draftFindings.push({ id: `TAD.entity:${entity?.name ?? '(unnamed)'}`, why: 'draft core entity pre-populated at L1, not yet settled' });
|
|
1101
|
+
}
|
|
1102
|
+
// Total for the draft check is every draft home that could carry
|
|
1103
|
+
// the marker on an in-scope TAC plus every core entity (tree-wide):
|
|
1104
|
+
// the TAC itself (its purpose) + every interface on it, plus the
|
|
1105
|
+
// coreEntities list.
|
|
1106
|
+
const totalDraftHomes = tacsInScope.length + totalInterfaces + coreEntities.length;
|
|
473
1107
|
checks.push(makeCheck('shapes:kindVocabulary', 'delta', totalInterfaces, badKinds));
|
|
1108
|
+
checks.push(makeCheck('shapes:draftSettled', 'delta', totalDraftHomes, draftFindings));
|
|
1109
|
+
|
|
1110
|
+
// ADR-4131 (0.30.0 PR 5): three D3 bite checks follow.
|
|
1111
|
+
// Check 4: shapes:templateMarkers (engineer, over delta). For every
|
|
1112
|
+
// interface on an in-scope TAC, parseInterfaceTemplate reports which
|
|
1113
|
+
// per-kind markers are missing from the description; a draft marker
|
|
1114
|
+
// is stripped before the scan so a [draft] recordShape without
|
|
1115
|
+
// `fields:` fails exactly as a settled one. An interface whose kind
|
|
1116
|
+
// is outside INTERFACE_KINDS is left to shapes:kindVocabulary (the
|
|
1117
|
+
// marker map returns `{missing: []}` for an unknown kind so this
|
|
1118
|
+
// check does not double-report the vocabulary miss).
|
|
1119
|
+
/** @type {Array<{ id: string, why: string }>} */
|
|
1120
|
+
const templateFindings = [];
|
|
1121
|
+
for (const tac of tacsInScope) {
|
|
1122
|
+
for (const iface of tac.interfaces ?? []) {
|
|
1123
|
+
const result = parseInterfaceTemplate(iface);
|
|
1124
|
+
if (!result.kind) continue;
|
|
1125
|
+
for (const marker of result.missing) {
|
|
1126
|
+
templateFindings.push({
|
|
1127
|
+
id: `${tac.tacId}:${iface?.name ?? '(unnamed)'}`,
|
|
1128
|
+
why: `missing marker ${marker}`,
|
|
1129
|
+
});
|
|
1130
|
+
}
|
|
1131
|
+
}
|
|
1132
|
+
}
|
|
1133
|
+
checks.push(makeCheck('shapes:templateMarkers', 'delta', totalInterfaces, templateFindings));
|
|
1134
|
+
|
|
1135
|
+
// Check 5: shapes:entityJoin (engineer, over tree). Every entry in
|
|
1136
|
+
// TAD.dataArchitecture.coreEntities must be named by exactly one
|
|
1137
|
+
// recordShape across the whole tree (not just the delta scope),
|
|
1138
|
+
// matching on the recordShape's `name` field or on an `entity:` line
|
|
1139
|
+
// in its description. A `[draft]` prefix is stripped before the
|
|
1140
|
+
// entity-line scan so a draft recordShape still joins.
|
|
1141
|
+
/** @type {Array<{ id: string, why: string }>} */
|
|
1142
|
+
const joinFindings = [];
|
|
1143
|
+
const treeTacs = tree.tacs ?? [];
|
|
1144
|
+
const recordShapesByEntity = new Map();
|
|
1145
|
+
for (const tac of treeTacs) {
|
|
1146
|
+
for (const iface of tac.interfaces ?? []) {
|
|
1147
|
+
if (iface?.kind !== 'recordShape') continue;
|
|
1148
|
+
const ownerLabel = `${tac.tacId}:${iface?.name ?? '(unnamed)'}`;
|
|
1149
|
+
const names = new Set();
|
|
1150
|
+
if (typeof iface?.name === 'string') names.add(iface.name);
|
|
1151
|
+
const desc = typeof iface?.description === 'string' ? stripDraftPrefix(iface.description) : '';
|
|
1152
|
+
const entityRe = /(^|\n)\s*(?:[-*]\s*)?entity\s*[:=]\s*["'`]?([A-Za-z_][A-Za-z0-9_]*)/g;
|
|
1153
|
+
let em;
|
|
1154
|
+
while ((em = entityRe.exec(desc)) !== null) {
|
|
1155
|
+
if (em[2]) names.add(em[2]);
|
|
1156
|
+
}
|
|
1157
|
+
for (const name of names) {
|
|
1158
|
+
const owners = recordShapesByEntity.get(name) ?? [];
|
|
1159
|
+
owners.push(ownerLabel);
|
|
1160
|
+
recordShapesByEntity.set(name, owners);
|
|
1161
|
+
}
|
|
1162
|
+
}
|
|
1163
|
+
}
|
|
1164
|
+
for (const entity of coreEntities) {
|
|
1165
|
+
const name = typeof entity?.name === 'string' ? entity.name : null;
|
|
1166
|
+
if (!name) continue;
|
|
1167
|
+
const owners = recordShapesByEntity.get(name) ?? [];
|
|
1168
|
+
if (owners.length === 0) {
|
|
1169
|
+
joinFindings.push({ id: `TAD.entity:${name}`, why: 'no record shape' });
|
|
1170
|
+
} else if (owners.length > 1) {
|
|
1171
|
+
joinFindings.push({ id: `TAD.entity:${name}`, why: `${owners.length} record shapes` });
|
|
1172
|
+
}
|
|
1173
|
+
}
|
|
1174
|
+
checks.push(makeCheck('shapes:entityJoin', 'tree', coreEntities.length, joinFindings));
|
|
1175
|
+
|
|
1176
|
+
// Check 6: shapes:pathsResolve (engineer, over delta). Any path:
|
|
1177
|
+
// token on an in-scope interface description must either resolve
|
|
1178
|
+
// against `resolvedPaths` (the CLI's on-disk pass) or the
|
|
1179
|
+
// description must carry an `authoredAt: D3` marker (the engineer
|
|
1180
|
+
// owns the path even when the file is yet to land). The marker is
|
|
1181
|
+
// a token in the description text (`authoredAt: D3` or
|
|
1182
|
+
// `authoredAt = D3`), not a separate schema field; the TAC schema
|
|
1183
|
+
// keeps interfaces to { name, kind, description }. Over delta,
|
|
1184
|
+
// one failing entry per unresolved (tacId:name, path) pair.
|
|
1185
|
+
const resolvedPaths = ctx.resolvedPaths instanceof Set ? ctx.resolvedPaths : new Set();
|
|
1186
|
+
/** @type {Array<{ id: string, why: string }>} */
|
|
1187
|
+
const pathFindings = [];
|
|
1188
|
+
let totalPathChecks = 0;
|
|
1189
|
+
for (const tac of tacsInScope) {
|
|
1190
|
+
for (const iface of tac.interfaces ?? []) {
|
|
1191
|
+
const desc = typeof iface?.description === 'string' ? iface.description : '';
|
|
1192
|
+
const tokens = extractInterfacePathTokens(desc);
|
|
1193
|
+
if (tokens.length === 0) continue;
|
|
1194
|
+
const authoredAtD3 = /\bauthoredAt\s*[:=]\s*["'`]?D3\b/.test(stripDraftPrefix(desc));
|
|
1195
|
+
for (const token of tokens) {
|
|
1196
|
+
totalPathChecks += 1;
|
|
1197
|
+
if (authoredAtD3) continue;
|
|
1198
|
+
if (resolvedPaths.has(token)) continue;
|
|
1199
|
+
pathFindings.push({
|
|
1200
|
+
id: `${tac.tacId}:${iface?.name ?? '(unnamed)'}`,
|
|
1201
|
+
why: `path does not resolve: ${token}`,
|
|
1202
|
+
});
|
|
1203
|
+
}
|
|
1204
|
+
}
|
|
1205
|
+
}
|
|
1206
|
+
// Keep total >= 1 so the chip prints a sensible ratio when no
|
|
1207
|
+
// interface in scope names a path.
|
|
1208
|
+
checks.push(makeCheck('shapes:pathsResolve', 'delta', Math.max(totalPathChecks, 1), pathFindings));
|
|
474
1209
|
|
|
475
1210
|
return foldState('D3', gate, checks, {
|
|
476
1211
|
currentTreeHash: ctx.currentTreeHash ?? null,
|
|
@@ -551,6 +1286,72 @@ export function checkD4Stories(ctx) {
|
|
|
551
1286
|
}
|
|
552
1287
|
checks.push(makeCheck('stories:usFloors', 'delta', usInScope.length, usFail));
|
|
553
1288
|
|
|
1289
|
+
// Check 3 (0.30.0 PR 6): stories:closedSets (engineer, over delta).
|
|
1290
|
+
// Every AC on a US in scope whose description contains an enumeration
|
|
1291
|
+
// cue (one of | any of | the following | types of | status is)
|
|
1292
|
+
// without an inline bracketed list of two or more tokens AND without
|
|
1293
|
+
// an ownerRef fails. The quoted-cue guard strips `"..."` substrings
|
|
1294
|
+
// before the cue scan so prose that quotes a cue does not fire the
|
|
1295
|
+
// check.
|
|
1296
|
+
/** @type {Array<{ id: string, why: string }>} */
|
|
1297
|
+
const closedSetFindings = [];
|
|
1298
|
+
let totalClosedSetAcs = 0;
|
|
1299
|
+
for (const us of usInScope) {
|
|
1300
|
+
const acs = Array.isArray(us.acceptanceCriteria) ? us.acceptanceCriteria : [];
|
|
1301
|
+
for (const ac of acs) {
|
|
1302
|
+
if (typeof ac?.description !== 'string' || ac.description.length === 0) continue;
|
|
1303
|
+
totalClosedSetAcs += 1;
|
|
1304
|
+
if (failsClosedSets(ac)) {
|
|
1305
|
+
closedSetFindings.push({
|
|
1306
|
+
id: ac.id ?? us.usId,
|
|
1307
|
+
why: 'enumeration cue without a closed set',
|
|
1308
|
+
});
|
|
1309
|
+
}
|
|
1310
|
+
}
|
|
1311
|
+
}
|
|
1312
|
+
checks.push(makeCheck('stories:closedSets', 'delta', totalClosedSetAcs, closedSetFindings));
|
|
1313
|
+
|
|
1314
|
+
// Check 4 (0.30.0 PR 6): stories:ownerRefResolves (engineer, over
|
|
1315
|
+
// delta plus tree for ownerRef targets). Every AC on a US in scope
|
|
1316
|
+
// whose ownerRef is set must point to an interface by name on the
|
|
1317
|
+
// named TAC. Ids `<acId>:<field>`; why 'ownerRef does not resolve'.
|
|
1318
|
+
/** @type {Array<{ id: string, why: string }>} */
|
|
1319
|
+
const ownerRefFindings = [];
|
|
1320
|
+
let totalOwnerRefAcs = 0;
|
|
1321
|
+
// R11 (spec section 17, 2026-10-03): the ownerRef field grammar
|
|
1322
|
+
// widens beyond `interfaces[<name>]` to every bracket-grammar path
|
|
1323
|
+
// that names an existing field on the owning TAC or ADR. The owner
|
|
1324
|
+
// may now be a TAC (via tacId) or an ADR (via adrId); the resolver
|
|
1325
|
+
// handles the bracket forms (`interfaces[<name>]`,
|
|
1326
|
+
// `responsibilities[<n>]`, `dependencies[<name>]`,
|
|
1327
|
+
// `alternativesConsidered[<n>]`) and bare schema fields (`purpose`,
|
|
1328
|
+
// `internalStructure`, `decision`, etc.). A path that does not
|
|
1329
|
+
// match any arm still fails. AC-17405-2 is unchanged in effect.
|
|
1330
|
+
for (const us of usInScope) {
|
|
1331
|
+
const acs = Array.isArray(us.acceptanceCriteria) ? us.acceptanceCriteria : [];
|
|
1332
|
+
for (const ac of acs) {
|
|
1333
|
+
if (!acHasOwnerRef(ac)) continue;
|
|
1334
|
+
totalOwnerRefAcs += 1;
|
|
1335
|
+
const ref = /** @type {any} */ (ac).ownerRef;
|
|
1336
|
+
let owner = null;
|
|
1337
|
+
if (typeof ref.tacId === 'string') {
|
|
1338
|
+
owner = (tree.tacs ?? []).find((t) => t?.tacId === ref.tacId) ?? null;
|
|
1339
|
+
} else if (typeof ref.adrId === 'string') {
|
|
1340
|
+
owner = (tree.adrs ?? []).find((a) => a?.adrId === ref.adrId) ?? null;
|
|
1341
|
+
}
|
|
1342
|
+
const resolves = !!(owner && resolveOwnerRefField(owner, ref.field));
|
|
1343
|
+
if (!resolves) {
|
|
1344
|
+
ownerRefFindings.push({
|
|
1345
|
+
id: `${ac.id ?? us.usId}:${ref.field ?? '(no field)'}`,
|
|
1346
|
+
why: 'ownerRef does not resolve',
|
|
1347
|
+
});
|
|
1348
|
+
}
|
|
1349
|
+
}
|
|
1350
|
+
}
|
|
1351
|
+
// Keep total >= 1 so the chip prints a sensible ratio when no AC in
|
|
1352
|
+
// scope carries an ownerRef.
|
|
1353
|
+
checks.push(makeCheck('stories:ownerRefResolves', 'delta', Math.max(totalOwnerRefAcs, 1), ownerRefFindings));
|
|
1354
|
+
|
|
554
1355
|
return foldState('D4', gate, checks, {
|
|
555
1356
|
currentTreeHash: ctx.currentTreeHash ?? null,
|
|
556
1357
|
freezeGates: /** @type {any} */ (ctx.freeze?.gates),
|
|
@@ -621,6 +1422,52 @@ export function checkD5Crosscut(ctx) {
|
|
|
621
1422
|
openInScope.map((c) => ({ id: `concern:${c.id}`, why: `open concern on ${c.reqId}: ${c.concern}` })),
|
|
622
1423
|
));
|
|
623
1424
|
|
|
1425
|
+
// Check 4 (0.30.0 PR 6): crosscut:catalogue (engineer, over tree).
|
|
1426
|
+
// For every REQ in scope, enumerate applicable (reqShape, concern)
|
|
1427
|
+
// pairs via src/define/concern-catalogue.js; each pair needs a
|
|
1428
|
+
// concern-ledger entry keyed <REQ>:<concern> with disposition
|
|
1429
|
+
// applied or waived (a waived entry carries a reason). Fail ids are
|
|
1430
|
+
// `<REQ>:<concern>`; the why names the missing concern. A waived
|
|
1431
|
+
// entry without a reason also fails. Keys shared with the baseline
|
|
1432
|
+
// catalogue where names coincide (today only `auth`).
|
|
1433
|
+
const entriesByKey = new Map();
|
|
1434
|
+
for (const entry of concernEntries) {
|
|
1435
|
+
if (!entry || typeof entry.reqId !== 'string' || typeof entry.concern !== 'string') continue;
|
|
1436
|
+
entriesByKey.set(`${entry.reqId}:${entry.concern}`, entry);
|
|
1437
|
+
}
|
|
1438
|
+
/** @type {Array<{ id: string, why: string }>} */
|
|
1439
|
+
const catalogueFindings = [];
|
|
1440
|
+
let totalCataloguePairs = 0;
|
|
1441
|
+
for (const req of reqInScope) {
|
|
1442
|
+
const shapes = Array.isArray(req?.shapeClassification?.shapes)
|
|
1443
|
+
? req.shapeClassification.shapes.filter((s) => typeof s === 'string')
|
|
1444
|
+
: [];
|
|
1445
|
+
const applicable = applicableConcernsForShapes(shapes);
|
|
1446
|
+
for (const concern of applicable) {
|
|
1447
|
+
totalCataloguePairs += 1;
|
|
1448
|
+
const key = `${req.reqId}:${concern}`;
|
|
1449
|
+
const entry = entriesByKey.get(key);
|
|
1450
|
+
if (!entry) {
|
|
1451
|
+
catalogueFindings.push({ id: key, why: `missing concern-ledger entry for ${concern}` });
|
|
1452
|
+
continue;
|
|
1453
|
+
}
|
|
1454
|
+
const disposition = typeof entry.disposition === 'string' ? entry.disposition : null;
|
|
1455
|
+
if (disposition !== 'applied' && disposition !== 'waived') {
|
|
1456
|
+
catalogueFindings.push({ id: key, why: `concern-ledger entry disposition is ${disposition ?? '(unset)'}` });
|
|
1457
|
+
continue;
|
|
1458
|
+
}
|
|
1459
|
+
if (disposition === 'waived') {
|
|
1460
|
+
const reason = typeof entry.reason === 'string' ? entry.reason.trim() : '';
|
|
1461
|
+
if (reason.length === 0) {
|
|
1462
|
+
catalogueFindings.push({ id: key, why: 'waived without a reason' });
|
|
1463
|
+
}
|
|
1464
|
+
}
|
|
1465
|
+
}
|
|
1466
|
+
}
|
|
1467
|
+
// Keep total >= 1 so the chip prints a sensible ratio when no REQ in
|
|
1468
|
+
// scope has applicable concerns (every REQ carries shape 'other').
|
|
1469
|
+
checks.push(makeCheck('crosscut:catalogue', 'tree', Math.max(totalCataloguePairs, 1), catalogueFindings));
|
|
1470
|
+
|
|
624
1471
|
return foldState('D5', gate, checks, {
|
|
625
1472
|
currentTreeHash: ctx.currentTreeHash ?? null,
|
|
626
1473
|
freezeGates: /** @type {any} */ (ctx.freeze?.gates),
|
|
@@ -632,14 +1479,14 @@ export function checkD5Crosscut(ctx) {
|
|
|
632
1479
|
// ---------------------------------------------------------------------------
|
|
633
1480
|
|
|
634
1481
|
/**
|
|
635
|
-
* D6 -- Consistency and satisfiability probe. 0.29.0
|
|
636
|
-
* validate-clean tree-wide check and the probe-ledger open count
|
|
637
|
-
*
|
|
638
|
-
*
|
|
639
|
-
*
|
|
640
|
-
*
|
|
641
|
-
*
|
|
642
|
-
*
|
|
1482
|
+
* D6 -- Consistency and satisfiability probe. 0.29.0 ran the
|
|
1483
|
+
* validate-clean tree-wide check and the probe-ledger open count;
|
|
1484
|
+
* 0.30.0 PR 7 (ADR-4131 extended, spec section 4 row 'D6 scans and the
|
|
1485
|
+
* injectable probe runner') adds the four mechanical scans
|
|
1486
|
+
* consistency:contradictions, consistency:unsatisfiable,
|
|
1487
|
+
* consistency:duplicates and consistency:orphanInterfaces. The probe
|
|
1488
|
+
* runner lives on the readiness compute (TAC-4123); the gate reads the
|
|
1489
|
+
* merged probes.probes[] it ends up with.
|
|
643
1490
|
*
|
|
644
1491
|
* @param {StageContext} ctx
|
|
645
1492
|
*/
|
|
@@ -683,12 +1530,350 @@ export function checkD6Consistency(ctx) {
|
|
|
683
1530
|
// uses a single representative entry regardless.
|
|
684
1531
|
checks.push(makeCheck('consistency:probeCount', 'tree', Math.max(effectiveOpen, 1), failing, effectiveOpen));
|
|
685
1532
|
|
|
1533
|
+
// ADR-4131 extended (0.30.0 PR 7): the four D6 scans.
|
|
1534
|
+
const scope = asSet(ctx.scope);
|
|
1535
|
+
const tree = ctx.tree;
|
|
1536
|
+
const usInScope = (tree.userStories ?? []).filter((us) => scope.has(us.usId));
|
|
1537
|
+
|
|
1538
|
+
// Scan 1: consistency:contradictions (engineer, over delta). Two ACs
|
|
1539
|
+
// on one story share a `when` clause and one of their `then` clauses
|
|
1540
|
+
// is a negation of the other. The quoted-cue guard strips
|
|
1541
|
+
// double-quoted substrings before the negation scan so prose that
|
|
1542
|
+
// quotes a negation inside a `then` does not fire the check.
|
|
1543
|
+
/** @type {Array<{ id: string, why: string }>} */
|
|
1544
|
+
const contradictionFindings = [];
|
|
1545
|
+
let totalStoriesScanned = 0;
|
|
1546
|
+
for (const us of usInScope) {
|
|
1547
|
+
const acs = Array.isArray(us.acceptanceCriteria) ? us.acceptanceCriteria : [];
|
|
1548
|
+
if (acs.length < 2) continue;
|
|
1549
|
+
totalStoriesScanned += 1;
|
|
1550
|
+
const parsed = acs
|
|
1551
|
+
.map((ac) => ({ ac, parts: parseWhenThen(ac?.description) }))
|
|
1552
|
+
.filter((p) => p.parts !== null);
|
|
1553
|
+
const reported = new Set();
|
|
1554
|
+
for (let i = 0; i < parsed.length; i += 1) {
|
|
1555
|
+
for (let j = i + 1; j < parsed.length; j += 1) {
|
|
1556
|
+
const a = parsed[i];
|
|
1557
|
+
const b = parsed[j];
|
|
1558
|
+
if (normaliseClause(a.parts.when) !== normaliseClause(b.parts.when)) continue;
|
|
1559
|
+
if (!thensNegateEachOther(a.parts.then, b.parts.then)) continue;
|
|
1560
|
+
const pairKey = `${us.usId}:${a.ac.id ?? '?'}:${b.ac.id ?? '?'}`;
|
|
1561
|
+
if (reported.has(pairKey)) continue;
|
|
1562
|
+
reported.add(pairKey);
|
|
1563
|
+
const idA = a.ac.id ?? us.usId;
|
|
1564
|
+
const idB = b.ac.id ?? us.usId;
|
|
1565
|
+
contradictionFindings.push({
|
|
1566
|
+
id: us.usId,
|
|
1567
|
+
why: `ACs ${idA} and ${idB} share a when clause with a negated then`,
|
|
1568
|
+
});
|
|
1569
|
+
}
|
|
1570
|
+
}
|
|
1571
|
+
}
|
|
1572
|
+
checks.push(makeCheck(
|
|
1573
|
+
'consistency:contradictions',
|
|
1574
|
+
'delta',
|
|
1575
|
+
Math.max(totalStoriesScanned, 1),
|
|
1576
|
+
contradictionFindings,
|
|
1577
|
+
));
|
|
1578
|
+
|
|
1579
|
+
// Scan 2: consistency:unsatisfiable (engineer, over delta). A `then`
|
|
1580
|
+
// naming a field that no recordShape anywhere in the tree defines
|
|
1581
|
+
// fails the AC with id `<acId>:<field>`. A field defined in a
|
|
1582
|
+
// `[draft]` recordShape counts as defined (the engineer owns the
|
|
1583
|
+
// draft; its `fields:` list is honest about what the then may name).
|
|
1584
|
+
const definedFields = collectRecordShapeFields(tree);
|
|
1585
|
+
/** @type {Array<{ id: string, why: string }>} */
|
|
1586
|
+
const unsatisfiableFindings = [];
|
|
1587
|
+
let totalThenFieldChecks = 0;
|
|
1588
|
+
for (const us of usInScope) {
|
|
1589
|
+
const acs = Array.isArray(us.acceptanceCriteria) ? us.acceptanceCriteria : [];
|
|
1590
|
+
for (const ac of acs) {
|
|
1591
|
+
const parts = parseWhenThen(ac?.description);
|
|
1592
|
+
if (!parts) continue;
|
|
1593
|
+
const fields = extractThenFieldTokens(parts.then);
|
|
1594
|
+
for (const field of fields) {
|
|
1595
|
+
totalThenFieldChecks += 1;
|
|
1596
|
+
if (definedFields.has(field)) continue;
|
|
1597
|
+
unsatisfiableFindings.push({
|
|
1598
|
+
id: `${ac.id ?? us.usId}:${field}`,
|
|
1599
|
+
why: `then names field ${field} that no recordShape defines`,
|
|
1600
|
+
});
|
|
1601
|
+
}
|
|
1602
|
+
}
|
|
1603
|
+
}
|
|
1604
|
+
checks.push(makeCheck(
|
|
1605
|
+
'consistency:unsatisfiable',
|
|
1606
|
+
'delta',
|
|
1607
|
+
Math.max(totalThenFieldChecks, 1),
|
|
1608
|
+
unsatisfiableFindings,
|
|
1609
|
+
));
|
|
1610
|
+
|
|
1611
|
+
// Scan 3: consistency:duplicates (engineer, over tree). Identical AC
|
|
1612
|
+
// descriptions across stories fail both ACs. The comparison trims
|
|
1613
|
+
// leading whitespace and the leading `[class]` marker.
|
|
1614
|
+
/** @type {Map<string, Array<{ usId: string, acId: string }>>} */
|
|
1615
|
+
const descBuckets = new Map();
|
|
1616
|
+
const allUs = tree.userStories ?? [];
|
|
1617
|
+
let totalDupAcs = 0;
|
|
1618
|
+
for (const us of allUs) {
|
|
1619
|
+
const acs = Array.isArray(us.acceptanceCriteria) ? us.acceptanceCriteria : [];
|
|
1620
|
+
for (const ac of acs) {
|
|
1621
|
+
const desc = typeof ac?.description === 'string' ? ac.description.trim() : '';
|
|
1622
|
+
if (desc.length === 0) continue;
|
|
1623
|
+
totalDupAcs += 1;
|
|
1624
|
+
const normalised = desc.replace(AC_CLASS_RE, '').trim().toLowerCase();
|
|
1625
|
+
if (normalised.length === 0) continue;
|
|
1626
|
+
const bucket = descBuckets.get(normalised) ?? [];
|
|
1627
|
+
bucket.push({ usId: us.usId, acId: ac.id ?? us.usId });
|
|
1628
|
+
descBuckets.set(normalised, bucket);
|
|
1629
|
+
}
|
|
1630
|
+
}
|
|
1631
|
+
/** @type {Array<{ id: string, why: string }>} */
|
|
1632
|
+
const duplicateFindings = [];
|
|
1633
|
+
for (const bucket of descBuckets.values()) {
|
|
1634
|
+
if (bucket.length < 2) continue;
|
|
1635
|
+
const stories = [...new Set(bucket.map((b) => b.usId))];
|
|
1636
|
+
if (stories.length < 2) continue;
|
|
1637
|
+
for (const entry of bucket) {
|
|
1638
|
+
duplicateFindings.push({
|
|
1639
|
+
id: entry.acId,
|
|
1640
|
+
why: `duplicate description (also on ${bucket.filter((b) => b.acId !== entry.acId).map((b) => b.acId).join(', ')})`,
|
|
1641
|
+
});
|
|
1642
|
+
}
|
|
1643
|
+
}
|
|
1644
|
+
checks.push(makeCheck(
|
|
1645
|
+
'consistency:duplicates',
|
|
1646
|
+
'tree',
|
|
1647
|
+
Math.max(totalDupAcs, 1),
|
|
1648
|
+
duplicateFindings,
|
|
1649
|
+
));
|
|
1650
|
+
|
|
1651
|
+
// Scan 4: consistency:orphanInterfaces (engineer, over tree). An
|
|
1652
|
+
// interface on any TAC that no AC `ownerRef` points at AND that no
|
|
1653
|
+
// REQ `deliveredBy` reaches fails. Shares the `interfaces[<name>]`
|
|
1654
|
+
// pointer grammar with D4 `stories:ownerRefResolves`. A REQ's
|
|
1655
|
+
// `deliveredBy` reaches an interface when it names the owning TAC id
|
|
1656
|
+
// (either as a `tacId` string or as a `TAC-nnnn:<name>` pointer).
|
|
1657
|
+
const reachedInterfaces = collectReachedInterfaces(tree);
|
|
1658
|
+
/** @type {Array<{ id: string, why: string }>} */
|
|
1659
|
+
const orphanFindings = [];
|
|
1660
|
+
let totalInterfacesScanned = 0;
|
|
1661
|
+
for (const tac of tree.tacs ?? []) {
|
|
1662
|
+
const list = Array.isArray(tac?.interfaces) ? tac.interfaces : [];
|
|
1663
|
+
for (const iface of list) {
|
|
1664
|
+
const name = typeof iface?.name === 'string' ? iface.name : null;
|
|
1665
|
+
if (!name) continue;
|
|
1666
|
+
totalInterfacesScanned += 1;
|
|
1667
|
+
const key = `${tac.tacId}:${name}`;
|
|
1668
|
+
if (reachedInterfaces.has(key)) continue;
|
|
1669
|
+
orphanFindings.push({
|
|
1670
|
+
id: key,
|
|
1671
|
+
why: 'no AC ownerRef and no REQ deliveredBy reaches it',
|
|
1672
|
+
});
|
|
1673
|
+
}
|
|
1674
|
+
}
|
|
1675
|
+
checks.push(makeCheck(
|
|
1676
|
+
'consistency:orphanInterfaces',
|
|
1677
|
+
'tree',
|
|
1678
|
+
Math.max(totalInterfacesScanned, 1),
|
|
1679
|
+
orphanFindings,
|
|
1680
|
+
));
|
|
1681
|
+
|
|
686
1682
|
return foldState('D6', gate, checks, {
|
|
687
1683
|
currentTreeHash: ctx.currentTreeHash ?? null,
|
|
688
1684
|
freezeGates: /** @type {any} */ (ctx.freeze?.gates),
|
|
689
1685
|
});
|
|
690
1686
|
}
|
|
691
1687
|
|
|
1688
|
+
/**
|
|
1689
|
+
* Parse an AC description into { when, then } clause strings. Accepts
|
|
1690
|
+
* the common "given ... when ... then ..." shape used across the ACs
|
|
1691
|
+
* of this codebase; returns null when the description does not carry
|
|
1692
|
+
* both a `when` and a `then` segment. The leading `[class]` marker is
|
|
1693
|
+
* stripped before the scan. The match is case-insensitive on the
|
|
1694
|
+
* keywords only; the clause bodies keep their original casing.
|
|
1695
|
+
*
|
|
1696
|
+
* @param {unknown} desc
|
|
1697
|
+
* @returns {{ when: string, then: string } | null}
|
|
1698
|
+
*/
|
|
1699
|
+
function parseWhenThen(desc) {
|
|
1700
|
+
if (typeof desc !== 'string' || desc.length === 0) return null;
|
|
1701
|
+
const stripped = desc.replace(AC_CLASS_RE, '').trim();
|
|
1702
|
+
const re = /\bwhen\b([\s\S]*?)\bthen\b([\s\S]*)$/i;
|
|
1703
|
+
const m = stripped.match(re);
|
|
1704
|
+
if (!m) return null;
|
|
1705
|
+
const when = m[1].trim();
|
|
1706
|
+
const then = m[2].trim();
|
|
1707
|
+
if (when.length === 0 || then.length === 0) return null;
|
|
1708
|
+
return { when, then };
|
|
1709
|
+
}
|
|
1710
|
+
|
|
1711
|
+
/**
|
|
1712
|
+
* Normalise a clause for the contradictions scan: lower-case, trim,
|
|
1713
|
+
* collapse whitespace. A clause is "the same" between two ACs when
|
|
1714
|
+
* their normalised forms match.
|
|
1715
|
+
*
|
|
1716
|
+
* @param {string} clause
|
|
1717
|
+
* @returns {string}
|
|
1718
|
+
*/
|
|
1719
|
+
function normaliseClause(clause) {
|
|
1720
|
+
return clause.toLowerCase().replace(/\s+/g, ' ').trim();
|
|
1721
|
+
}
|
|
1722
|
+
|
|
1723
|
+
/**
|
|
1724
|
+
* Strip double-quoted substrings and then test whether one `then`
|
|
1725
|
+
* clause is the negation of the other. "Negation" is a cheap test: one
|
|
1726
|
+
* clause begins (or carries, after a verb) a `not`, `no`, `does not`,
|
|
1727
|
+
* `is not`, `never`, `must not` token where the other clause does not;
|
|
1728
|
+
* or the two clauses are the same body with one carrying such a token.
|
|
1729
|
+
* The quoted-substring strip is the shared guard with D4.
|
|
1730
|
+
*
|
|
1731
|
+
* @param {string} a
|
|
1732
|
+
* @param {string} b
|
|
1733
|
+
* @returns {boolean}
|
|
1734
|
+
*/
|
|
1735
|
+
function thensNegateEachOther(a, b) {
|
|
1736
|
+
const aPlain = normaliseClause(stripQuotedSubstrings(a));
|
|
1737
|
+
const bPlain = normaliseClause(stripQuotedSubstrings(b));
|
|
1738
|
+
if (aPlain === bPlain) return false;
|
|
1739
|
+
const NEG_RE = /\b(?:not|no|never|does not|is not|must not|cannot|won't|will not)\b/;
|
|
1740
|
+
const aNeg = NEG_RE.test(aPlain);
|
|
1741
|
+
const bNeg = NEG_RE.test(bPlain);
|
|
1742
|
+
if (aNeg === bNeg) return false;
|
|
1743
|
+
// One side negates; test the negated body against the positive one.
|
|
1744
|
+
const positive = aNeg ? bPlain : aPlain;
|
|
1745
|
+
const negative = aNeg ? aPlain : bPlain;
|
|
1746
|
+
const negativeStripped = negative.replace(NEG_RE, '').replace(/\s+/g, ' ').trim();
|
|
1747
|
+
// A sufficiently similar body is "the same claim with a negation".
|
|
1748
|
+
// We treat the shorter being a prefix / suffix / substring of the
|
|
1749
|
+
// longer, or sharing 80% of its tokens, as "same body".
|
|
1750
|
+
if (negativeStripped.length === 0) return false;
|
|
1751
|
+
if (positive.includes(negativeStripped) || negativeStripped.includes(positive)) return true;
|
|
1752
|
+
const posTokens = new Set(positive.split(/\s+/).filter((t) => t.length > 2));
|
|
1753
|
+
const negTokens = negativeStripped.split(/\s+/).filter((t) => t.length > 2);
|
|
1754
|
+
if (negTokens.length === 0) return false;
|
|
1755
|
+
const shared = negTokens.filter((t) => posTokens.has(t)).length;
|
|
1756
|
+
return shared / negTokens.length >= 0.6;
|
|
1757
|
+
}
|
|
1758
|
+
|
|
1759
|
+
/**
|
|
1760
|
+
* Collect every field name defined by any `recordShape` interface in
|
|
1761
|
+
* the tree. A `fields:` marker in the interface description introduces
|
|
1762
|
+
* a list of field names; each name is a token on a bullet, a line, or
|
|
1763
|
+
* a comma-separated list. Draft recordShapes are included (the
|
|
1764
|
+
* engineer owns the draft and its fields: list is honest).
|
|
1765
|
+
*
|
|
1766
|
+
* @param {import('#core/store/walker.js').TreeModel} tree
|
|
1767
|
+
* @returns {Set<string>}
|
|
1768
|
+
*/
|
|
1769
|
+
function collectRecordShapeFields(tree) {
|
|
1770
|
+
const out = new Set();
|
|
1771
|
+
for (const tac of tree.tacs ?? []) {
|
|
1772
|
+
for (const iface of tac.interfaces ?? []) {
|
|
1773
|
+
if (iface?.kind !== 'recordShape') continue;
|
|
1774
|
+
const desc = typeof iface?.description === 'string' ? iface.description : '';
|
|
1775
|
+
const stripped = stripDraftPrefix(desc);
|
|
1776
|
+
// Find the `fields:` segment and read until the next `:` or end.
|
|
1777
|
+
const match = stripped.match(/(^|\n)\s*(?:[-*]\s*)?fields\s*:\s*([\s\S]*?)(?=(?:\n\s*(?:[-*]\s*)?[a-zA-Z][a-zA-Z0-9_]*\s*:)|$)/);
|
|
1778
|
+
if (!match) continue;
|
|
1779
|
+
const body = match[2];
|
|
1780
|
+
for (const token of body.split(/[\s,]+/)) {
|
|
1781
|
+
const name = token.replace(/^[-*]/, '').replace(/[:(){}\[\]]/g, '').trim();
|
|
1782
|
+
if (!name) continue;
|
|
1783
|
+
if (/^[A-Za-z_][A-Za-z0-9_]*$/.test(name)) out.add(name);
|
|
1784
|
+
}
|
|
1785
|
+
}
|
|
1786
|
+
}
|
|
1787
|
+
return out;
|
|
1788
|
+
}
|
|
1789
|
+
|
|
1790
|
+
/**
|
|
1791
|
+
* Pull field tokens out of a `then` clause. A field token is a word
|
|
1792
|
+
* that follows a verb like `set`, `write`, `include`, `return`,
|
|
1793
|
+
* `contain`, `name` or appears as the direct object of a `then`'s
|
|
1794
|
+
* verb phrase; a cheap approximation uses `then <subject> <verb>
|
|
1795
|
+
* <field>` plus `field <name>`, `<name> field` and `field: <name>`
|
|
1796
|
+
* patterns. The scan is deliberately conservative so a plain English
|
|
1797
|
+
* sentence yields a small set.
|
|
1798
|
+
*
|
|
1799
|
+
* @param {string} thenClause
|
|
1800
|
+
* @returns {string[]}
|
|
1801
|
+
*/
|
|
1802
|
+
function extractThenFieldTokens(thenClause) {
|
|
1803
|
+
if (typeof thenClause !== 'string' || thenClause.length === 0) return [];
|
|
1804
|
+
const text = stripQuotedSubstrings(thenClause);
|
|
1805
|
+
/** @type {Set<string>} */
|
|
1806
|
+
const tokens = new Set();
|
|
1807
|
+
// Pattern 1: backticked identifier (`then `balance` is set`). The
|
|
1808
|
+
// primary signal; prose that quotes a field name under backticks is
|
|
1809
|
+
// the convention this check expects.
|
|
1810
|
+
for (const m of text.matchAll(/`([A-Za-z_][A-Za-z0-9_]*)`/g)) {
|
|
1811
|
+
if (m[1]) tokens.add(m[1]);
|
|
1812
|
+
}
|
|
1813
|
+
// Pattern 2: `<name> field` (adjective-form naming). An English
|
|
1814
|
+
// "stop word" skip keeps "the field", "a field" and "its field" from
|
|
1815
|
+
// tripping the check.
|
|
1816
|
+
const STOP = new Set(['the', 'a', 'an', 'this', 'that', 'its', 'our', 'their', 'any', 'no', 'some', 'each', 'every', 'another']);
|
|
1817
|
+
for (const m of text.matchAll(/\b([A-Za-z_][A-Za-z0-9_]*)\s+field\b/g)) {
|
|
1818
|
+
const token = m[1];
|
|
1819
|
+
if (!token) continue;
|
|
1820
|
+
if (STOP.has(token.toLowerCase())) continue;
|
|
1821
|
+
tokens.add(token);
|
|
1822
|
+
}
|
|
1823
|
+
// Pattern 3: `field: <name>` or `field = <name>` (schema-like
|
|
1824
|
+
// notation inside a then clause).
|
|
1825
|
+
for (const m of text.matchAll(/\bfield\s*[:=]\s*([A-Za-z_][A-Za-z0-9_]*)/g)) {
|
|
1826
|
+
if (m[1]) tokens.add(m[1]);
|
|
1827
|
+
}
|
|
1828
|
+
return [...tokens];
|
|
1829
|
+
}
|
|
1830
|
+
|
|
1831
|
+
/**
|
|
1832
|
+
* Collect every interface the tree "reaches" from an AC `ownerRef` or
|
|
1833
|
+
* a REQ `deliveredBy` (REQ-174 companion field). The result is a Set
|
|
1834
|
+
* of `<tacId>:<name>` keys. A `deliveredBy` on a REQ can take two
|
|
1835
|
+
* shapes: an array of `TAC-nnnn:<name>` pointer strings, or an array
|
|
1836
|
+
* of plain TAC ids ("delivered by this TAC"); the second shape reaches
|
|
1837
|
+
* every interface on the named TAC.
|
|
1838
|
+
*
|
|
1839
|
+
* @param {import('#core/store/walker.js').TreeModel} tree
|
|
1840
|
+
* @returns {Set<string>}
|
|
1841
|
+
*/
|
|
1842
|
+
function collectReachedInterfaces(tree) {
|
|
1843
|
+
const out = new Set();
|
|
1844
|
+
// AC ownerRefs.
|
|
1845
|
+
for (const us of tree.userStories ?? []) {
|
|
1846
|
+
const acs = Array.isArray(us.acceptanceCriteria) ? us.acceptanceCriteria : [];
|
|
1847
|
+
for (const ac of acs) {
|
|
1848
|
+
if (!acHasOwnerRef(ac)) continue;
|
|
1849
|
+
const ref = /** @type {any} */ (ac).ownerRef;
|
|
1850
|
+
const name = parseOwnerRefInterfaceField(ref?.field);
|
|
1851
|
+
if (!name || typeof ref?.tacId !== 'string') continue;
|
|
1852
|
+
out.add(`${ref.tacId}:${name}`);
|
|
1853
|
+
}
|
|
1854
|
+
}
|
|
1855
|
+
// REQ deliveredBy (optional field; shapes above).
|
|
1856
|
+
for (const req of tree.requirements ?? []) {
|
|
1857
|
+
const deliveredBy = /** @type {any} */ (req)?.deliveredBy;
|
|
1858
|
+
if (!Array.isArray(deliveredBy)) continue;
|
|
1859
|
+
for (const entry of deliveredBy) {
|
|
1860
|
+
if (typeof entry !== 'string' || entry.length === 0) continue;
|
|
1861
|
+
const m = entry.match(/^(TAC-[A-Za-z0-9-]+):(.+)$/);
|
|
1862
|
+
if (m) {
|
|
1863
|
+
out.add(`${m[1]}:${m[2]}`);
|
|
1864
|
+
continue;
|
|
1865
|
+
}
|
|
1866
|
+
// Plain TAC id: every interface on that TAC is reached.
|
|
1867
|
+
const tac = (tree.tacs ?? []).find((t) => t?.tacId === entry);
|
|
1868
|
+
if (!tac) continue;
|
|
1869
|
+
for (const iface of tac.interfaces ?? []) {
|
|
1870
|
+
if (typeof iface?.name === 'string') out.add(`${tac.tacId}:${iface.name}`);
|
|
1871
|
+
}
|
|
1872
|
+
}
|
|
1873
|
+
}
|
|
1874
|
+
return out;
|
|
1875
|
+
}
|
|
1876
|
+
|
|
692
1877
|
// ---------------------------------------------------------------------------
|
|
693
1878
|
// D7 -- Decisions and review (blocking in 0.29.0).
|
|
694
1879
|
// ---------------------------------------------------------------------------
|
|
@@ -713,6 +1898,31 @@ export function checkD7Decisions(ctx) {
|
|
|
713
1898
|
}
|
|
714
1899
|
|
|
715
1900
|
const checks = [];
|
|
1901
|
+
// Check 1: `decisions:wellFormed` (productOwner, over tree) --
|
|
1902
|
+
// every decision is enumerated (ADR-4126, proposal section 1.3):
|
|
1903
|
+
// a non-empty question, at least two options, a default that
|
|
1904
|
+
// names one of the option letters.
|
|
1905
|
+
const wellFormedFail = [];
|
|
1906
|
+
for (const d of decisionEntries) {
|
|
1907
|
+
const why = 'decision is not enumerated (question, two or more options, a default)';
|
|
1908
|
+
const id = `decision:${d?.id ?? '?'}`;
|
|
1909
|
+
if (typeof d?.question !== 'string' || d.question.length === 0) {
|
|
1910
|
+
wellFormedFail.push({ id, why });
|
|
1911
|
+
continue;
|
|
1912
|
+
}
|
|
1913
|
+
if (!Array.isArray(d.options) || d.options.length < 2) {
|
|
1914
|
+
wellFormedFail.push({ id, why });
|
|
1915
|
+
continue;
|
|
1916
|
+
}
|
|
1917
|
+
const letters = new Set(d.options.map((o) => (o && typeof o === 'object') ? /** @type {any} */ (o).letter : undefined));
|
|
1918
|
+
if (typeof d.default !== 'string' || !letters.has(d.default)) {
|
|
1919
|
+
wellFormedFail.push({ id, why });
|
|
1920
|
+
}
|
|
1921
|
+
}
|
|
1922
|
+
checks.push(makeCheck('decisions:wellFormed', 'tree', decisionEntries.length, wellFormedFail));
|
|
1923
|
+
|
|
1924
|
+
// Check 2: `decisions:allAnswered` (engineer, over tree) -- zero
|
|
1925
|
+
// open decisions. The hand-over condition for build.
|
|
716
1926
|
checks.push(makeCheck(
|
|
717
1927
|
'decisions:allAnswered',
|
|
718
1928
|
'tree',
|