@nahisaho/musubix-core 1.1.16 → 1.3.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/AGENTS.md +53 -10
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -1
- package/dist/symbolic/__tests__/ears-to-formal.test.d.ts +9 -0
- package/dist/symbolic/__tests__/ears-to-formal.test.d.ts.map +1 -0
- package/dist/symbolic/__tests__/ears-to-formal.test.js +187 -0
- package/dist/symbolic/__tests__/ears-to-formal.test.js.map +1 -0
- package/dist/symbolic/__tests__/quality-gate.test.d.ts +9 -0
- package/dist/symbolic/__tests__/quality-gate.test.d.ts.map +1 -0
- package/dist/symbolic/__tests__/quality-gate.test.js +230 -0
- package/dist/symbolic/__tests__/quality-gate.test.js.map +1 -0
- package/dist/symbolic/__tests__/security-scanner.test.d.ts +9 -0
- package/dist/symbolic/__tests__/security-scanner.test.d.ts.map +1 -0
- package/dist/symbolic/__tests__/security-scanner.test.js +336 -0
- package/dist/symbolic/__tests__/security-scanner.test.js.map +1 -0
- package/dist/symbolic/__tests__/vc-generator.test.d.ts +9 -0
- package/dist/symbolic/__tests__/vc-generator.test.d.ts.map +1 -0
- package/dist/symbolic/__tests__/vc-generator.test.js +301 -0
- package/dist/symbolic/__tests__/vc-generator.test.js.map +1 -0
- package/dist/symbolic/__tests__/z3-adapter.test.d.ts +10 -0
- package/dist/symbolic/__tests__/z3-adapter.test.d.ts.map +1 -0
- package/dist/symbolic/__tests__/z3-adapter.test.js +260 -0
- package/dist/symbolic/__tests__/z3-adapter.test.js.map +1 -0
- package/dist/symbolic/audit-logger.d.ts +233 -0
- package/dist/symbolic/audit-logger.d.ts.map +1 -0
- package/dist/symbolic/audit-logger.js +438 -0
- package/dist/symbolic/audit-logger.js.map +1 -0
- package/dist/symbolic/candidate-ranker.d.ts +133 -0
- package/dist/symbolic/candidate-ranker.d.ts.map +1 -0
- package/dist/symbolic/candidate-ranker.js +223 -0
- package/dist/symbolic/candidate-ranker.js.map +1 -0
- package/dist/symbolic/confidence-estimator.d.ts +57 -0
- package/dist/symbolic/confidence-estimator.d.ts.map +1 -0
- package/dist/symbolic/confidence-estimator.js +185 -0
- package/dist/symbolic/confidence-estimator.js.map +1 -0
- package/dist/symbolic/confidence-router.d.ts +55 -0
- package/dist/symbolic/confidence-router.d.ts.map +1 -0
- package/dist/symbolic/confidence-router.js +186 -0
- package/dist/symbolic/confidence-router.js.map +1 -0
- package/dist/symbolic/constitution-registry.d.ts +100 -0
- package/dist/symbolic/constitution-registry.d.ts.map +1 -0
- package/dist/symbolic/constitution-registry.js +324 -0
- package/dist/symbolic/constitution-registry.js.map +1 -0
- package/dist/symbolic/ears-to-formal.d.ts +156 -0
- package/dist/symbolic/ears-to-formal.d.ts.map +1 -0
- package/dist/symbolic/ears-to-formal.js +419 -0
- package/dist/symbolic/ears-to-formal.js.map +1 -0
- package/dist/symbolic/error-handler.d.ts +88 -0
- package/dist/symbolic/error-handler.d.ts.map +1 -0
- package/dist/symbolic/error-handler.js +239 -0
- package/dist/symbolic/error-handler.js.map +1 -0
- package/dist/symbolic/hallucination-detector.d.ts +100 -0
- package/dist/symbolic/hallucination-detector.d.ts.map +1 -0
- package/dist/symbolic/hallucination-detector.js +327 -0
- package/dist/symbolic/hallucination-detector.js.map +1 -0
- package/dist/symbolic/index.d.ts +75 -0
- package/dist/symbolic/index.d.ts.map +1 -0
- package/dist/symbolic/index.js +95 -0
- package/dist/symbolic/index.js.map +1 -0
- package/dist/symbolic/performance-budget.d.ts +208 -0
- package/dist/symbolic/performance-budget.d.ts.map +1 -0
- package/dist/symbolic/performance-budget.js +356 -0
- package/dist/symbolic/performance-budget.js.map +1 -0
- package/dist/symbolic/quality-gate.d.ts +170 -0
- package/dist/symbolic/quality-gate.d.ts.map +1 -0
- package/dist/symbolic/quality-gate.js +484 -0
- package/dist/symbolic/quality-gate.js.map +1 -0
- package/dist/symbolic/result-blender.d.ts +150 -0
- package/dist/symbolic/result-blender.d.ts.map +1 -0
- package/dist/symbolic/result-blender.js +246 -0
- package/dist/symbolic/result-blender.js.map +1 -0
- package/dist/symbolic/rule-config.d.ts +223 -0
- package/dist/symbolic/rule-config.d.ts.map +1 -0
- package/dist/symbolic/rule-config.js +569 -0
- package/dist/symbolic/rule-config.js.map +1 -0
- package/dist/symbolic/security-scanner.d.ts +332 -0
- package/dist/symbolic/security-scanner.d.ts.map +1 -0
- package/dist/symbolic/security-scanner.js +727 -0
- package/dist/symbolic/security-scanner.js.map +1 -0
- package/dist/symbolic/semantic-filter.d.ts +57 -0
- package/dist/symbolic/semantic-filter.d.ts.map +1 -0
- package/dist/symbolic/semantic-filter.js +136 -0
- package/dist/symbolic/semantic-filter.js.map +1 -0
- package/dist/symbolic/types.d.ts +265 -0
- package/dist/symbolic/types.d.ts.map +1 -0
- package/dist/symbolic/types.js +16 -0
- package/dist/symbolic/types.js.map +1 -0
- package/dist/symbolic/vc-generator.d.ts +177 -0
- package/dist/symbolic/vc-generator.d.ts.map +1 -0
- package/dist/symbolic/vc-generator.js +400 -0
- package/dist/symbolic/vc-generator.js.map +1 -0
- package/dist/symbolic/z3-adapter.d.ts +219 -0
- package/dist/symbolic/z3-adapter.d.ts.map +1 -0
- package/dist/symbolic/z3-adapter.js +528 -0
- package/dist/symbolic/z3-adapter.js.map +1 -0
- package/package.json +1 -1
package/AGENTS.md
CHANGED
|
@@ -8,14 +8,14 @@
|
|
|
8
8
|
|
|
9
9
|
| 項目 | 詳細 |
|
|
10
10
|
|------|------|
|
|
11
|
-
| **バージョン** | 1.
|
|
11
|
+
| **バージョン** | 1.3.0 |
|
|
12
12
|
| **言語** | TypeScript |
|
|
13
13
|
| **ランタイム** | Node.js >= 20.0.0 |
|
|
14
14
|
| **パッケージマネージャ** | npm >= 10.0.0 |
|
|
15
15
|
| **ビルドシステム** | モノレポ(npm workspaces) |
|
|
16
16
|
| **テストフレームワーク** | Vitest |
|
|
17
|
-
| **テスト数** |
|
|
18
|
-
| **コンポーネント数** |
|
|
17
|
+
| **テスト数** | 752 (全合格) |
|
|
18
|
+
| **コンポーネント数** | 243 (62ドメイン対応) |
|
|
19
19
|
| **Agent Skills** | 12 (Claude Code対応) |
|
|
20
20
|
|
|
21
21
|
---
|
|
@@ -28,14 +28,22 @@
|
|
|
28
28
|
packages/
|
|
29
29
|
├── core/ # @nahisaho/musubix-core
|
|
30
30
|
├── mcp-server/ # @nahisaho/musubix-mcp-server
|
|
31
|
-
|
|
31
|
+
├── yata-client/ # @nahisaho/musubix-yata-client
|
|
32
|
+
├── pattern-mcp/ # @nahisaho/musubix-pattern-mcp (NEW!)
|
|
33
|
+
├── ontology-mcp/ # @nahisaho/musubix-ontology-mcp (NEW!)
|
|
34
|
+
├── wake-sleep/ # @nahisaho/musubix-wake-sleep (NEW!)
|
|
35
|
+
└── sdd-ontology/ # @nahisaho/musubix-sdd-ontology (NEW!)
|
|
32
36
|
```
|
|
33
37
|
|
|
34
38
|
| パッケージ | npm | 役割 |
|
|
35
39
|
|-----------|-----|------|
|
|
36
40
|
| `packages/core/` | `@nahisaho/musubix-core` | コアライブラリ - CLI、EARS検証、コード生成、設計パターン |
|
|
37
|
-
| `packages/mcp-server/` | `@nahisaho/musubix-mcp-server` | MCPサーバー -
|
|
41
|
+
| `packages/mcp-server/` | `@nahisaho/musubix-mcp-server` | MCPサーバー - 16ツール、3プロンプト |
|
|
38
42
|
| `packages/yata-client/` | `@nahisaho/musubix-yata-client` | YATAクライアント - 知識グラフ連携 |
|
|
43
|
+
| `packages/pattern-mcp/` | `@nahisaho/musubix-pattern-mcp` | パターン学習 - 抽出・圧縮・ライブラリ |
|
|
44
|
+
| `packages/ontology-mcp/` | `@nahisaho/musubix-ontology-mcp` | オントロジー - N3Store・推論エンジン |
|
|
45
|
+
| `packages/wake-sleep/` | `@nahisaho/musubix-wake-sleep` | Wake-Sleep学習サイクル |
|
|
46
|
+
| `packages/sdd-ontology/` | `@nahisaho/musubix-sdd-ontology` | SDD方法論オントロジー |
|
|
39
47
|
|
|
40
48
|
### Core パッケージモジュール
|
|
41
49
|
|
|
@@ -47,8 +55,9 @@ packages/core/src/
|
|
|
47
55
|
├── design/ # 設計パターン・C4モデル
|
|
48
56
|
├── error/ # エラーハンドリング
|
|
49
57
|
├── explanation/ # 説明生成・可視化
|
|
50
|
-
├── learning/ #
|
|
58
|
+
├── learning/ # 自己学習システム
|
|
51
59
|
├── requirements/ # 要件分析・分解
|
|
60
|
+
├── symbolic/ # シンボリック推論(v1.2.0 NEW!)
|
|
52
61
|
├── traceability/ # トレーサビリティ
|
|
53
62
|
├── types/ # 型定義
|
|
54
63
|
├── utils/ # ユーティリティ
|
|
@@ -121,7 +130,9 @@ npx @nahisaho/musubix-mcp-server
|
|
|
121
130
|
npx musubix-mcp --transport stdio
|
|
122
131
|
```
|
|
123
132
|
|
|
124
|
-
### ツール一覧(
|
|
133
|
+
### ツール一覧(16ツール)
|
|
134
|
+
|
|
135
|
+
#### SDD基本ツール(9ツール)
|
|
125
136
|
|
|
126
137
|
| ツール名 | 説明 |
|
|
127
138
|
|---------|------|
|
|
@@ -135,6 +146,18 @@ npx musubix-mcp --transport stdio
|
|
|
135
146
|
| `sdd_validate_constitution` | 9憲法条項への準拠検証 |
|
|
136
147
|
| `sdd_validate_traceability` | 要件↔設計↔タスクのトレーサビリティ検証 |
|
|
137
148
|
|
|
149
|
+
#### パターン統合ツール(7ツール)- v1.3.0 NEW!
|
|
150
|
+
|
|
151
|
+
| ツール名 | 説明 |
|
|
152
|
+
|---------|------|
|
|
153
|
+
| `pattern_extract` | コードからパターンを抽出 |
|
|
154
|
+
| `pattern_compress` | パターンの抽象化・圧縮 |
|
|
155
|
+
| `pattern_store` | パターンライブラリへの保存 |
|
|
156
|
+
| `pattern_query` | パターンの検索・取得 |
|
|
157
|
+
| `pattern_consolidate` | 類似パターンの統合 |
|
|
158
|
+
| `ontology_query` | オントロジーグラフへのクエリ |
|
|
159
|
+
| `ontology_infer` | オントロジーによる推論実行 |
|
|
160
|
+
|
|
138
161
|
### プロンプト一覧(3プロンプト)
|
|
139
162
|
|
|
140
163
|
| プロンプト名 | 説明 |
|
|
@@ -275,9 +298,29 @@ npx musubix codegen generate <design.md> --output src/
|
|
|
275
298
|
フィードバック → パターン候補 → 閾値超過 → パターン登録 → 推論に適用
|
|
276
299
|
```
|
|
277
300
|
|
|
301
|
+
### 6. Wake-Sleep学習サイクル(v1.3.0 NEW!)
|
|
302
|
+
|
|
303
|
+
Wake-Sleepアルゴリズムに基づいた継続的学習システム:
|
|
304
|
+
|
|
305
|
+
| フェーズ | 処理内容 |
|
|
306
|
+
|---------|----------|
|
|
307
|
+
| **Wake** | コード観察 → パターン抽出 → 知識グラフ更新 |
|
|
308
|
+
| **Sleep** | パターン統合 → 類似パターン圧縮 → メモリ最適化 |
|
|
309
|
+
|
|
310
|
+
```
|
|
311
|
+
Wake Phase: observe() → extractPatterns() → updateKnowledge()
|
|
312
|
+
Sleep Phase: consolidate() → compress() → optimize()
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
**主要コンポーネント**:
|
|
316
|
+
- `WakeSleepCycle`: 学習サイクル全体の制御
|
|
317
|
+
- `PatternLibrary`: 学習済みパターンの永続化管理
|
|
318
|
+
- `PatternOntologyBridge`: パターン↔オントロジー相互変換
|
|
319
|
+
- `N3Store`: RDF/OWLベースの知識グラフストレージ
|
|
320
|
+
|
|
278
321
|
---
|
|
279
322
|
|
|
280
|
-
##
|
|
323
|
+
## 📚 学習済みベストプラクティス(v1.1.10 Updated!)
|
|
281
324
|
|
|
282
325
|
Project-07〜14の実装から学習したパターンです。
|
|
283
326
|
|
|
@@ -424,6 +467,6 @@ npx musubix learn best-practices --format markdown
|
|
|
424
467
|
---
|
|
425
468
|
|
|
426
469
|
**Agent**: GitHub Copilot / Claude
|
|
427
|
-
**Last Updated**:
|
|
428
|
-
**Version**: 1.
|
|
470
|
+
**Last Updated**: 2025-01-10
|
|
471
|
+
**Version**: 1.3.0
|
|
429
472
|
**Repository**: https://github.com/nahisaho/MUSUBIX
|
package/dist/index.d.ts
CHANGED
|
@@ -20,6 +20,10 @@ export * from './codegen/index.js';
|
|
|
20
20
|
export * from './explanation/index.js';
|
|
21
21
|
export * from './error/index.js';
|
|
22
22
|
export * from './learning/index.js';
|
|
23
|
+
import * as symbolic from './symbolic/index.js';
|
|
24
|
+
export { symbolic };
|
|
25
|
+
export { createSymbolicPipeline, processSymbolic, SemanticCodeFilterPipeline, HallucinationDetector, ProjectSymbolIndex, ConstitutionRuleRegistry, ConfidenceEstimator, ConfidenceBasedRouter, ErrorHandler, DEFAULT_CONSTITUTION_RULES, checkArticleI, checkArticleII, checkArticleIII, checkArticleIV, checkArticleV, checkArticleVI, checkArticleVII, checkArticleVIII, checkArticleIX, EarsToFormalSpecConverter, VerificationConditionGenerator, Z3Adapter, PreconditionVerifier, PostconditionVerifier, InvariantVerifier, } from './symbolic/index.js';
|
|
26
|
+
export type { FilterInput, FilterOutput, CodeCandidate, ProjectContext, SymbolInfo, HallucinationItem, HallucinationResult, ConstitutionRule, ConstitutionCheckInput, ConstitutionCheckResult, ConstitutionReport, ConfidenceEstimation, ConfidenceBreakdown, RiskFactor, RoutingResult, RoutingDecision, VerificationRequirement, RecoveryResult, ErrorClassification, FallbackAction, AuditLogEntry, EarsRequirement, EarsPatternType, EarsAstNode, SmtLibOutput, FormalSpecification, VerificationCondition, VcGenerationResult, Z3Result, FormalVerificationResult, } from './symbolic/index.js';
|
|
23
27
|
/**
|
|
24
28
|
* Core Library Entry Point
|
|
25
29
|
*
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAGH,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAGvC,cAAc,kBAAkB,CAAC;AAGjC,cAAc,kBAAkB,CAAC;AAGjC,cAAc,gBAAgB,CAAC;AAG/B,cAAc,uBAAuB,CAAC;AAGtC,cAAc,yBAAyB,CAAC;AAGxC,cAAc,mBAAmB,CAAC;AAGlC,cAAc,oBAAoB,CAAC;AAGnC,cAAc,wBAAwB,CAAC;AAGvC,cAAc,kBAAkB,CAAC;AAGjC,cAAc,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAGH,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAGvC,cAAc,kBAAkB,CAAC;AAGjC,cAAc,kBAAkB,CAAC;AAGjC,cAAc,gBAAgB,CAAC;AAG/B,cAAc,uBAAuB,CAAC;AAGtC,cAAc,yBAAyB,CAAC;AAGxC,cAAc,mBAAmB,CAAC;AAGlC,cAAc,oBAAoB,CAAC;AAGnC,cAAc,wBAAwB,CAAC;AAGvC,cAAc,kBAAkB,CAAC;AAGjC,cAAc,qBAAqB,CAAC;AAIpC,OAAO,KAAK,QAAQ,MAAM,qBAAqB,CAAC;AAChD,OAAO,EAAE,QAAQ,EAAE,CAAC;AAGpB,OAAO,EACL,sBAAsB,EACtB,eAAe,EACf,0BAA0B,EAC1B,qBAAqB,EACrB,kBAAkB,EAClB,wBAAwB,EACxB,mBAAmB,EACnB,qBAAqB,EACrB,YAAY,EACZ,0BAA0B,EAC1B,aAAa,EACb,cAAc,EACd,eAAe,EACf,cAAc,EACd,aAAa,EACb,cAAc,EACd,eAAe,EACf,gBAAgB,EAChB,cAAc,EAEd,yBAAyB,EACzB,8BAA8B,EAC9B,SAAS,EACT,oBAAoB,EACpB,qBAAqB,EACrB,iBAAiB,GAClB,MAAM,qBAAqB,CAAC;AAG7B,YAAY,EACV,WAAW,EACX,YAAY,EACZ,aAAa,EACb,cAAc,EACd,UAAU,EACV,iBAAiB,EACjB,mBAAmB,EACnB,gBAAgB,EAChB,sBAAsB,EACtB,uBAAuB,EACvB,kBAAkB,EAClB,oBAAoB,EACpB,mBAAmB,EACnB,UAAU,EACV,aAAa,EACb,eAAe,EACf,uBAAuB,EACvB,cAAc,EACd,mBAAmB,EACnB,cAAc,EACd,aAAa,EAEb,eAAe,EACf,eAAe,EACf,WAAW,EACX,YAAY,EACZ,mBAAmB,EACnB,qBAAqB,EACrB,kBAAkB,EAClB,QAAQ,EACR,wBAAwB,GACzB,MAAM,qBAAqB,CAAC;AAO7B;;;;;;;;;;GAUG"}
|
package/dist/index.js
CHANGED
|
@@ -31,6 +31,14 @@ export * from './explanation/index.js';
|
|
|
31
31
|
export * from './error/index.js';
|
|
32
32
|
// Export learning system
|
|
33
33
|
export * from './learning/index.js';
|
|
34
|
+
// Export symbolic reasoning (Neuro-Symbolic Integration)
|
|
35
|
+
// Use namespace import to avoid name collisions with existing types
|
|
36
|
+
import * as symbolic from './symbolic/index.js';
|
|
37
|
+
export { symbolic };
|
|
38
|
+
// Re-export key symbolic functions at top level for convenience
|
|
39
|
+
export { createSymbolicPipeline, processSymbolic, SemanticCodeFilterPipeline, HallucinationDetector, ProjectSymbolIndex, ConstitutionRuleRegistry, ConfidenceEstimator, ConfidenceBasedRouter, ErrorHandler, DEFAULT_CONSTITUTION_RULES, checkArticleI, checkArticleII, checkArticleIII, checkArticleIV, checkArticleV, checkArticleVI, checkArticleVII, checkArticleVIII, checkArticleIX,
|
|
40
|
+
// Phase 2: Formal Verification
|
|
41
|
+
EarsToFormalSpecConverter, VerificationConditionGenerator, Z3Adapter, PreconditionVerifier, PostconditionVerifier, InvariantVerifier, } from './symbolic/index.js';
|
|
34
42
|
// Re-export modules (will be implemented in subsequent tasks)
|
|
35
43
|
// export * from './integrator/index.js';
|
|
36
44
|
// export * from './requirements/index.js';
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,UAAU;AACV,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAEvC,eAAe;AACf,cAAc,kBAAkB,CAAC;AAEjC,mBAAmB;AACnB,cAAc,kBAAkB,CAAC;AAEjC,aAAa;AACb,cAAc,gBAAgB,CAAC;AAE/B,oBAAoB;AACpB,cAAc,uBAAuB,CAAC;AAEtC,sBAAsB;AACtB,cAAc,yBAAyB,CAAC;AAExC,gBAAgB;AAChB,cAAc,mBAAmB,CAAC;AAElC,yBAAyB;AACzB,cAAc,oBAAoB,CAAC;AAEnC,qBAAqB;AACrB,cAAc,wBAAwB,CAAC;AAEvC,wBAAwB;AACxB,cAAc,kBAAkB,CAAC;AAEjC,yBAAyB;AACzB,cAAc,qBAAqB,CAAC;AAEpC,8DAA8D;AAC9D,yCAAyC;AACzC,2CAA2C;AAC3C,sCAAsC;AAEtC;;;;;;;;;;GAUG"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,UAAU;AACV,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAEvC,eAAe;AACf,cAAc,kBAAkB,CAAC;AAEjC,mBAAmB;AACnB,cAAc,kBAAkB,CAAC;AAEjC,aAAa;AACb,cAAc,gBAAgB,CAAC;AAE/B,oBAAoB;AACpB,cAAc,uBAAuB,CAAC;AAEtC,sBAAsB;AACtB,cAAc,yBAAyB,CAAC;AAExC,gBAAgB;AAChB,cAAc,mBAAmB,CAAC;AAElC,yBAAyB;AACzB,cAAc,oBAAoB,CAAC;AAEnC,qBAAqB;AACrB,cAAc,wBAAwB,CAAC;AAEvC,wBAAwB;AACxB,cAAc,kBAAkB,CAAC;AAEjC,yBAAyB;AACzB,cAAc,qBAAqB,CAAC;AAEpC,yDAAyD;AACzD,oEAAoE;AACpE,OAAO,KAAK,QAAQ,MAAM,qBAAqB,CAAC;AAChD,OAAO,EAAE,QAAQ,EAAE,CAAC;AAEpB,gEAAgE;AAChE,OAAO,EACL,sBAAsB,EACtB,eAAe,EACf,0BAA0B,EAC1B,qBAAqB,EACrB,kBAAkB,EAClB,wBAAwB,EACxB,mBAAmB,EACnB,qBAAqB,EACrB,YAAY,EACZ,0BAA0B,EAC1B,aAAa,EACb,cAAc,EACd,eAAe,EACf,cAAc,EACd,aAAa,EACb,cAAc,EACd,eAAe,EACf,gBAAgB,EAChB,cAAc;AACd,+BAA+B;AAC/B,yBAAyB,EACzB,8BAA8B,EAC9B,SAAS,EACT,oBAAoB,EACpB,qBAAqB,EACrB,iBAAiB,GAClB,MAAM,qBAAqB,CAAC;AAqC7B,8DAA8D;AAC9D,yCAAyC;AACzC,2CAA2C;AAC3C,sCAAsC;AAEtC;;;;;;;;;;GAUG"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ears-to-formal.test.d.ts","sourceRoot":"","sources":["../../../src/symbolic/__tests__/ears-to-formal.test.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG"}
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* EARS to Formal Spec Converter Tests
|
|
3
|
+
*
|
|
4
|
+
* Tests for EARS requirement parsing and SMT-LIB generation.
|
|
5
|
+
*
|
|
6
|
+
* @see TSK-SYMB-009
|
|
7
|
+
*/
|
|
8
|
+
import { describe, it, expect, beforeEach } from 'vitest';
|
|
9
|
+
import { EarsToFormalSpecConverter, parseEarsRequirement, generateSmtLib, } from '../ears-to-formal.js';
|
|
10
|
+
describe('EarsToFormalSpecConverter', () => {
|
|
11
|
+
let converter;
|
|
12
|
+
beforeEach(() => {
|
|
13
|
+
converter = new EarsToFormalSpecConverter();
|
|
14
|
+
});
|
|
15
|
+
describe('parseEarsRequirement', () => {
|
|
16
|
+
it('should parse ubiquitous pattern (THE system SHALL requirement)', () => {
|
|
17
|
+
const result = parseEarsRequirement('REQ-001', 'THE system SHALL validate all user inputs');
|
|
18
|
+
expect(result.success).toBe(true);
|
|
19
|
+
if (result.success) {
|
|
20
|
+
expect(result.ast.pattern).toBe('ubiquitous');
|
|
21
|
+
expect(result.ast.system).toBe('system');
|
|
22
|
+
expect(result.ast.requirement).toBe('validate all user inputs');
|
|
23
|
+
expect(result.ast.requirementId).toBe('REQ-001');
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
it('should parse event-driven pattern (WHEN event, THE system SHALL response)', () => {
|
|
27
|
+
const result = parseEarsRequirement('REQ-002', 'WHEN user clicks submit, THE system SHALL save the form data');
|
|
28
|
+
expect(result.success).toBe(true);
|
|
29
|
+
if (result.success) {
|
|
30
|
+
expect(result.ast.pattern).toBe('event-driven');
|
|
31
|
+
expect(result.ast.event).toBe('user clicks submit');
|
|
32
|
+
expect(result.ast.system).toBe('system');
|
|
33
|
+
expect(result.ast.requirement).toBe('save the form data');
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
it('should parse state-driven pattern (WHILE state, THE system SHALL response)', () => {
|
|
37
|
+
const result = parseEarsRequirement('REQ-003', 'WHILE system is in maintenance mode, THE API SHALL return 503 status');
|
|
38
|
+
expect(result.success).toBe(true);
|
|
39
|
+
if (result.success) {
|
|
40
|
+
expect(result.ast.pattern).toBe('state-driven');
|
|
41
|
+
expect(result.ast.state).toBe('system is in maintenance mode');
|
|
42
|
+
expect(result.ast.system).toBe('API');
|
|
43
|
+
expect(result.ast.requirement).toBe('return 503 status');
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
it('should parse unwanted pattern (THE system SHALL NOT behavior)', () => {
|
|
47
|
+
const result = parseEarsRequirement('REQ-004', 'THE system SHALL NOT store passwords in plain text');
|
|
48
|
+
expect(result.success).toBe(true);
|
|
49
|
+
if (result.success) {
|
|
50
|
+
expect(result.ast.pattern).toBe('unwanted');
|
|
51
|
+
expect(result.ast.system).toBe('system');
|
|
52
|
+
expect(result.ast.unwantedBehavior).toBe('store passwords in plain text');
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
it('should parse optional pattern (IF condition, THEN THE system SHALL response)', () => {
|
|
56
|
+
const result = parseEarsRequirement('REQ-005', 'IF user is premium, THEN THE system SHALL provide advanced features');
|
|
57
|
+
expect(result.success).toBe(true);
|
|
58
|
+
if (result.success) {
|
|
59
|
+
expect(result.ast.pattern).toBe('optional');
|
|
60
|
+
expect(result.ast.condition).toBe('user is premium');
|
|
61
|
+
expect(result.ast.system).toBe('system');
|
|
62
|
+
expect(result.ast.requirement).toBe('provide advanced features');
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
it('should return error for non-EARS format', () => {
|
|
66
|
+
const result = parseEarsRequirement('REQ-006', 'The system should work properly');
|
|
67
|
+
expect(result.success).toBe(false);
|
|
68
|
+
if (!result.success) {
|
|
69
|
+
expect(result.error).toContain('EARS pattern');
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
it('should be case-insensitive for keywords', () => {
|
|
73
|
+
const result = parseEarsRequirement('REQ-007', 'the System shall Process all requests');
|
|
74
|
+
expect(result.success).toBe(true);
|
|
75
|
+
if (result.success) {
|
|
76
|
+
expect(result.ast.pattern).toBe('ubiquitous');
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
describe('generateSmtLib', () => {
|
|
81
|
+
it('should generate SMT-LIB for ubiquitous pattern', () => {
|
|
82
|
+
const ast = {
|
|
83
|
+
requirementId: 'REQ-001',
|
|
84
|
+
pattern: 'ubiquitous',
|
|
85
|
+
system: 'system',
|
|
86
|
+
requirement: 'validate inputs',
|
|
87
|
+
originalText: 'THE system SHALL validate inputs',
|
|
88
|
+
parsedAt: new Date().toISOString(),
|
|
89
|
+
};
|
|
90
|
+
const result = generateSmtLib(ast);
|
|
91
|
+
expect(result.smtLib).toContain('REQ-001');
|
|
92
|
+
expect(result.smtLib).toContain('declare-const');
|
|
93
|
+
expect(result.requirementId).toBe('REQ-001');
|
|
94
|
+
expect(result.variables.length).toBeGreaterThan(0);
|
|
95
|
+
expect(result.assertions.length).toBeGreaterThan(0);
|
|
96
|
+
});
|
|
97
|
+
it('should generate SMT-LIB for event-driven pattern with implication', () => {
|
|
98
|
+
const ast = {
|
|
99
|
+
requirementId: 'REQ-002',
|
|
100
|
+
pattern: 'event-driven',
|
|
101
|
+
system: 'system',
|
|
102
|
+
requirement: 'respond quickly',
|
|
103
|
+
event: 'user clicks',
|
|
104
|
+
originalText: 'WHEN user clicks, THE system SHALL respond quickly',
|
|
105
|
+
parsedAt: new Date().toISOString(),
|
|
106
|
+
};
|
|
107
|
+
const result = generateSmtLib(ast);
|
|
108
|
+
expect(result.smtLib).toContain('user_clicks');
|
|
109
|
+
// Event-driven pattern should have implication logic
|
|
110
|
+
expect(result.assertions.length).toBeGreaterThan(0);
|
|
111
|
+
});
|
|
112
|
+
it('should generate SMT-LIB for unwanted pattern with negation', () => {
|
|
113
|
+
const ast = {
|
|
114
|
+
requirementId: 'REQ-003',
|
|
115
|
+
pattern: 'unwanted',
|
|
116
|
+
system: 'system',
|
|
117
|
+
requirement: 'NOT store plaintext',
|
|
118
|
+
unwantedBehavior: 'store plaintext',
|
|
119
|
+
originalText: 'THE system SHALL NOT store plaintext',
|
|
120
|
+
parsedAt: new Date().toISOString(),
|
|
121
|
+
};
|
|
122
|
+
const result = generateSmtLib(ast);
|
|
123
|
+
expect(result.smtLib).toContain('not');
|
|
124
|
+
});
|
|
125
|
+
it('should include explanation with reasoning', () => {
|
|
126
|
+
const ast = {
|
|
127
|
+
requirementId: 'REQ-004',
|
|
128
|
+
pattern: 'ubiquitous',
|
|
129
|
+
system: 'API',
|
|
130
|
+
requirement: 'return JSON',
|
|
131
|
+
originalText: 'THE API SHALL return JSON',
|
|
132
|
+
parsedAt: new Date().toISOString(),
|
|
133
|
+
};
|
|
134
|
+
const result = generateSmtLib(ast);
|
|
135
|
+
expect(result.explanation.summary).toContain('SMT-LIB');
|
|
136
|
+
expect(result.explanation.reasoning.length).toBeGreaterThan(0);
|
|
137
|
+
expect(result.explanation.relatedRequirements).toContain('REQ-004');
|
|
138
|
+
});
|
|
139
|
+
});
|
|
140
|
+
describe('EarsToFormalSpecConverter class', () => {
|
|
141
|
+
it('should parse requirements using parse method', () => {
|
|
142
|
+
const result = converter.parse('REQ-001', 'THE system SHALL work');
|
|
143
|
+
expect(result.success).toBe(true);
|
|
144
|
+
});
|
|
145
|
+
it('should convert single requirement to SMT-LIB', () => {
|
|
146
|
+
const result = converter.convert({
|
|
147
|
+
id: 'REQ-001',
|
|
148
|
+
text: 'THE system SHALL validate inputs',
|
|
149
|
+
type: 'ubiquitous',
|
|
150
|
+
});
|
|
151
|
+
expect(result.smtLib).toBeTruthy();
|
|
152
|
+
expect(result.requirementId).toBe('REQ-001');
|
|
153
|
+
});
|
|
154
|
+
it('should handle parse errors gracefully in convert', () => {
|
|
155
|
+
const result = converter.convert({
|
|
156
|
+
id: 'REQ-INVALID',
|
|
157
|
+
text: 'This is not EARS format',
|
|
158
|
+
type: 'ubiquitous',
|
|
159
|
+
});
|
|
160
|
+
expect(result.smtLib).toContain('Error');
|
|
161
|
+
expect(result.explanation.summary).toContain('Failed');
|
|
162
|
+
});
|
|
163
|
+
it('should convert multiple requirements', () => {
|
|
164
|
+
const requirements = [
|
|
165
|
+
{ id: 'REQ-001', text: 'THE system SHALL validate inputs', type: 'ubiquitous' },
|
|
166
|
+
{ id: 'REQ-002', text: 'WHEN error occurs, THE system SHALL log it', type: 'event-driven' },
|
|
167
|
+
];
|
|
168
|
+
const result = converter.convertAll(requirements);
|
|
169
|
+
expect(result.astNodes.length).toBe(2);
|
|
170
|
+
expect(result.smtOutputs.length).toBe(2);
|
|
171
|
+
expect(result.combinedSmtLib).toContain('REQ-001');
|
|
172
|
+
expect(result.combinedSmtLib).toContain('REQ-002');
|
|
173
|
+
});
|
|
174
|
+
it('should generate combined SMT-LIB with all requirements', () => {
|
|
175
|
+
const requirements = [
|
|
176
|
+
{ id: 'REQ-001', text: 'THE API SHALL return JSON', type: 'ubiquitous' },
|
|
177
|
+
{ id: 'REQ-002', text: 'THE API SHALL NOT leak secrets', type: 'unwanted' },
|
|
178
|
+
];
|
|
179
|
+
const result = converter.convertAll(requirements);
|
|
180
|
+
expect(result.combinedSmtLib).toContain('Combined');
|
|
181
|
+
expect(result.combinedSmtLib).toContain('check-sat');
|
|
182
|
+
expect(result.explanation.relatedRequirements).toContain('REQ-001');
|
|
183
|
+
expect(result.explanation.relatedRequirements).toContain('REQ-002');
|
|
184
|
+
});
|
|
185
|
+
});
|
|
186
|
+
});
|
|
187
|
+
//# sourceMappingURL=ears-to-formal.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ears-to-formal.test.js","sourceRoot":"","sources":["../../../src/symbolic/__tests__/ears-to-formal.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"quality-gate.test.d.ts","sourceRoot":"","sources":["../../../src/symbolic/__tests__/quality-gate.test.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG"}
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Quality Gate Validator Tests
|
|
3
|
+
*
|
|
4
|
+
* Tests for TSK-SYMB-019: Quality Gate validation
|
|
5
|
+
*
|
|
6
|
+
* @module quality-gate.test
|
|
7
|
+
*/
|
|
8
|
+
import { describe, it, expect, beforeEach } from 'vitest';
|
|
9
|
+
import { QualityGateValidator, createComponentValidation, } from '../quality-gate.js';
|
|
10
|
+
describe('QualityGateValidator', () => {
|
|
11
|
+
let validator;
|
|
12
|
+
let fullTraceability;
|
|
13
|
+
let fullComponents;
|
|
14
|
+
beforeEach(() => {
|
|
15
|
+
validator = new QualityGateValidator();
|
|
16
|
+
// Create full traceability for 27 requirements
|
|
17
|
+
fullTraceability = [
|
|
18
|
+
// Semantic Filter requirements
|
|
19
|
+
{ requirementId: 'REQ-SF-001', designIds: ['DES-001'], taskIds: ['TSK-001'], testIds: ['TEST-001'], coveragePercent: 100 },
|
|
20
|
+
{ requirementId: 'REQ-SF-002', designIds: ['DES-001'], taskIds: ['TSK-001'], testIds: ['TEST-002'], coveragePercent: 100 },
|
|
21
|
+
{ requirementId: 'REQ-SF-003', designIds: ['DES-001'], taskIds: ['TSK-002'], testIds: ['TEST-003'], coveragePercent: 100 },
|
|
22
|
+
// Formal Verification requirements
|
|
23
|
+
{ requirementId: 'REQ-FV-001', designIds: ['DES-002'], taskIds: ['TSK-003'], testIds: ['TEST-004'], coveragePercent: 100 },
|
|
24
|
+
{ requirementId: 'REQ-FV-002', designIds: ['DES-002'], taskIds: ['TSK-003'], testIds: ['TEST-005'], coveragePercent: 100 },
|
|
25
|
+
{ requirementId: 'REQ-FV-003', designIds: ['DES-002'], taskIds: ['TSK-004'], testIds: ['TEST-006'], coveragePercent: 100 },
|
|
26
|
+
{ requirementId: 'REQ-FV-004', designIds: ['DES-002'], taskIds: ['TSK-004'], testIds: ['TEST-007'], coveragePercent: 100 },
|
|
27
|
+
{ requirementId: 'REQ-FV-005', designIds: ['DES-002'], taskIds: ['TSK-005'], testIds: ['TEST-008'], coveragePercent: 100 },
|
|
28
|
+
// Constitution requirements
|
|
29
|
+
{ requirementId: 'REQ-CONST-001', designIds: ['DES-003'], taskIds: ['TSK-006'], testIds: ['TEST-009'], coveragePercent: 100 },
|
|
30
|
+
{ requirementId: 'REQ-CONST-002', designIds: ['DES-003'], taskIds: ['TSK-006'], testIds: ['TEST-010'], coveragePercent: 100 },
|
|
31
|
+
{ requirementId: 'REQ-CONST-003', designIds: ['DES-003'], taskIds: ['TSK-007'], testIds: ['TEST-011'], coveragePercent: 100 },
|
|
32
|
+
{ requirementId: 'REQ-CONST-004', designIds: ['DES-003'], taskIds: ['TSK-007'], testIds: ['TEST-012'], coveragePercent: 100 },
|
|
33
|
+
{ requirementId: 'REQ-CONST-005', designIds: ['DES-003'], taskIds: ['TSK-008'], testIds: ['TEST-013'], coveragePercent: 100 },
|
|
34
|
+
{ requirementId: 'REQ-CONST-006', designIds: ['DES-003'], taskIds: ['TSK-008'], testIds: ['TEST-014'], coveragePercent: 100 },
|
|
35
|
+
{ requirementId: 'REQ-CONST-007', designIds: ['DES-003'], taskIds: ['TSK-009'], testIds: ['TEST-015'], coveragePercent: 100 },
|
|
36
|
+
{ requirementId: 'REQ-CONST-008', designIds: ['DES-003'], taskIds: ['TSK-009'], testIds: ['TEST-016'], coveragePercent: 100 },
|
|
37
|
+
{ requirementId: 'REQ-CONST-009', designIds: ['DES-003'], taskIds: ['TSK-010'], testIds: ['TEST-017'], coveragePercent: 100 },
|
|
38
|
+
{ requirementId: 'REQ-CONST-010', designIds: ['DES-003'], taskIds: ['TSK-010'], testIds: ['TEST-018'], coveragePercent: 100 },
|
|
39
|
+
// Routing requirements
|
|
40
|
+
{ requirementId: 'REQ-ROUTE-001', designIds: ['DES-004'], taskIds: ['TSK-011'], testIds: ['TEST-019'], coveragePercent: 100 },
|
|
41
|
+
{ requirementId: 'REQ-ROUTE-002', designIds: ['DES-004'], taskIds: ['TSK-011'], testIds: ['TEST-020'], coveragePercent: 100 },
|
|
42
|
+
{ requirementId: 'REQ-ROUTE-003', designIds: ['DES-004'], taskIds: ['TSK-012'], testIds: ['TEST-021'], coveragePercent: 100 },
|
|
43
|
+
// Non-functional requirements
|
|
44
|
+
{ requirementId: 'REQ-NFR-001', designIds: ['DES-005'], taskIds: ['TSK-013'], testIds: ['TEST-022'], coveragePercent: 100 },
|
|
45
|
+
{ requirementId: 'REQ-NFR-002', designIds: ['DES-005'], taskIds: ['TSK-013'], testIds: ['TEST-023'], coveragePercent: 100 },
|
|
46
|
+
{ requirementId: 'REQ-NFR-003', designIds: ['DES-005'], taskIds: ['TSK-014'], testIds: ['TEST-024'], coveragePercent: 100 },
|
|
47
|
+
{ requirementId: 'REQ-NFR-004', designIds: ['DES-005'], taskIds: ['TSK-014'], testIds: ['TEST-025'], coveragePercent: 100 },
|
|
48
|
+
{ requirementId: 'REQ-NFR-005', designIds: ['DES-005'], taskIds: ['TSK-015'], testIds: ['TEST-026'], coveragePercent: 100 },
|
|
49
|
+
{ requirementId: 'REQ-NFR-006', designIds: ['DES-005'], taskIds: ['TSK-015'], testIds: ['TEST-027'], coveragePercent: 100 },
|
|
50
|
+
];
|
|
51
|
+
// Create fully compliant component validation
|
|
52
|
+
fullComponents = createComponentValidation({
|
|
53
|
+
performanceBudgetDefined: true,
|
|
54
|
+
extensibleConfigDefined: true,
|
|
55
|
+
explanationGeneratorDefined: true,
|
|
56
|
+
securityMaskingDefined: true,
|
|
57
|
+
auditLoggingDefined: true,
|
|
58
|
+
libraryFirstCompliant: true,
|
|
59
|
+
cliInterfaceDefined: true,
|
|
60
|
+
testFirstCompliant: true,
|
|
61
|
+
earsFormatCompliant: true,
|
|
62
|
+
traceabilityCompliant: true,
|
|
63
|
+
projectMemoryCompliant: true,
|
|
64
|
+
designPatternsDocumented: true,
|
|
65
|
+
adrCompliant: true,
|
|
66
|
+
qualityGatesConfigured: true,
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
describe('validate', () => {
|
|
70
|
+
it('should pass when all criteria are met', () => {
|
|
71
|
+
const result = validator.validate(fullTraceability, fullComponents);
|
|
72
|
+
expect(result.passed).toBe(true);
|
|
73
|
+
expect(result.gateName).toBe('DES-SYMB-001 Implementation Gate');
|
|
74
|
+
expect(result.phase).toBe('design');
|
|
75
|
+
expect(result.summary.blockerCount).toBe(0);
|
|
76
|
+
expect(result.summary.criticalCount).toBe(0);
|
|
77
|
+
});
|
|
78
|
+
it('should fail when design coverage is incomplete', () => {
|
|
79
|
+
// Remove design IDs from some requirements
|
|
80
|
+
const incompleteTraceability = fullTraceability.map((t, i) => i < 3 ? { ...t, designIds: [] } : t);
|
|
81
|
+
const result = validator.validate(incompleteTraceability, fullComponents);
|
|
82
|
+
expect(result.passed).toBe(false);
|
|
83
|
+
expect(result.summary.blockerCount).toBeGreaterThan(0);
|
|
84
|
+
const designCheck = result.checks.find(c => c.checkId === 'QG-TRACE-001');
|
|
85
|
+
expect(designCheck?.passed).toBe(false);
|
|
86
|
+
});
|
|
87
|
+
it('should fail when performance budget is not defined', () => {
|
|
88
|
+
const incompleteComponents = createComponentValidation({
|
|
89
|
+
...fullComponents,
|
|
90
|
+
performanceBudgetDefined: false,
|
|
91
|
+
});
|
|
92
|
+
const result = validator.validate(fullTraceability, incompleteComponents);
|
|
93
|
+
expect(result.passed).toBe(false);
|
|
94
|
+
const perfCheck = result.checks.find(c => c.checkId === 'QG-NFR-001');
|
|
95
|
+
expect(perfCheck?.passed).toBe(false);
|
|
96
|
+
expect(perfCheck?.severity).toBe('blocker');
|
|
97
|
+
});
|
|
98
|
+
it('should fail when audit logging is not defined', () => {
|
|
99
|
+
const incompleteComponents = createComponentValidation({
|
|
100
|
+
...fullComponents,
|
|
101
|
+
auditLoggingDefined: false,
|
|
102
|
+
});
|
|
103
|
+
const result = validator.validate(fullTraceability, incompleteComponents);
|
|
104
|
+
expect(result.passed).toBe(false);
|
|
105
|
+
const auditCheck = result.checks.find(c => c.checkId === 'QG-SEC-002');
|
|
106
|
+
expect(auditCheck?.passed).toBe(false);
|
|
107
|
+
expect(auditCheck?.severity).toBe('blocker');
|
|
108
|
+
});
|
|
109
|
+
it('should check all 9 Constitution articles', () => {
|
|
110
|
+
const result = validator.validate(fullTraceability, fullComponents);
|
|
111
|
+
const constitutionChecks = result.checks.filter(c => c.category === 'constitution');
|
|
112
|
+
expect(constitutionChecks.length).toBe(9);
|
|
113
|
+
// All should pass
|
|
114
|
+
for (const check of constitutionChecks) {
|
|
115
|
+
expect(check.passed).toBe(true);
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
it('should fail for non-compliant Constitution articles', () => {
|
|
119
|
+
const incompleteComponents = createComponentValidation({
|
|
120
|
+
...fullComponents,
|
|
121
|
+
traceabilityCompliant: false, // Article V
|
|
122
|
+
});
|
|
123
|
+
const result = validator.validate(fullTraceability, incompleteComponents);
|
|
124
|
+
expect(result.passed).toBe(false);
|
|
125
|
+
const articleVCheck = result.checks.find(c => c.checkId === 'QG-CONST-V');
|
|
126
|
+
expect(articleVCheck?.passed).toBe(false);
|
|
127
|
+
expect(articleVCheck?.severity).toBe('blocker'); // Article V is blocker
|
|
128
|
+
});
|
|
129
|
+
it('should include explanation with reasoning', () => {
|
|
130
|
+
const result = validator.validate(fullTraceability, fullComponents);
|
|
131
|
+
expect(result.explanation).toBeDefined();
|
|
132
|
+
expect(result.explanation.summary).toContain('PASSED');
|
|
133
|
+
expect(result.explanation.reasoning.length).toBeGreaterThan(0);
|
|
134
|
+
expect(result.explanation.evidence.length).toBeGreaterThan(0);
|
|
135
|
+
});
|
|
136
|
+
});
|
|
137
|
+
describe('custom configuration', () => {
|
|
138
|
+
it('should use custom min design coverage', () => {
|
|
139
|
+
const customConfig = {
|
|
140
|
+
minDesignCoverage: 90,
|
|
141
|
+
};
|
|
142
|
+
const customValidator = new QualityGateValidator(customConfig);
|
|
143
|
+
// Remove design from ~5% of requirements (2 out of 27)
|
|
144
|
+
const partialTraceability = fullTraceability.map((t, i) => i < 2 ? { ...t, designIds: [] } : t);
|
|
145
|
+
const result = customValidator.validate(partialTraceability, fullComponents);
|
|
146
|
+
// 25/27 = 92.6% > 90%, should pass
|
|
147
|
+
const designCheck = result.checks.find(c => c.checkId === 'QG-TRACE-001');
|
|
148
|
+
expect(designCheck?.passed).toBe(true);
|
|
149
|
+
});
|
|
150
|
+
});
|
|
151
|
+
describe('generateApprovalReport', () => {
|
|
152
|
+
it('should generate markdown report for passed gate', () => {
|
|
153
|
+
const result = validator.validate(fullTraceability, fullComponents);
|
|
154
|
+
const report = validator.generateApprovalReport(result);
|
|
155
|
+
expect(report).toContain('# Quality Gate Approval Report');
|
|
156
|
+
expect(report).toContain('✅ PASSED');
|
|
157
|
+
expect(report).toContain('## Summary');
|
|
158
|
+
expect(report).toContain('## Traceability Checks');
|
|
159
|
+
expect(report).toContain('## Non-Functional Checks');
|
|
160
|
+
expect(report).toContain('## Security & Audit Checks');
|
|
161
|
+
expect(report).toContain('## Constitution Checks');
|
|
162
|
+
expect(report).toContain('## Approval Record');
|
|
163
|
+
});
|
|
164
|
+
it('should generate markdown report for failed gate', () => {
|
|
165
|
+
const incompleteComponents = createComponentValidation({
|
|
166
|
+
...fullComponents,
|
|
167
|
+
performanceBudgetDefined: false,
|
|
168
|
+
auditLoggingDefined: false,
|
|
169
|
+
});
|
|
170
|
+
const result = validator.validate(fullTraceability, incompleteComponents);
|
|
171
|
+
const report = validator.generateApprovalReport(result);
|
|
172
|
+
expect(report).toContain('❌ FAILED');
|
|
173
|
+
expect(report).toContain('🚫'); // Blocker icon
|
|
174
|
+
});
|
|
175
|
+
});
|
|
176
|
+
describe('createComponentValidation', () => {
|
|
177
|
+
it('should create validation with defaults', () => {
|
|
178
|
+
const validation = createComponentValidation({});
|
|
179
|
+
expect(validation.performanceBudgetDefined).toBe(false);
|
|
180
|
+
expect(validation.auditLoggingDefined).toBe(false);
|
|
181
|
+
expect(validation.libraryFirstCompliant).toBe(false);
|
|
182
|
+
});
|
|
183
|
+
it('should create validation with partial overrides', () => {
|
|
184
|
+
const validation = createComponentValidation({
|
|
185
|
+
performanceBudgetDefined: true,
|
|
186
|
+
auditLoggingDefined: true,
|
|
187
|
+
});
|
|
188
|
+
expect(validation.performanceBudgetDefined).toBe(true);
|
|
189
|
+
expect(validation.auditLoggingDefined).toBe(true);
|
|
190
|
+
expect(validation.extensibleConfigDefined).toBe(false);
|
|
191
|
+
});
|
|
192
|
+
});
|
|
193
|
+
describe('traceability checks', () => {
|
|
194
|
+
it('should detect coverage gaps', () => {
|
|
195
|
+
// Create traceability with gaps
|
|
196
|
+
const gappyTraceability = fullTraceability.map((t, i) => i % 3 === 0 ? { ...t, coveragePercent: 50 } : t);
|
|
197
|
+
const result = validator.validate(gappyTraceability, fullComponents);
|
|
198
|
+
const gapCheck = result.checks.find(c => c.checkId === 'QG-TRACE-003');
|
|
199
|
+
expect(gapCheck?.passed).toBe(false);
|
|
200
|
+
expect(gapCheck?.message).toContain('coverage gaps');
|
|
201
|
+
});
|
|
202
|
+
it('should report task coverage', () => {
|
|
203
|
+
const result = validator.validate(fullTraceability, fullComponents);
|
|
204
|
+
const taskCheck = result.checks.find(c => c.checkId === 'QG-TRACE-002');
|
|
205
|
+
expect(taskCheck?.passed).toBe(true);
|
|
206
|
+
expect(taskCheck?.message).toContain('100');
|
|
207
|
+
});
|
|
208
|
+
});
|
|
209
|
+
describe('edge cases', () => {
|
|
210
|
+
it('should handle empty traceability', () => {
|
|
211
|
+
const result = validator.validate([], fullComponents);
|
|
212
|
+
expect(result.checks.length).toBeGreaterThan(0);
|
|
213
|
+
// Design coverage should be 0% which fails
|
|
214
|
+
const designCheck = result.checks.find(c => c.checkId === 'QG-TRACE-001');
|
|
215
|
+
expect(designCheck?.passed).toBe(false);
|
|
216
|
+
});
|
|
217
|
+
it('should handle partial component validation', () => {
|
|
218
|
+
const partialComponents = createComponentValidation({
|
|
219
|
+
performanceBudgetDefined: true,
|
|
220
|
+
auditLoggingDefined: true,
|
|
221
|
+
// Everything else defaults to false
|
|
222
|
+
});
|
|
223
|
+
const result = validator.validate(fullTraceability, partialComponents);
|
|
224
|
+
// Should fail due to missing components
|
|
225
|
+
expect(result.passed).toBe(false);
|
|
226
|
+
expect(result.summary.criticalCount).toBeGreaterThan(0);
|
|
227
|
+
});
|
|
228
|
+
});
|
|
229
|
+
});
|
|
230
|
+
//# sourceMappingURL=quality-gate.test.js.map
|