@transitrix/diagrams 1.0.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/LICENSE +21 -0
- package/README.md +47 -0
- package/dist/__tests__/edge-path.test.d.ts +1 -0
- package/dist/__tests__/edge-path.test.js +39 -0
- package/dist/__tests__/scope.test.d.ts +1 -0
- package/dist/__tests__/scope.test.js +23 -0
- package/dist/__tests__/yaml-normalize.test.d.ts +1 -0
- package/dist/__tests__/yaml-normalize.test.js +148 -0
- package/dist/activities/__tests__/cpm.test.d.ts +1 -0
- package/dist/activities/__tests__/cpm.test.js +146 -0
- package/dist/activities/__tests__/gantt.test.d.ts +1 -0
- package/dist/activities/__tests__/gantt.test.js +224 -0
- package/dist/activities/__tests__/layout.test.d.ts +1 -0
- package/dist/activities/__tests__/layout.test.js +98 -0
- package/dist/activities/__tests__/validate.test.d.ts +1 -0
- package/dist/activities/__tests__/validate.test.js +363 -0
- package/dist/activities/cpm.d.ts +2 -0
- package/dist/activities/cpm.js +86 -0
- package/dist/activities/gantt.d.ts +6 -0
- package/dist/activities/gantt.js +250 -0
- package/dist/activities/index.d.ts +5 -0
- package/dist/activities/index.js +4 -0
- package/dist/activities/layout.d.ts +2 -0
- package/dist/activities/layout.js +103 -0
- package/dist/activities/types.d.ts +125 -0
- package/dist/activities/types.js +1 -0
- package/dist/activities/validate.d.ts +2 -0
- package/dist/activities/validate.js +326 -0
- package/dist/activity-card/__tests__/example.test.d.ts +1 -0
- package/dist/activity-card/__tests__/example.test.js +56 -0
- package/dist/activity-card/__tests__/layout.test.d.ts +1 -0
- package/dist/activity-card/__tests__/layout.test.js +57 -0
- package/dist/activity-card/__tests__/resolver.test.d.ts +1 -0
- package/dist/activity-card/__tests__/resolver.test.js +146 -0
- package/dist/activity-card/__tests__/validate.test.d.ts +1 -0
- package/dist/activity-card/__tests__/validate.test.js +116 -0
- package/dist/activity-card/index.d.ts +5 -0
- package/dist/activity-card/index.js +3 -0
- package/dist/activity-card/layout.d.ts +7 -0
- package/dist/activity-card/layout.js +167 -0
- package/dist/activity-card/resolver.d.ts +7 -0
- package/dist/activity-card/resolver.js +310 -0
- package/dist/activity-card/types.d.ts +175 -0
- package/dist/activity-card/types.js +20 -0
- package/dist/activity-card/validate.d.ts +3 -0
- package/dist/activity-card/validate.js +145 -0
- package/dist/actor/__tests__/validate.test.d.ts +1 -0
- package/dist/actor/__tests__/validate.test.js +57 -0
- package/dist/actor/index.d.ts +3 -0
- package/dist/actor/index.js +2 -0
- package/dist/actor/types.d.ts +20 -0
- package/dist/actor/types.js +4 -0
- package/dist/actor/validate.d.ts +2 -0
- package/dist/actor/validate.js +34 -0
- package/dist/applications/__tests__/validate.test.d.ts +1 -0
- package/dist/applications/__tests__/validate.test.js +223 -0
- package/dist/applications/index.d.ts +2 -0
- package/dist/applications/index.js +1 -0
- package/dist/applications/types.d.ts +39 -0
- package/dist/applications/types.js +1 -0
- package/dist/applications/validate.d.ts +3 -0
- package/dist/applications/validate.js +109 -0
- package/dist/assertion/__tests__/example.test.d.ts +1 -0
- package/dist/assertion/__tests__/example.test.js +32 -0
- package/dist/assertion/__tests__/validate.test.d.ts +1 -0
- package/dist/assertion/__tests__/validate.test.js +130 -0
- package/dist/assertion/index.d.ts +4 -0
- package/dist/assertion/index.js +2 -0
- package/dist/assertion/types.d.ts +43 -0
- package/dist/assertion/types.js +7 -0
- package/dist/assertion/validate.d.ts +9 -0
- package/dist/assertion/validate.js +137 -0
- package/dist/blocks/__tests__/layout.test.d.ts +1 -0
- package/dist/blocks/__tests__/layout.test.js +153 -0
- package/dist/blocks/__tests__/validate.test.d.ts +1 -0
- package/dist/blocks/__tests__/validate.test.js +235 -0
- package/dist/blocks/index.d.ts +4 -0
- package/dist/blocks/index.js +2 -0
- package/dist/blocks/layout.d.ts +4 -0
- package/dist/blocks/layout.js +145 -0
- package/dist/blocks/types.d.ts +56 -0
- package/dist/blocks/types.js +1 -0
- package/dist/blocks/validate.d.ts +9 -0
- package/dist/blocks/validate.js +186 -0
- package/dist/capability-map/__tests__/validate.test.d.ts +1 -0
- package/dist/capability-map/__tests__/validate.test.js +212 -0
- package/dist/capability-map/index.d.ts +2 -0
- package/dist/capability-map/index.js +1 -0
- package/dist/capability-map/types.d.ts +26 -0
- package/dist/capability-map/types.js +1 -0
- package/dist/capability-map/validate.d.ts +3 -0
- package/dist/capability-map/validate.js +103 -0
- package/dist/change/__tests__/validate.test.d.ts +1 -0
- package/dist/change/__tests__/validate.test.js +73 -0
- package/dist/change/index.d.ts +2 -0
- package/dist/change/index.js +1 -0
- package/dist/change/types.d.ts +17 -0
- package/dist/change/types.js +3 -0
- package/dist/change/validate.d.ts +2 -0
- package/dist/change/validate.js +57 -0
- package/dist/compliance/__tests__/classify.test.d.ts +1 -0
- package/dist/compliance/__tests__/classify.test.js +24 -0
- package/dist/compliance/__tests__/confidence.test.d.ts +1 -0
- package/dist/compliance/__tests__/confidence.test.js +78 -0
- package/dist/compliance/__tests__/coverage-metric.test.d.ts +1 -0
- package/dist/compliance/__tests__/coverage-metric.test.js +164 -0
- package/dist/compliance/__tests__/demo-scenario.test.d.ts +1 -0
- package/dist/compliance/__tests__/demo-scenario.test.js +226 -0
- package/dist/compliance/__tests__/example.test.d.ts +1 -0
- package/dist/compliance/__tests__/example.test.js +51 -0
- package/dist/compliance/__tests__/gap-report.test.d.ts +1 -0
- package/dist/compliance/__tests__/gap-report.test.js +113 -0
- package/dist/compliance/__tests__/html.test.d.ts +1 -0
- package/dist/compliance/__tests__/html.test.js +122 -0
- package/dist/compliance/__tests__/impact.test.d.ts +1 -0
- package/dist/compliance/__tests__/impact.test.js +410 -0
- package/dist/compliance/__tests__/markdown.test.d.ts +1 -0
- package/dist/compliance/__tests__/markdown.test.js +85 -0
- package/dist/compliance/__tests__/views.test.d.ts +1 -0
- package/dist/compliance/__tests__/views.test.js +59 -0
- package/dist/compliance/classify.d.ts +27 -0
- package/dist/compliance/classify.js +60 -0
- package/dist/compliance/confidence.d.ts +27 -0
- package/dist/compliance/confidence.js +43 -0
- package/dist/compliance/coverage-metric.d.ts +74 -0
- package/dist/compliance/coverage-metric.js +181 -0
- package/dist/compliance/gap-report.d.ts +20 -0
- package/dist/compliance/gap-report.js +64 -0
- package/dist/compliance/html.d.ts +22 -0
- package/dist/compliance/html.js +256 -0
- package/dist/compliance/impact.d.ts +251 -0
- package/dist/compliance/impact.js +464 -0
- package/dist/compliance/index.d.ts +16 -0
- package/dist/compliance/index.js +9 -0
- package/dist/compliance/markdown.d.ts +18 -0
- package/dist/compliance/markdown.js +129 -0
- package/dist/compliance/reverse-index.d.ts +8 -0
- package/dist/compliance/reverse-index.js +30 -0
- package/dist/compliance/types.d.ts +98 -0
- package/dist/compliance/types.js +5 -0
- package/dist/compliance/views.d.ts +14 -0
- package/dist/compliance/views.js +35 -0
- package/dist/compliance-matrix/__tests__/build.test.d.ts +1 -0
- package/dist/compliance-matrix/__tests__/build.test.js +183 -0
- package/dist/compliance-matrix/__tests__/example.test.d.ts +1 -0
- package/dist/compliance-matrix/__tests__/example.test.js +49 -0
- package/dist/compliance-matrix/build.d.ts +18 -0
- package/dist/compliance-matrix/build.js +0 -0
- package/dist/compliance-matrix/index.d.ts +2 -0
- package/dist/compliance-matrix/index.js +1 -0
- package/dist/compliance-matrix/types.d.ts +86 -0
- package/dist/compliance-matrix/types.js +8 -0
- package/dist/confidence/__tests__/score.test.d.ts +1 -0
- package/dist/confidence/__tests__/score.test.js +188 -0
- package/dist/confidence/index.d.ts +2 -0
- package/dist/confidence/index.js +1 -0
- package/dist/confidence/score.d.ts +62 -0
- package/dist/confidence/score.js +215 -0
- package/dist/confidence/types.d.ts +79 -0
- package/dist/confidence/types.js +6 -0
- package/dist/edge-path.d.ts +18 -0
- package/dist/edge-path.js +35 -0
- package/dist/element-envelope.d.ts +15 -0
- package/dist/element-envelope.js +55 -0
- package/dist/factor/__tests__/validate.test.d.ts +1 -0
- package/dist/factor/__tests__/validate.test.js +83 -0
- package/dist/factor/index.d.ts +3 -0
- package/dist/factor/index.js +2 -0
- package/dist/factor/types.d.ts +23 -0
- package/dist/factor/types.js +6 -0
- package/dist/factor/validate.d.ts +2 -0
- package/dist/factor/validate.js +69 -0
- package/dist/fgca/__tests__/chain-table.test.d.ts +1 -0
- package/dist/fgca/__tests__/chain-table.test.js +158 -0
- package/dist/fgca/__tests__/layout.test.d.ts +1 -0
- package/dist/fgca/__tests__/layout.test.js +140 -0
- package/dist/fgca/__tests__/parse-canonical.test.d.ts +1 -0
- package/dist/fgca/__tests__/parse-canonical.test.js +224 -0
- package/dist/fgca/__tests__/preview-layout.test.d.ts +1 -0
- package/dist/fgca/__tests__/preview-layout.test.js +106 -0
- package/dist/fgca/__tests__/validate.test.d.ts +1 -0
- package/dist/fgca/__tests__/validate.test.js +125 -0
- package/dist/fgca/chain-table.d.ts +36 -0
- package/dist/fgca/chain-table.js +177 -0
- package/dist/fgca/index.d.ts +16 -0
- package/dist/fgca/index.js +11 -0
- package/dist/fgca/layout.d.ts +27 -0
- package/dist/fgca/layout.js +156 -0
- package/dist/fgca/nodeTypes.d.ts +6 -0
- package/dist/fgca/nodeTypes.js +10 -0
- package/dist/fgca/nodes/FGCAActivityNode.d.ts +13 -0
- package/dist/fgca/nodes/FGCAActivityNode.js +35 -0
- package/dist/fgca/nodes/FGCAChangeNode.d.ts +12 -0
- package/dist/fgca/nodes/FGCAChangeNode.js +35 -0
- package/dist/fgca/nodes/FGCAFactorNode.d.ts +12 -0
- package/dist/fgca/nodes/FGCAFactorNode.js +35 -0
- package/dist/fgca/nodes/FGCAGoalNode.d.ts +14 -0
- package/dist/fgca/nodes/FGCAGoalNode.js +40 -0
- package/dist/fgca/parse-canonical.d.ts +58 -0
- package/dist/fgca/parse-canonical.js +339 -0
- package/dist/fgca/preview-layout.d.ts +87 -0
- package/dist/fgca/preview-layout.js +122 -0
- package/dist/fgca/types.d.ts +39 -0
- package/dist/fgca/types.js +7 -0
- package/dist/fgca/validate.d.ts +14 -0
- package/dist/fgca/validate.js +108 -0
- package/dist/geometry.d.ts +7 -0
- package/dist/geometry.js +2 -0
- package/dist/goals/__tests__/layout.test.d.ts +1 -0
- package/dist/goals/__tests__/layout.test.js +153 -0
- package/dist/goals/__tests__/mutations.test.d.ts +1 -0
- package/dist/goals/__tests__/mutations.test.js +95 -0
- package/dist/goals/__tests__/parse-canonical.test.d.ts +1 -0
- package/dist/goals/__tests__/parse-canonical.test.js +129 -0
- package/dist/goals/__tests__/validate.test.d.ts +1 -0
- package/dist/goals/__tests__/validate.test.js +183 -0
- package/dist/goals/index.d.ts +6 -0
- package/dist/goals/index.js +4 -0
- package/dist/goals/layout.d.ts +11 -0
- package/dist/goals/layout.js +147 -0
- package/dist/goals/mutations.d.ts +6 -0
- package/dist/goals/mutations.js +116 -0
- package/dist/goals/parse-canonical.d.ts +29 -0
- package/dist/goals/parse-canonical.js +257 -0
- package/dist/goals/types.d.ts +71 -0
- package/dist/goals/types.js +1 -0
- package/dist/goals/validate.d.ts +2 -0
- package/dist/goals/validate.js +122 -0
- package/dist/index.d.ts +23 -0
- package/dist/index.js +23 -0
- package/dist/issues/__tests__/layout.test.d.ts +1 -0
- package/dist/issues/__tests__/layout.test.js +62 -0
- package/dist/issues/__tests__/validate.test.d.ts +1 -0
- package/dist/issues/__tests__/validate.test.js +82 -0
- package/dist/issues/index.d.ts +4 -0
- package/dist/issues/index.js +2 -0
- package/dist/issues/layout.d.ts +10 -0
- package/dist/issues/layout.js +82 -0
- package/dist/issues/types.d.ts +61 -0
- package/dist/issues/types.js +6 -0
- package/dist/issues/validate.d.ts +3 -0
- package/dist/issues/validate.js +143 -0
- package/dist/process-blueprint/__tests__/compliance-lane.test.d.ts +1 -0
- package/dist/process-blueprint/__tests__/compliance-lane.test.js +272 -0
- package/dist/process-blueprint/__tests__/layout.test.d.ts +1 -0
- package/dist/process-blueprint/__tests__/layout.test.js +159 -0
- package/dist/process-blueprint/__tests__/validate.test.d.ts +1 -0
- package/dist/process-blueprint/__tests__/validate.test.js +280 -0
- package/dist/process-blueprint/index.d.ts +4 -0
- package/dist/process-blueprint/index.js +2 -0
- package/dist/process-blueprint/layout.d.ts +2 -0
- package/dist/process-blueprint/layout.js +416 -0
- package/dist/process-blueprint/types.d.ts +220 -0
- package/dist/process-blueprint/types.js +1 -0
- package/dist/process-blueprint/validate.d.ts +3 -0
- package/dist/process-blueprint/validate.js +165 -0
- package/dist/process-map/__tests__/validate.test.d.ts +1 -0
- package/dist/process-map/__tests__/validate.test.js +199 -0
- package/dist/process-map/index.d.ts +2 -0
- package/dist/process-map/index.js +1 -0
- package/dist/process-map/types.d.ts +32 -0
- package/dist/process-map/types.js +1 -0
- package/dist/process-map/validate.d.ts +3 -0
- package/dist/process-map/validate.js +115 -0
- package/dist/products/__tests__/validate.test.d.ts +1 -0
- package/dist/products/__tests__/validate.test.js +210 -0
- package/dist/products/index.d.ts +2 -0
- package/dist/products/index.js +1 -0
- package/dist/products/types.d.ts +28 -0
- package/dist/products/types.js +1 -0
- package/dist/products/validate.d.ts +3 -0
- package/dist/products/validate.js +93 -0
- package/dist/repo-validate/__tests__/validate-repo.test.d.ts +1 -0
- package/dist/repo-validate/__tests__/validate-repo.test.js +132 -0
- package/dist/repo-validate/index.d.ts +2 -0
- package/dist/repo-validate/index.js +1 -0
- package/dist/repo-validate/types.d.ts +34 -0
- package/dist/repo-validate/types.js +14 -0
- package/dist/repo-validate/validate-repo.d.ts +8 -0
- package/dist/repo-validate/validate-repo.js +189 -0
- package/dist/requirement/__tests__/example.test.d.ts +1 -0
- package/dist/requirement/__tests__/example.test.js +21 -0
- package/dist/requirement/__tests__/validate.test.d.ts +1 -0
- package/dist/requirement/__tests__/validate.test.js +80 -0
- package/dist/requirement/index.d.ts +4 -0
- package/dist/requirement/index.js +2 -0
- package/dist/requirement/types.d.ts +25 -0
- package/dist/requirement/types.js +4 -0
- package/dist/requirement/validate.d.ts +7 -0
- package/dist/requirement/validate.js +81 -0
- package/dist/scenarios/__tests__/validate.test.d.ts +1 -0
- package/dist/scenarios/__tests__/validate.test.js +183 -0
- package/dist/scenarios/index.d.ts +2 -0
- package/dist/scenarios/index.js +1 -0
- package/dist/scenarios/types.d.ts +45 -0
- package/dist/scenarios/types.js +1 -0
- package/dist/scenarios/validate.d.ts +3 -0
- package/dist/scenarios/validate.js +110 -0
- package/dist/schema-version.d.ts +16 -0
- package/dist/schema-version.js +16 -0
- package/dist/scope.d.ts +23 -0
- package/dist/scope.js +38 -0
- package/dist/stakeholder/__tests__/validate.test.d.ts +1 -0
- package/dist/stakeholder/__tests__/validate.test.js +86 -0
- package/dist/stakeholder/index.d.ts +3 -0
- package/dist/stakeholder/index.js +2 -0
- package/dist/stakeholder/types.d.ts +24 -0
- package/dist/stakeholder/types.js +5 -0
- package/dist/stakeholder/validate.d.ts +2 -0
- package/dist/stakeholder/validate.js +58 -0
- package/dist/target-state/__tests__/validate.test.d.ts +1 -0
- package/dist/target-state/__tests__/validate.test.js +62 -0
- package/dist/target-state/index.d.ts +2 -0
- package/dist/target-state/index.js +1 -0
- package/dist/target-state/types.d.ts +18 -0
- package/dist/target-state/types.js +7 -0
- package/dist/target-state/validate.d.ts +2 -0
- package/dist/target-state/validate.js +61 -0
- package/dist/theme/index.d.ts +4 -0
- package/dist/theme/index.js +2 -0
- package/dist/theme/themes.d.ts +16 -0
- package/dist/theme/themes.js +213 -0
- package/dist/theme/tokens.d.ts +158 -0
- package/dist/theme/tokens.js +105 -0
- package/dist/typed-id.d.ts +20 -0
- package/dist/typed-id.js +38 -0
- package/dist/validation-types.d.ts +34 -0
- package/dist/validation-types.js +1 -0
- package/dist/webview/__tests__/entry-notations.test.d.ts +1 -0
- package/dist/webview/__tests__/entry-notations.test.js +62 -0
- package/dist/webview/__tests__/entry.test.d.ts +1 -0
- package/dist/webview/__tests__/entry.test.js +56 -0
- package/dist/webview/__tests__/render-goals.test.d.ts +1 -0
- package/dist/webview/__tests__/render-goals.test.js +65 -0
- package/dist/webview/entry.d.ts +38 -0
- package/dist/webview/entry.js +182 -0
- package/dist/webview/render-activities.d.ts +24 -0
- package/dist/webview/render-activities.js +127 -0
- package/dist/webview/render-activity-card.d.ts +5 -0
- package/dist/webview/render-activity-card.js +168 -0
- package/dist/webview/render-applications.d.ts +11 -0
- package/dist/webview/render-applications.js +105 -0
- package/dist/webview/render-blocks.d.ts +5 -0
- package/dist/webview/render-blocks.js +71 -0
- package/dist/webview/render-capability-map.d.ts +7 -0
- package/dist/webview/render-capability-map.js +88 -0
- package/dist/webview/render-fgca.d.ts +8 -0
- package/dist/webview/render-fgca.js +94 -0
- package/dist/webview/render-goals.d.ts +6 -0
- package/dist/webview/render-goals.js +92 -0
- package/dist/webview/render-process-blueprint.d.ts +5 -0
- package/dist/webview/render-process-blueprint.js +135 -0
- package/dist/webview/render-process-map.d.ts +7 -0
- package/dist/webview/render-process-map.js +82 -0
- package/dist/webview/render-products.d.ts +7 -0
- package/dist/webview/render-products.js +81 -0
- package/dist/webview/render-scenarios.d.ts +7 -0
- package/dist/webview/render-scenarios.js +75 -0
- package/dist/webview/render-util.d.ts +16 -0
- package/dist/webview/render-util.js +31 -0
- package/dist/webview/transitrix-render.css +323 -0
- package/dist/webview/transitrix-render.js +6452 -0
- package/dist/webview/transitrix-render.js.map +7 -0
- package/dist/yaml-normalize.d.ts +20 -0
- package/dist/yaml-normalize.js +57 -0
- package/package.json +40 -0
- package/src/__tests__/edge-path.test.ts +46 -0
- package/src/__tests__/scope.test.ts +27 -0
- package/src/__tests__/yaml-normalize.test.ts +158 -0
- package/src/activities/__tests__/cpm.test.ts +164 -0
- package/src/activities/__tests__/gantt.test.ts +245 -0
- package/src/activities/__tests__/layout.test.ts +112 -0
- package/src/activities/__tests__/validate.test.ts +409 -0
- package/src/activities/cpm.ts +95 -0
- package/src/activities/gantt.ts +276 -0
- package/src/activities/index.ts +28 -0
- package/src/activities/layout.ts +112 -0
- package/src/activities/types.ts +148 -0
- package/src/activities/validate.ts +357 -0
- package/src/activity-card/__tests__/example.test.ts +66 -0
- package/src/activity-card/__tests__/layout.test.ts +63 -0
- package/src/activity-card/__tests__/resolver.test.ts +161 -0
- package/src/activity-card/__tests__/validate.test.ts +131 -0
- package/src/activity-card/index.ts +32 -0
- package/src/activity-card/layout.ts +194 -0
- package/src/activity-card/resolver.ts +337 -0
- package/src/activity-card/types.ts +237 -0
- package/src/activity-card/validate.ts +158 -0
- package/src/actor/__tests__/validate.test.ts +67 -0
- package/src/actor/index.ts +3 -0
- package/src/actor/types.ts +29 -0
- package/src/actor/validate.ts +38 -0
- package/src/applications/__tests__/validate.test.ts +256 -0
- package/src/applications/index.ts +11 -0
- package/src/applications/types.ts +43 -0
- package/src/applications/validate.ts +131 -0
- package/src/assertion/__tests__/example.test.ts +37 -0
- package/src/assertion/__tests__/validate.test.ts +142 -0
- package/src/assertion/index.ts +12 -0
- package/src/assertion/types.ts +58 -0
- package/src/assertion/validate.ts +145 -0
- package/src/blocks/__tests__/layout.test.ts +169 -0
- package/src/blocks/__tests__/validate.test.ts +260 -0
- package/src/blocks/index.ts +17 -0
- package/src/blocks/layout.ts +186 -0
- package/src/blocks/types.ts +62 -0
- package/src/blocks/validate.ts +206 -0
- package/src/capability-map/__tests__/validate.test.ts +238 -0
- package/src/capability-map/index.ts +8 -0
- package/src/capability-map/types.ts +29 -0
- package/src/capability-map/validate.ts +127 -0
- package/src/change/__tests__/validate.test.ts +88 -0
- package/src/change/index.ts +2 -0
- package/src/change/types.ts +23 -0
- package/src/change/validate.ts +61 -0
- package/src/compliance/__tests__/classify.test.ts +27 -0
- package/src/compliance/__tests__/confidence.test.ts +98 -0
- package/src/compliance/__tests__/coverage-metric.test.ts +188 -0
- package/src/compliance/__tests__/demo-scenario.test.ts +273 -0
- package/src/compliance/__tests__/example.test.ts +57 -0
- package/src/compliance/__tests__/gap-report.test.ts +129 -0
- package/src/compliance/__tests__/html.test.ts +142 -0
- package/src/compliance/__tests__/impact.test.ts +482 -0
- package/src/compliance/__tests__/markdown.test.ts +95 -0
- package/src/compliance/__tests__/views.test.ts +64 -0
- package/src/compliance/classify.ts +84 -0
- package/src/compliance/confidence.ts +69 -0
- package/src/compliance/coverage-metric.ts +263 -0
- package/src/compliance/gap-report.ts +94 -0
- package/src/compliance/html.ts +295 -0
- package/src/compliance/impact.ts +677 -0
- package/src/compliance/index.ts +56 -0
- package/src/compliance/markdown.ts +135 -0
- package/src/compliance/reverse-index.ts +33 -0
- package/src/compliance/types.ts +120 -0
- package/src/compliance/views.ts +46 -0
- package/src/compliance-matrix/__tests__/build.test.ts +200 -0
- package/src/compliance-matrix/__tests__/example.test.ts +57 -0
- package/src/compliance-matrix/build.ts +0 -0
- package/src/compliance-matrix/index.ts +11 -0
- package/src/compliance-matrix/types.ts +102 -0
- package/src/confidence/__tests__/score.test.ts +254 -0
- package/src/confidence/index.ts +21 -0
- package/src/confidence/score.ts +243 -0
- package/src/confidence/types.ts +96 -0
- package/src/edge-path.ts +44 -0
- package/src/element-envelope.ts +76 -0
- package/src/factor/__tests__/validate.test.ts +98 -0
- package/src/factor/index.ts +8 -0
- package/src/factor/types.ts +41 -0
- package/src/factor/validate.ts +74 -0
- package/src/fgca/__tests__/chain-table.test.ts +172 -0
- package/src/fgca/__tests__/layout.test.ts +179 -0
- package/src/fgca/__tests__/parse-canonical.test.ts +248 -0
- package/src/fgca/__tests__/preview-layout.test.ts +124 -0
- package/src/fgca/__tests__/validate.test.ts +142 -0
- package/src/fgca/chain-table.ts +225 -0
- package/src/fgca/index.ts +45 -0
- package/src/fgca/layout.ts +204 -0
- package/src/fgca/nodeTypes.ts +11 -0
- package/src/fgca/nodes/FGCAActivityNode.tsx +65 -0
- package/src/fgca/nodes/FGCAChangeNode.tsx +64 -0
- package/src/fgca/nodes/FGCAFactorNode.tsx +64 -0
- package/src/fgca/nodes/FGCAGoalNode.tsx +72 -0
- package/src/fgca/parse-canonical.ts +400 -0
- package/src/fgca/preview-layout.ts +217 -0
- package/src/fgca/types.ts +50 -0
- package/src/fgca/validate.ts +126 -0
- package/src/geometry.ts +9 -0
- package/src/goals/__tests__/layout.test.ts +175 -0
- package/src/goals/__tests__/mutations.test.ts +111 -0
- package/src/goals/__tests__/parse-canonical.test.ts +145 -0
- package/src/goals/__tests__/validate.test.ts +202 -0
- package/src/goals/index.ts +21 -0
- package/src/goals/layout.ts +172 -0
- package/src/goals/mutations.ts +123 -0
- package/src/goals/parse-canonical.ts +286 -0
- package/src/goals/types.ts +85 -0
- package/src/goals/validate.ts +136 -0
- package/src/index.ts +23 -0
- package/src/process-blueprint/__tests__/compliance-lane.test.ts +320 -0
- package/src/process-blueprint/__tests__/layout.test.ts +195 -0
- package/src/process-blueprint/__tests__/validate.test.ts +310 -0
- package/src/process-blueprint/index.ts +31 -0
- package/src/process-blueprint/layout.ts +531 -0
- package/src/process-blueprint/types.ts +242 -0
- package/src/process-blueprint/validate.ts +181 -0
- package/src/process-map/__tests__/validate.test.ts +223 -0
- package/src/process-map/index.ts +10 -0
- package/src/process-map/types.ts +36 -0
- package/src/process-map/validate.ts +135 -0
- package/src/products/__tests__/validate.test.ts +239 -0
- package/src/products/index.ts +9 -0
- package/src/products/types.ts +31 -0
- package/src/products/validate.ts +112 -0
- package/src/repo-validate/__tests__/validate-repo.test.ts +149 -0
- package/src/repo-validate/index.ts +2 -0
- package/src/repo-validate/types.ts +50 -0
- package/src/repo-validate/validate-repo.ts +196 -0
- package/src/requirement/__tests__/example.test.ts +24 -0
- package/src/requirement/__tests__/validate.test.ts +96 -0
- package/src/requirement/index.ts +4 -0
- package/src/requirement/types.ts +35 -0
- package/src/requirement/validate.ts +92 -0
- package/src/scenarios/__tests__/validate.test.ts +209 -0
- package/src/scenarios/index.ts +15 -0
- package/src/scenarios/types.ts +37 -0
- package/src/scenarios/validate.ts +122 -0
- package/src/schema-version.ts +16 -0
- package/src/scope.ts +46 -0
- package/src/stakeholder/__tests__/validate.test.ts +101 -0
- package/src/stakeholder/index.ts +3 -0
- package/src/stakeholder/types.ts +33 -0
- package/src/stakeholder/validate.ts +63 -0
- package/src/target-state/__tests__/validate.test.ts +74 -0
- package/src/target-state/index.ts +2 -0
- package/src/target-state/types.ts +28 -0
- package/src/target-state/validate.ts +67 -0
- package/src/theme/index.ts +4 -0
- package/src/theme/themes.ts +237 -0
- package/src/theme/tokens.ts +133 -0
- package/src/typed-id.ts +56 -0
- package/src/validation-types.ts +36 -0
- package/src/webview/__tests__/entry-notations.test.ts +77 -0
- package/src/webview/__tests__/entry.test.ts +64 -0
- package/src/webview/__tests__/render-goals.test.ts +72 -0
- package/src/webview/entry.ts +292 -0
- package/src/webview/render-activities.ts +156 -0
- package/src/webview/render-activity-card.ts +234 -0
- package/src/webview/render-applications.ts +123 -0
- package/src/webview/render-blocks.ts +91 -0
- package/src/webview/render-capability-map.ts +98 -0
- package/src/webview/render-fgca.ts +122 -0
- package/src/webview/render-goals.ts +110 -0
- package/src/webview/render-process-blueprint.ts +207 -0
- package/src/webview/render-process-map.ts +93 -0
- package/src/webview/render-products.ts +91 -0
- package/src/webview/render-scenarios.ts +90 -0
- package/src/webview/render-util.ts +34 -0
- package/src/webview/styles.css +323 -0
- package/src/yaml-normalize.ts +56 -0
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
// Confidence-scoring types per methodology CONTRACT §11 (Confidence and
|
|
2
|
+
// freshness). Two independent signals — source trust (authored, fixed) and
|
|
3
|
+
// freshness (derived, recomputed on read) — combined per element and rolled
|
|
4
|
+
// up to a view composite. See packages/diagrams/src/confidence/score.ts for
|
|
5
|
+
// the pure scoring functions.
|
|
6
|
+
|
|
7
|
+
/** Closed source-trust scale per CONTRACT §11.2. */
|
|
8
|
+
export type SourceQuality =
|
|
9
|
+
| 'authoritative'
|
|
10
|
+
| 'corroborated'
|
|
11
|
+
| 'single_source'
|
|
12
|
+
| 'unverified';
|
|
13
|
+
|
|
14
|
+
/** Confidence band per CONTRACT §11.6 — derived from a numeric confidence. */
|
|
15
|
+
export type ConfidenceBand = 'A' | 'B' | 'C' | 'D';
|
|
16
|
+
|
|
17
|
+
/** Per-TYPE freshness-decay parameters per CONTRACT §11.3. */
|
|
18
|
+
export interface DecayParams {
|
|
19
|
+
fresh_days: number;
|
|
20
|
+
stale_days: number;
|
|
21
|
+
floor: number;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Adopter-manifest `confidence_decay` block (MANIFEST.md §2). Both halves
|
|
26
|
+
* are optional: an absent `defaults` block falls back to the §11.3 implicit
|
|
27
|
+
* defaults, and an absent `by_type` entry inherits from `defaults`.
|
|
28
|
+
*/
|
|
29
|
+
export interface ConfidenceDecayConfig {
|
|
30
|
+
defaults?: Partial<DecayParams>;
|
|
31
|
+
by_type?: Record<string, Partial<DecayParams>>;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* One canonical element fed to the scorer. The caller (Studio / DSM) has
|
|
36
|
+
* already resolved `derived_from` to the field artefacts and extracted their
|
|
37
|
+
* `source_quality` labels — this module never reads files.
|
|
38
|
+
*/
|
|
39
|
+
export interface ScoringElement {
|
|
40
|
+
/** Element TYPE name, used to look up per-TYPE decay (e.g. `CAPABILITY`). */
|
|
41
|
+
type: string;
|
|
42
|
+
/**
|
|
43
|
+
* ISO 8601 date the admission gate last ran for this element
|
|
44
|
+
* (`admitted_at`, CONTRACT §6). Reaffirmation bumps this date — the cure
|
|
45
|
+
* for staleness. Absent ⇒ treated as fully stale (freshness = floor).
|
|
46
|
+
*/
|
|
47
|
+
admitted_at?: string;
|
|
48
|
+
/**
|
|
49
|
+
* Source qualities resolved from `derived_from` — one entry per cited
|
|
50
|
+
* field artefact. Undefined or empty ⇒ unsourced: scored as `unverified`
|
|
51
|
+
* (0.25) and counted separately per §11.5.
|
|
52
|
+
*/
|
|
53
|
+
sources?: SourceQuality[];
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/** Per-element scoring output. */
|
|
57
|
+
export interface ElementScore {
|
|
58
|
+
/** Max source-trust weight over `sources`; 0.25 (`unverified`) if unsourced. */
|
|
59
|
+
source_trust: number;
|
|
60
|
+
/** Freshness in [floor, 1.0] per the §11.3 curve. */
|
|
61
|
+
freshness: number;
|
|
62
|
+
/** `source_trust × freshness`. */
|
|
63
|
+
confidence: number;
|
|
64
|
+
/**
|
|
65
|
+
* True iff at least one resolvable `derived_from` source was supplied.
|
|
66
|
+
* Drives the §11.5 "counted separately" gap signal and view coverage.
|
|
67
|
+
*/
|
|
68
|
+
sourced: boolean;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* View-level composite per CONTRACT §11.6. Three numbers surfaced alongside
|
|
73
|
+
* the view's formation date; the headline `band` is the band of the
|
|
74
|
+
* weakest link.
|
|
75
|
+
*/
|
|
76
|
+
export interface ViewComposite {
|
|
77
|
+
/** `min(confidence)` over the rendered elements. The headline figure. */
|
|
78
|
+
weakest_link: number;
|
|
79
|
+
/** Arithmetic mean of `confidence` (equal element weight in v1). */
|
|
80
|
+
mean: number;
|
|
81
|
+
/** Fraction of elements with `sourced === true`. */
|
|
82
|
+
coverage: number;
|
|
83
|
+
/** Band of the weakest link. */
|
|
84
|
+
band: ConfidenceBand;
|
|
85
|
+
element_count: number;
|
|
86
|
+
/** Elements with no resolvable `derived_from` — `unsourced_count` / `element_count` is the gap. */
|
|
87
|
+
unsourced_count: number;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/** Full scorer output: per-element + composite, plus the `today` used. */
|
|
91
|
+
export interface ViewScore {
|
|
92
|
+
elements: ElementScore[];
|
|
93
|
+
composite: ViewComposite;
|
|
94
|
+
/** The date used as `today` (the reference for `age_days`). */
|
|
95
|
+
today: string;
|
|
96
|
+
}
|
package/src/edge-path.ts
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
// Shared edge geometry for the static notation previews (Goals, FGCA, FGA,
|
|
2
|
+
// Activities). All four render dependency/relationship edges as a single cubic
|
|
3
|
+
// Bézier with horizontal control handles: each control point shares its
|
|
4
|
+
// endpoint's Y, so the tangent is horizontal at both ends and the marker-end
|
|
5
|
+
// arrow reads as perpendicular to the node's vertical edge.
|
|
6
|
+
//
|
|
7
|
+
// Pulling the path math here (rather than duplicating it inline in each
|
|
8
|
+
// preview) makes the configurable-curvature behaviour (vkgeorgia/strategy#76)
|
|
9
|
+
// unit-testable — the extension has no test harness.
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Base handle length floor + span factors. The handle grows with both the
|
|
13
|
+
* horizontal and vertical span so the curve stays visibly horizontal long
|
|
14
|
+
* enough for the arrowhead to sit flush against the line.
|
|
15
|
+
*/
|
|
16
|
+
export const EDGE_MIN_HANDLE = 64;
|
|
17
|
+
const DX_FACTOR = 0.5;
|
|
18
|
+
const DY_FACTOR = 0.8;
|
|
19
|
+
|
|
20
|
+
/** Multiplier applied to the base handle length. 1 = historical appearance. */
|
|
21
|
+
export const DEFAULT_EDGE_CURVATURE = 1;
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Builds the SVG `d` for a horizontal-tangent cubic Bézier from (sx,sy) to
|
|
25
|
+
* (tx,ty).
|
|
26
|
+
*
|
|
27
|
+
* `curvature` scales the control-handle length:
|
|
28
|
+
* - 0 → control points collapse onto the endpoints ⇒ a straight line.
|
|
29
|
+
* - 1 → the historical curve (no visual change from before #76).
|
|
30
|
+
* - >1 → progressively stronger arc.
|
|
31
|
+
*/
|
|
32
|
+
export function horizontalCubicEdgePath(
|
|
33
|
+
sx: number,
|
|
34
|
+
sy: number,
|
|
35
|
+
tx: number,
|
|
36
|
+
ty: number,
|
|
37
|
+
curvature: number = DEFAULT_EDGE_CURVATURE,
|
|
38
|
+
): string {
|
|
39
|
+
const dx = tx - sx;
|
|
40
|
+
const dy = ty - sy;
|
|
41
|
+
const baseHandle = Math.max(EDGE_MIN_HANDLE, Math.abs(dx) * DX_FACTOR, Math.abs(dy) * DY_FACTOR);
|
|
42
|
+
const handle = baseHandle * curvature;
|
|
43
|
+
return `M${sx},${sy} C${sx + handle},${sy} ${tx - handle},${ty} ${tx},${ty}`;
|
|
44
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
// Shared §3 envelope validator for standalone element primitives.
|
|
2
|
+
//
|
|
3
|
+
// Every standalone element file in the methodology canon carries the same
|
|
4
|
+
// envelope: a fixed `notation` tag, a canonical `id` whose TYPE prefix matches
|
|
5
|
+
// the element TYPE, `name`, an admission record (`zone`/`admitted_at`/
|
|
6
|
+
// `admitted_by`/`gate_checks`), and a primitive lifecycle
|
|
7
|
+
// (`valid_from`/`valid_to`). Per-TYPE fields (§7) sit between.
|
|
8
|
+
//
|
|
9
|
+
// Each per-TYPE validator delegates envelope checks here so the §3 rule lives
|
|
10
|
+
// in one place; per-TYPE fields (subtype enums, cross-references) are checked
|
|
11
|
+
// in the TYPE's own validator. The error `code` is parameterised so an
|
|
12
|
+
// envelope failure surfaces under the TYPE's own code (e.g. `FACTOR-001`,
|
|
13
|
+
// `CHANGE-001`), preserving per-TYPE attribution.
|
|
14
|
+
|
|
15
|
+
import type { ValidationError } from './validation-types.js';
|
|
16
|
+
import { isCanonicalIdOfType } from './typed-id.js';
|
|
17
|
+
|
|
18
|
+
export interface EnvelopeOptions {
|
|
19
|
+
/** Fixed `notation:` tag — lowercased TYPE short name (e.g. `factor`). */
|
|
20
|
+
notation: string;
|
|
21
|
+
/** Required `id:` TYPE prefix (e.g. `FACTOR`). */
|
|
22
|
+
idType: string;
|
|
23
|
+
/** Error code used for every envelope failure (e.g. `FACTOR-001`). */
|
|
24
|
+
code: string;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export interface EnvelopeResult {
|
|
28
|
+
/** The input narrowed to a record on success; `null` when the input is not a mapping. */
|
|
29
|
+
record: Record<string, unknown> | null;
|
|
30
|
+
errors: ValidationError[];
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function validateElementEnvelope(input: unknown, opts: EnvelopeOptions): EnvelopeResult {
|
|
34
|
+
const errors: ValidationError[] = [];
|
|
35
|
+
|
|
36
|
+
if (input === null || typeof input !== 'object' || Array.isArray(input)) {
|
|
37
|
+
errors.push({ code: opts.code, message: `${opts.idType} must be a YAML mapping.` });
|
|
38
|
+
return { record: null, errors };
|
|
39
|
+
}
|
|
40
|
+
const r = input as Record<string, unknown>;
|
|
41
|
+
|
|
42
|
+
if (r.notation !== opts.notation) {
|
|
43
|
+
errors.push({
|
|
44
|
+
code: opts.code,
|
|
45
|
+
message: `notation must be the fixed value "${opts.notation}".`,
|
|
46
|
+
path: 'notation',
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
if (!isCanonicalIdOfType(r.id, opts.idType)) {
|
|
50
|
+
errors.push({
|
|
51
|
+
code: opts.code,
|
|
52
|
+
message: `id "${String(r.id)}" must match ${opts.idType}-[<middle>-]<INTEGER>.`,
|
|
53
|
+
path: 'id',
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
for (const f of ['name', 'admitted_at', 'admitted_by', 'valid_from'] as const) {
|
|
57
|
+
if (typeof r[f] !== 'string' || (r[f] as string).trim() === '') {
|
|
58
|
+
errors.push({ code: opts.code, message: `${f} is required.`, path: f });
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
if (r.zone !== 'canon') {
|
|
62
|
+
errors.push({ code: opts.code, message: 'zone is required and must be "canon".', path: 'zone' });
|
|
63
|
+
}
|
|
64
|
+
if (r.gate_checks === null || typeof r.gate_checks !== 'object' || Array.isArray(r.gate_checks)) {
|
|
65
|
+
errors.push({ code: opts.code, message: 'gate_checks is required and must be a mapping.', path: 'gate_checks' });
|
|
66
|
+
}
|
|
67
|
+
if (!('valid_to' in r) || !(typeof r.valid_to === 'string' || r.valid_to === null)) {
|
|
68
|
+
errors.push({
|
|
69
|
+
code: opts.code,
|
|
70
|
+
message: 'valid_to is required (an ISO date string or null).',
|
|
71
|
+
path: 'valid_to',
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return { record: r, errors };
|
|
76
|
+
}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { validateFactor } from '../validate.js';
|
|
3
|
+
|
|
4
|
+
function valid(): Record<string, unknown> {
|
|
5
|
+
return {
|
|
6
|
+
notation: 'factor',
|
|
7
|
+
id: 'FACTOR-EU-REG-1',
|
|
8
|
+
name: 'EU regulatory window for market entry',
|
|
9
|
+
type: 'external',
|
|
10
|
+
category: 'legal',
|
|
11
|
+
description: 'Standing external driver — the EU regulatory regime.',
|
|
12
|
+
references_constraint: ['CONSTRAINT-GDPR-RESIDENCY-1'],
|
|
13
|
+
zone: 'canon',
|
|
14
|
+
admitted_at: '2026-05-29',
|
|
15
|
+
admitted_by: 'v.korobeinikov',
|
|
16
|
+
gate_checks: { uniqueness: 'pass', consistency: 'pass', completeness: 'pass' },
|
|
17
|
+
valid_from: '2026-05-26',
|
|
18
|
+
valid_to: null,
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const codes = (input: unknown): string[] => validateFactor(input).errors.map(e => e.code);
|
|
23
|
+
const warns = (input: unknown): string[] => validateFactor(input).warnings.map(w => w.code);
|
|
24
|
+
|
|
25
|
+
describe('validateFactor — positive', () => {
|
|
26
|
+
it('accepts the worked-example FACTOR-EU-REG-1', () => {
|
|
27
|
+
const r = validateFactor(valid());
|
|
28
|
+
expect(r.valid, JSON.stringify(r.errors)).toBe(true);
|
|
29
|
+
expect(r.errors).toHaveLength(0);
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
it('accepts a minimal factor (no type/category/references)', () => {
|
|
33
|
+
const r = valid();
|
|
34
|
+
delete r.type;
|
|
35
|
+
delete r.category;
|
|
36
|
+
delete r.references_constraint;
|
|
37
|
+
expect(validateFactor(r).valid).toBe(true);
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
describe('validateFactor — FACTOR-001 (envelope / shape)', () => {
|
|
42
|
+
it('flags a non-object', () => {
|
|
43
|
+
expect(codes(null)).toEqual(['FACTOR-001']);
|
|
44
|
+
expect(codes(['x'])).toEqual(['FACTOR-001']);
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it('flags a wrong notation tag', () => {
|
|
48
|
+
expect(codes({ ...valid(), notation: 'driver' })).toContain('FACTOR-001');
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it('flags an id with the wrong TYPE prefix', () => {
|
|
52
|
+
expect(codes({ ...valid(), id: 'GOAL-EU-1' })).toContain('FACTOR-001');
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it('flags an id with a leading-zero terminal', () => {
|
|
56
|
+
expect(codes({ ...valid(), id: 'FACTOR-EU-REG-01' })).toContain('FACTOR-001');
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it('flags a missing valid_to key (distinct from a null value)', () => {
|
|
60
|
+
const r = valid();
|
|
61
|
+
delete r.valid_to;
|
|
62
|
+
expect(codes(r)).toContain('FACTOR-001');
|
|
63
|
+
expect(validateFactor({ ...valid(), valid_to: null }).valid).toBe(true);
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it('flags references_constraint entries that are not CONSTRAINT typed ids', () => {
|
|
67
|
+
expect(codes({ ...valid(), references_constraint: ['GOAL-EU-1'] })).toContain('FACTOR-001');
|
|
68
|
+
expect(codes({ ...valid(), references_constraint: 'CONSTRAINT-X-1' })).toContain('FACTOR-001');
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
describe('validateFactor — FACTOR-002 (type enum)', () => {
|
|
73
|
+
it('flags a type outside external/internal', () => {
|
|
74
|
+
expect(codes({ ...valid(), type: 'driver' })).toContain('FACTOR-002');
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
it('accepts each permitted type', () => {
|
|
78
|
+
for (const t of ['external', 'internal']) {
|
|
79
|
+
expect(codes({ ...valid(), type: t, category: undefined })).not.toContain('FACTOR-002');
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
describe('validateFactor — FACTOR-003 (PESTLE category)', () => {
|
|
85
|
+
it('flags a category outside the PESTLE classes', () => {
|
|
86
|
+
expect(codes({ ...valid(), category: 'cultural' })).toContain('FACTOR-003');
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
it('warns when category is set on an internal factor', () => {
|
|
90
|
+
expect(warns({ ...valid(), type: 'internal', category: 'economic' })).toContain('FACTOR-003');
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
it('accepts each permitted PESTLE class', () => {
|
|
94
|
+
for (const c of ['political', 'economic', 'social', 'technological', 'legal', 'environmental']) {
|
|
95
|
+
expect(codes({ ...valid(), category: c })).not.toContain('FACTOR-003');
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
});
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
// The `Factor` type is re-exported under the alias `FactorPrimitive` at the
|
|
2
|
+
// package surface to avoid a name collision with the legacy FGCA-inline
|
|
3
|
+
// `Factor` shape exported from `./goals/index` (a v0.x view shape with
|
|
4
|
+
// numeric ids — distinct from this element primitive). Both types remain
|
|
5
|
+
// importable from their module subpaths.
|
|
6
|
+
export type { Factor as FactorPrimitive, FactorType, FactorCategory } from './types.js';
|
|
7
|
+
export { FACTOR_TYPES, FACTOR_CATEGORIES } from './types.js';
|
|
8
|
+
export { validateFactor } from './validate.js';
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
// FACTOR — motivation-layer driver primitive.
|
|
2
|
+
// Schema: methodology notations/ELEMENT_PRIMITIVES.md §7.1 + envelope §3.
|
|
3
|
+
|
|
4
|
+
import type { GateChecks } from '../requirement/types.js';
|
|
5
|
+
|
|
6
|
+
/** Optional subtype — internal/external organisation force. */
|
|
7
|
+
export type FactorType = 'external' | 'internal';
|
|
8
|
+
|
|
9
|
+
export const FACTOR_TYPES = ['external', 'internal'] as const;
|
|
10
|
+
|
|
11
|
+
/** PESTLE sub-classification — external factors only. Open-ended in practice
|
|
12
|
+
* but v1 fixes the six standard classes; an unknown category is flagged. */
|
|
13
|
+
export type FactorCategory =
|
|
14
|
+
| 'political'
|
|
15
|
+
| 'economic'
|
|
16
|
+
| 'social'
|
|
17
|
+
| 'technological'
|
|
18
|
+
| 'legal'
|
|
19
|
+
| 'environmental';
|
|
20
|
+
|
|
21
|
+
export const FACTOR_CATEGORIES = [
|
|
22
|
+
'political', 'economic', 'social', 'technological', 'legal', 'environmental',
|
|
23
|
+
] as const;
|
|
24
|
+
|
|
25
|
+
export interface Factor {
|
|
26
|
+
notation: 'factor';
|
|
27
|
+
id: string;
|
|
28
|
+
name: string;
|
|
29
|
+
type?: FactorType;
|
|
30
|
+
category?: FactorCategory;
|
|
31
|
+
description?: string;
|
|
32
|
+
references_constraint?: string[];
|
|
33
|
+
|
|
34
|
+
zone: 'canon';
|
|
35
|
+
admitted_at: string;
|
|
36
|
+
admitted_by: string;
|
|
37
|
+
gate_checks: GateChecks;
|
|
38
|
+
|
|
39
|
+
valid_from: string;
|
|
40
|
+
valid_to: string | null;
|
|
41
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
// FACTOR validator — methodology notations/ELEMENT_PRIMITIVES.md §7.1.
|
|
2
|
+
//
|
|
3
|
+
// Implements FACTOR-001..003. Cross-cutting HDR-/LIFECYCLE-/policy rules
|
|
4
|
+
// (CONTRACT.md §8) are owned elsewhere and out of scope for this
|
|
5
|
+
// single-artefact validator.
|
|
6
|
+
|
|
7
|
+
import type { ValidationError, ValidationResult, ValidationWarning } from '../validation-types.js';
|
|
8
|
+
import { typeOfId } from '../typed-id.js';
|
|
9
|
+
import { validateElementEnvelope } from '../element-envelope.js';
|
|
10
|
+
import { FACTOR_CATEGORIES, FACTOR_TYPES } from './types.js';
|
|
11
|
+
|
|
12
|
+
export function validateFactor(input: unknown): ValidationResult {
|
|
13
|
+
const errors: ValidationError[] = [];
|
|
14
|
+
const warnings: ValidationWarning[] = [];
|
|
15
|
+
|
|
16
|
+
const { record, errors: envErrors } = validateElementEnvelope(input, {
|
|
17
|
+
notation: 'factor',
|
|
18
|
+
idType: 'FACTOR',
|
|
19
|
+
code: 'FACTOR-001',
|
|
20
|
+
});
|
|
21
|
+
errors.push(...envErrors);
|
|
22
|
+
if (!record) return { valid: false, errors, warnings };
|
|
23
|
+
|
|
24
|
+
// FACTOR-002 — type subtype enum (optional field).
|
|
25
|
+
if (record.type !== undefined && !FACTOR_TYPES.includes(record.type as never)) {
|
|
26
|
+
errors.push({
|
|
27
|
+
code: 'FACTOR-002',
|
|
28
|
+
message: `type "${String(record.type)}" must be one of ${FACTOR_TYPES.join(', ')}.`,
|
|
29
|
+
path: 'type',
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// FACTOR-003 — PESTLE category enum on external factors; warn on internal.
|
|
34
|
+
if (record.category !== undefined) {
|
|
35
|
+
if (!FACTOR_CATEGORIES.includes(record.category as never)) {
|
|
36
|
+
errors.push({
|
|
37
|
+
code: 'FACTOR-003',
|
|
38
|
+
message: `category "${String(record.category)}" must be a PESTLE class (${FACTOR_CATEGORIES.join(', ')}).`,
|
|
39
|
+
path: 'category',
|
|
40
|
+
});
|
|
41
|
+
} else if (record.type === 'internal') {
|
|
42
|
+
// §7.1: "Omit on internal factors — PESTLE does not apply."
|
|
43
|
+
warnings.push({
|
|
44
|
+
code: 'FACTOR-003',
|
|
45
|
+
message: 'category is set on an internal factor; PESTLE applies to external drivers only.',
|
|
46
|
+
path: 'category',
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// FACTOR-001 — references_constraint shape + TYPE on each entry.
|
|
52
|
+
if (record.references_constraint !== undefined) {
|
|
53
|
+
if (!Array.isArray(record.references_constraint)) {
|
|
54
|
+
errors.push({
|
|
55
|
+
code: 'FACTOR-001',
|
|
56
|
+
message: 'references_constraint must be a list of typed CONSTRAINT IDs.',
|
|
57
|
+
path: 'references_constraint',
|
|
58
|
+
});
|
|
59
|
+
} else {
|
|
60
|
+
record.references_constraint.forEach((ref, i) => {
|
|
61
|
+
const type = typeOfId(ref);
|
|
62
|
+
if (type !== 'CONSTRAINT') {
|
|
63
|
+
errors.push({
|
|
64
|
+
code: 'FACTOR-001',
|
|
65
|
+
message: `references_constraint[${i}] "${String(ref)}" must be a CONSTRAINT typed ID.`,
|
|
66
|
+
path: `references_constraint[${i}]`,
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return { valid: errors.length === 0, errors, warnings };
|
|
74
|
+
}
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { buildChainTable, type ChainTable, type ChainColumn } from '../chain-table.js';
|
|
3
|
+
import type { FGCAPreviewDoc } from '../preview-layout.js';
|
|
4
|
+
|
|
5
|
+
// Renders a ChainTable to a compact text grid for readable assertions. Each
|
|
6
|
+
// cell shows "label×rowSpan" (×1 omitted); a position covered by a span above
|
|
7
|
+
// shows "·".
|
|
8
|
+
function asGrid(t: ChainTable): string[][] {
|
|
9
|
+
return t.rows.map(row =>
|
|
10
|
+
row.map(c => {
|
|
11
|
+
if (c === null) return '·';
|
|
12
|
+
const label = c.cell ? c.cell.label : '∅';
|
|
13
|
+
return c.rowSpan > 1 ? `${label}×${c.rowSpan}` : label;
|
|
14
|
+
}),
|
|
15
|
+
);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
describe('buildChainTable — worked example (FGCA)', () => {
|
|
19
|
+
// F1 → G1, G2 ; G1 → C1 → A1 ; G2 → C2 → A2, A3
|
|
20
|
+
const doc: FGCAPreviewDoc = {
|
|
21
|
+
factors: [{ id: 1, name: 'F1' }],
|
|
22
|
+
goals: [
|
|
23
|
+
{ id: 10, name: 'G1', factor: [{ id: 1 }] },
|
|
24
|
+
{ id: 11, name: 'G2', factor: [{ id: 1 }] },
|
|
25
|
+
],
|
|
26
|
+
changes: [
|
|
27
|
+
{ id: 20, name: 'C1', goal_id: 10, activity_ids: [30] },
|
|
28
|
+
{ id: 21, name: 'C2', goal_id: 11, activity_ids: [31, 32] },
|
|
29
|
+
],
|
|
30
|
+
activities: [
|
|
31
|
+
{ id: 30, name: 'A1', goal_id: 10 },
|
|
32
|
+
{ id: 31, name: 'A2', goal_id: 11 },
|
|
33
|
+
{ id: 32, name: 'A3', goal_id: 11 },
|
|
34
|
+
],
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
it('produces the spec grid with F1 spanning 3 and G2/C2 spanning 2', () => {
|
|
38
|
+
const t = buildChainTable(doc);
|
|
39
|
+
expect(t.columns).toEqual<ChainColumn[]>(['factor', 'goal', 'change', 'activity']);
|
|
40
|
+
expect(asGrid(t)).toEqual([
|
|
41
|
+
['F1×3', 'G1', 'C1', 'A1'],
|
|
42
|
+
['·', 'G2×2', 'C2×2', 'A2'],
|
|
43
|
+
['·', '·', '·', 'A3'],
|
|
44
|
+
]);
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it('orders the merged cells with correct rowSpans on the model', () => {
|
|
48
|
+
const t = buildChainTable(doc);
|
|
49
|
+
// Factor cell spans all three rows.
|
|
50
|
+
expect(t.rows[0][0]).toMatchObject({ rowSpan: 3, cell: { label: 'F1' } });
|
|
51
|
+
// Covered positions are null (no <td> emitted).
|
|
52
|
+
expect(t.rows[1][0]).toBeNull();
|
|
53
|
+
expect(t.rows[2][1]).toBeNull();
|
|
54
|
+
});
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
describe('buildChainTable — FGA (no Change column)', () => {
|
|
58
|
+
// FGA links Goal → Activity directly via activity.goal_id; no changes.
|
|
59
|
+
const doc: FGCAPreviewDoc = {
|
|
60
|
+
factors: [{ id: 1, name: 'F1' }],
|
|
61
|
+
goals: [{ id: 10, name: 'G1', factor: [{ id: 1 }] }],
|
|
62
|
+
activities: [
|
|
63
|
+
{ id: 30, name: 'A1', goal_id: 10 },
|
|
64
|
+
{ id: 31, name: 'A2', goal_id: 10 },
|
|
65
|
+
],
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
it('emits three columns and merges Factor/Goal across the two activities', () => {
|
|
69
|
+
const t = buildChainTable(doc, { hideChanges: true });
|
|
70
|
+
expect(t.columns).toEqual<ChainColumn[]>(['factor', 'goal', 'activity']);
|
|
71
|
+
expect(asGrid(t)).toEqual([
|
|
72
|
+
['F1×2', 'G1×2', 'A1'],
|
|
73
|
+
['·', '·', 'A2'],
|
|
74
|
+
]);
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
describe('buildChainTable — missing downstream links (gaps stay visible)', () => {
|
|
79
|
+
it('shows a factor with no goal, a goal with no change, and a change with no activity', () => {
|
|
80
|
+
const doc: FGCAPreviewDoc = {
|
|
81
|
+
factors: [
|
|
82
|
+
{ id: 1, name: 'F1' },
|
|
83
|
+
{ id: 2, name: 'F2' }, // no goals
|
|
84
|
+
],
|
|
85
|
+
goals: [
|
|
86
|
+
{ id: 10, name: 'G1', factor: [{ id: 1 }] }, // no change, no activity
|
|
87
|
+
{ id: 11, name: 'G2', factor: [{ id: 1 }] }, // has a change with no activity
|
|
88
|
+
],
|
|
89
|
+
changes: [{ id: 20, name: 'C1', goal_id: 11, activity_ids: [] }],
|
|
90
|
+
activities: [],
|
|
91
|
+
};
|
|
92
|
+
const t = buildChainTable(doc);
|
|
93
|
+
expect(asGrid(t)).toEqual([
|
|
94
|
+
['F1×2', 'G1', '∅', '∅'],
|
|
95
|
+
['·', 'G2', 'C1', '∅'],
|
|
96
|
+
['F2', '∅', '∅', '∅'],
|
|
97
|
+
]);
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
it('renders a change-less direct goal→activity path with an empty Change cell', () => {
|
|
101
|
+
const doc: FGCAPreviewDoc = {
|
|
102
|
+
factors: [{ id: 1, name: 'F1' }],
|
|
103
|
+
goals: [{ id: 10, name: 'G1', factor: [{ id: 1 }] }],
|
|
104
|
+
// activity bound straight to the goal, not covered by any change
|
|
105
|
+
changes: [],
|
|
106
|
+
activities: [{ id: 30, name: 'A1', goal_id: 10 }],
|
|
107
|
+
};
|
|
108
|
+
const t = buildChainTable(doc);
|
|
109
|
+
expect(asGrid(t)).toEqual([['F1', 'G1', '∅', 'A1']]);
|
|
110
|
+
});
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
describe('buildChainTable — orphans (broken refs are warnings, not errors)', () => {
|
|
114
|
+
it('places a goal with a missing factor in a trailing empty-Factor row', () => {
|
|
115
|
+
const doc: FGCAPreviewDoc = {
|
|
116
|
+
factors: [{ id: 1, name: 'F1' }],
|
|
117
|
+
goals: [
|
|
118
|
+
{ id: 10, name: 'G1', factor: [{ id: 1 }] },
|
|
119
|
+
{ id: 11, name: 'Gx', factor: [{ id: 99 }] }, // factor 99 does not exist
|
|
120
|
+
{ id: 12, name: 'Gy' }, // no factor at all
|
|
121
|
+
],
|
|
122
|
+
changes: [{ id: 20, name: 'C1', goal_id: 10, activity_ids: [30] }],
|
|
123
|
+
activities: [{ id: 30, name: 'A1', goal_id: 10 }],
|
|
124
|
+
};
|
|
125
|
+
const t = buildChainTable(doc);
|
|
126
|
+
expect(asGrid(t)).toEqual([
|
|
127
|
+
['F1', 'G1', 'C1', 'A1'],
|
|
128
|
+
['∅×2', 'Gx', '∅', '∅'],
|
|
129
|
+
['·', 'Gy', '∅', '∅'],
|
|
130
|
+
]);
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
it('surfaces an unlinked activity as a trailing row with empty cells to its left', () => {
|
|
134
|
+
const doc: FGCAPreviewDoc = {
|
|
135
|
+
factors: [{ id: 1, name: 'F1' }],
|
|
136
|
+
goals: [{ id: 10, name: 'G1', factor: [{ id: 1 }] }],
|
|
137
|
+
changes: [{ id: 20, name: 'C1', goal_id: 10, activity_ids: [30] }],
|
|
138
|
+
activities: [
|
|
139
|
+
{ id: 30, name: 'A1', goal_id: 10 },
|
|
140
|
+
{ id: 99, name: 'Aorphan' }, // no goal, no change
|
|
141
|
+
],
|
|
142
|
+
};
|
|
143
|
+
const t = buildChainTable(doc);
|
|
144
|
+
expect(asGrid(t)).toEqual([
|
|
145
|
+
['F1', 'G1', 'C1', 'A1'],
|
|
146
|
+
['∅', '∅', '∅', 'Aorphan'],
|
|
147
|
+
]);
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
it('surfaces a change whose goal is missing as an empty Factor+Goal row', () => {
|
|
151
|
+
const doc: FGCAPreviewDoc = {
|
|
152
|
+
factors: [],
|
|
153
|
+
goals: [],
|
|
154
|
+
changes: [{ id: 20, name: 'Cx', goal_id: 999, activity_ids: [30] }],
|
|
155
|
+
activities: [{ id: 30, name: 'A1' }],
|
|
156
|
+
};
|
|
157
|
+
const t = buildChainTable(doc);
|
|
158
|
+
expect(asGrid(t)).toEqual([['∅', '∅', 'Cx', 'A1']]);
|
|
159
|
+
});
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
describe('buildChainTable — name fallback', () => {
|
|
163
|
+
it('falls back to the id when an element has an empty name', () => {
|
|
164
|
+
const doc: FGCAPreviewDoc = {
|
|
165
|
+
factors: [{ id: 7, name: '' }],
|
|
166
|
+
goals: [],
|
|
167
|
+
activities: [],
|
|
168
|
+
};
|
|
169
|
+
const t = buildChainTable(doc);
|
|
170
|
+
expect(t.rows[0][0]?.cell?.label).toBe('7');
|
|
171
|
+
});
|
|
172
|
+
});
|