@dommaker/harness 1.1.0 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +19 -2
- package/README.md +2 -4
- package/bin/harness.js +12 -37
- package/dist/cli/commands/check.d.ts +2 -2
- package/dist/cli/commands/check.d.ts.map +1 -1
- package/dist/cli/commands/check.js +7 -32
- package/dist/cli/commands/check.js.map +1 -1
- package/dist/cli/commands/definitions.d.ts +2 -0
- package/dist/cli/commands/definitions.d.ts.map +1 -1
- package/dist/cli/commands/definitions.js.map +1 -1
- package/dist/cli/commands/init.d.ts.map +1 -1
- package/dist/cli/commands/init.js +6 -37
- package/dist/cli/commands/init.js.map +1 -1
- package/dist/cli/commands/knowledge.d.ts.map +1 -1
- package/dist/cli/commands/knowledge.js +1 -12
- package/dist/cli/commands/knowledge.js.map +1 -1
- package/dist/cli/commands/report.d.ts.map +1 -1
- package/dist/cli/commands/report.js +0 -2
- package/dist/cli/commands/report.js.map +1 -1
- package/dist/cli/commands/status.d.ts.map +1 -1
- package/dist/cli/commands/status.js +2 -11
- package/dist/cli/commands/status.js.map +1 -1
- package/dist/context/index.d.ts +9 -6
- package/dist/context/index.d.ts.map +1 -1
- package/dist/context/index.js +18 -20
- package/dist/context/index.js.map +1 -1
- package/dist/core/constraints/capabilities-parser.d.ts +3 -2
- package/dist/core/constraints/capabilities-parser.d.ts.map +1 -1
- package/dist/core/constraints/capabilities-parser.js +25 -47
- package/dist/core/constraints/capabilities-parser.js.map +1 -1
- package/dist/core/constraints/checker.d.ts +32 -33
- package/dist/core/constraints/checker.d.ts.map +1 -1
- package/dist/core/constraints/checker.js +38 -128
- package/dist/core/constraints/checker.js.map +1 -1
- package/dist/core/constraints/checkers/index.d.ts +2 -1
- package/dist/core/constraints/checkers/index.d.ts.map +1 -1
- package/dist/core/constraints/checkers/index.js +3 -0
- package/dist/core/constraints/checkers/index.js.map +1 -1
- package/dist/core/constraints/checkers/types.d.ts +25 -0
- package/dist/core/constraints/checkers/types.d.ts.map +1 -1
- package/dist/core/constraints/checkers/types.js +24 -0
- package/dist/core/constraints/checkers/types.js.map +1 -1
- package/dist/core/constraints/definitions/guidelines.d.ts.map +1 -1
- package/dist/core/constraints/definitions/guidelines.js +0 -2
- package/dist/core/constraints/definitions/guidelines.js.map +1 -1
- package/dist/core/constraints/definitions/prompts.d.ts.map +1 -1
- package/dist/core/constraints/definitions/prompts.js +0 -5
- package/dist/core/constraints/definitions/prompts.js.map +1 -1
- package/dist/core/constraints/index.d.ts +1 -2
- package/dist/core/constraints/index.d.ts.map +1 -1
- package/dist/core/constraints/index.js +1 -7
- package/dist/core/constraints/index.js.map +1 -1
- package/dist/core/constraints/usage-report.d.ts +1 -2
- package/dist/core/constraints/usage-report.d.ts.map +1 -1
- package/dist/core/constraints/usage-report.js +2 -5
- package/dist/core/constraints/usage-report.js.map +1 -1
- package/dist/core/effective-constraints.d.ts +24 -4
- package/dist/core/effective-constraints.d.ts.map +1 -1
- package/dist/core/effective-constraints.js +28 -7
- package/dist/core/effective-constraints.js.map +1 -1
- package/dist/core/effective-set.d.ts +30 -0
- package/dist/core/effective-set.d.ts.map +1 -0
- package/dist/core/effective-set.js +35 -0
- package/dist/core/effective-set.js.map +1 -0
- package/dist/core/index.d.ts +13 -6
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +44 -21
- package/dist/core/index.js.map +1 -1
- package/dist/core/project-config-loader.d.ts +3 -6
- package/dist/core/project-config-loader.d.ts.map +1 -1
- package/dist/core/project-config-loader.js +47 -61
- package/dist/core/project-config-loader.js.map +1 -1
- package/dist/failure/constraint-handler.d.ts +1 -1
- package/dist/failure/constraint-handler.js +1 -1
- package/dist/gates/checker-gate.d.ts +1 -4
- package/dist/gates/checker-gate.d.ts.map +1 -1
- package/dist/gates/checker-gate.js +3 -11
- package/dist/gates/checker-gate.js.map +1 -1
- package/dist/gates/definitions.d.ts +9 -38
- package/dist/gates/definitions.d.ts.map +1 -1
- package/dist/gates/definitions.js +24 -13
- package/dist/gates/definitions.js.map +1 -1
- package/dist/gates/effective-gates.d.ts.map +1 -1
- package/dist/gates/effective-gates.js +14 -18
- package/dist/gates/effective-gates.js.map +1 -1
- package/dist/gates/index.d.ts +1 -1
- package/dist/gates/index.d.ts.map +1 -1
- package/dist/gates/index.js.map +1 -1
- package/dist/hooks/bootstrap.d.ts.map +1 -1
- package/dist/hooks/bootstrap.js +0 -3
- package/dist/hooks/bootstrap.js.map +1 -1
- package/dist/index.d.ts +43 -53
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +180 -138
- package/dist/index.js.map +1 -1
- package/dist/knowledge/query.d.ts +15 -0
- package/dist/knowledge/query.d.ts.map +1 -1
- package/dist/knowledge/query.js +23 -0
- package/dist/knowledge/query.js.map +1 -1
- package/dist/monitoring/analyzer-base.d.ts +0 -4
- package/dist/monitoring/analyzer-base.d.ts.map +1 -1
- package/dist/monitoring/analyzer-base.js +0 -21
- package/dist/monitoring/analyzer-base.js.map +1 -1
- package/dist/monitoring/index.d.ts +6 -12
- package/dist/monitoring/index.d.ts.map +1 -1
- package/dist/monitoring/index.js +13 -29
- package/dist/monitoring/index.js.map +1 -1
- package/dist/monitoring/trace-analyzer.d.ts.map +1 -1
- package/dist/monitoring/trace-analyzer.js +2 -68
- package/dist/monitoring/trace-analyzer.js.map +1 -1
- package/dist/monitoring/traces.d.ts +2 -6
- package/dist/monitoring/traces.d.ts.map +1 -1
- package/dist/monitoring/traces.js +0 -14
- package/dist/monitoring/traces.js.map +1 -1
- package/dist/presets/index.d.ts +2 -2
- package/dist/presets/index.d.ts.map +1 -1
- package/dist/presets/index.js +3 -4
- package/dist/presets/index.js.map +1 -1
- package/dist/presets/standard.d.ts +10 -22
- package/dist/presets/standard.d.ts.map +1 -1
- package/dist/presets/standard.js +15 -75
- package/dist/presets/standard.js.map +1 -1
- package/dist/types/constraint.d.ts +1 -29
- package/dist/types/constraint.d.ts.map +1 -1
- package/dist/types/constraint.js +1 -1
- package/dist/types/constraint.js.map +1 -1
- package/dist/types/index.d.ts +0 -3
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +0 -4
- package/dist/types/index.js.map +1 -1
- package/dist/types/project-config.d.ts +4 -8
- package/dist/types/project-config.d.ts.map +1 -1
- package/dist/types/trace.d.ts +9 -22
- package/dist/types/trace.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/CONTEXT.md +5 -7
- package/src/__tests__/checker-extra.test.ts +80 -139
- package/src/__tests__/checker.test.ts +0 -376
- package/src/__tests__/project-config-loader-extra.test.ts +42 -29
- package/src/__tests__/public-exports.test.ts +138 -0
- package/src/__tests__/trace-analyzer-extra.test.ts +6 -86
- package/src/__tests__/trace-analyzer.test.ts +4 -5
- package/src/__tests__/trace-collector.test.ts +0 -11
- package/src/__tests__/traces.test.ts +3 -22
- package/src/cli/commands/CONTEXT.md +2 -2
- package/src/cli/commands/__tests__/check-skip-output.test.ts +10 -7
- package/src/cli/commands/__tests__/check.test.ts +29 -69
- package/src/cli/commands/__tests__/constraints-report.test.ts +1 -1
- package/src/cli/commands/__tests__/knowledge.test.ts +90 -1
- package/src/cli/commands/__tests__/registry.test.ts +8 -6
- package/src/cli/commands/__tests__/status-extra.test.ts +6 -28
- package/src/cli/commands/__tests__/status.test.ts +6 -21
- package/src/cli/commands/check.ts +8 -34
- package/src/cli/commands/definitions.ts +2 -0
- package/src/cli/commands/init.ts +6 -37
- package/src/cli/commands/knowledge.ts +1 -16
- package/src/cli/commands/report.ts +0 -2
- package/src/cli/commands/status.ts +2 -12
- package/src/context/index.ts +29 -6
- package/src/core/CONTEXT.md +4 -3
- package/src/core/__tests__/effective-set.test.ts +80 -0
- package/src/core/constraints/capabilities-parser.ts +43 -49
- package/src/core/constraints/checker.ts +56 -147
- package/src/core/constraints/checkers/index.ts +2 -1
- package/src/core/constraints/checkers/types.ts +42 -0
- package/src/core/constraints/definitions/guidelines.ts +0 -2
- package/src/core/constraints/definitions/prompts.ts +0 -5
- package/src/core/constraints/index.ts +2 -17
- package/src/core/constraints/usage-report.ts +5 -8
- package/src/core/effective-constraints.ts +35 -7
- package/src/core/effective-set.ts +56 -0
- package/src/core/index.ts +80 -6
- package/src/core/project-config-loader.ts +53 -68
- package/src/failure/CONTEXT.md +1 -1
- package/src/failure/constraint-handler.ts +1 -1
- package/src/gates/CONTEXT.md +3 -3
- package/src/gates/checker-gate.ts +4 -12
- package/src/gates/definitions.ts +27 -50
- package/src/gates/effective-gates.ts +14 -21
- package/src/gates/index.ts +1 -1
- package/src/hooks/bootstrap.ts +0 -3
- package/src/index.ts +384 -137
- package/src/knowledge/CONTEXT.md +2 -2
- package/src/knowledge/__tests__/query.test.ts +64 -0
- package/src/knowledge/query.ts +28 -0
- package/src/monitoring/CONTEXT.md +7 -13
- package/src/monitoring/__tests__/traces.test.ts +0 -10
- package/src/monitoring/analyzer-base.ts +0 -22
- package/src/monitoring/index.ts +6 -12
- package/src/monitoring/trace-analyzer.ts +2 -73
- package/src/monitoring/traces.ts +2 -22
- package/src/presets/__tests__/standard.test.ts +48 -69
- package/src/presets/index.ts +3 -5
- package/src/presets/standard.ts +14 -79
- package/src/spec/CONTEXT.md +5 -13
- package/src/types/constraint.ts +1 -51
- package/src/types/index.ts +0 -12
- package/src/types/project-config.ts +4 -10
- package/src/types/trace.ts +9 -34
- package/dist/core/constraints/interceptor.d.ts +0 -38
- package/dist/core/constraints/interceptor.d.ts.map +0 -1
- package/dist/core/constraints/interceptor.js +0 -166
- package/dist/core/constraints/interceptor.js.map +0 -1
- package/dist/dashboard/data.d.ts +0 -31
- package/dist/dashboard/data.d.ts.map +0 -1
- package/dist/dashboard/data.js +0 -81
- package/dist/dashboard/data.js.map +0 -1
- package/dist/dashboard/index.d.ts +0 -4
- package/dist/dashboard/index.d.ts.map +0 -1
- package/dist/dashboard/index.js +0 -20
- package/dist/dashboard/index.js.map +0 -1
- package/dist/dashboard/stats.d.ts +0 -20
- package/dist/dashboard/stats.d.ts.map +0 -1
- package/dist/dashboard/stats.js +0 -115
- package/dist/dashboard/stats.js.map +0 -1
- package/dist/dashboard/types.d.ts +0 -110
- package/dist/dashboard/types.d.ts.map +0 -1
- package/dist/dashboard/types.js +0 -8
- package/dist/dashboard/types.js.map +0 -1
- package/dist/monitoring/constraint-doctor.d.ts +0 -82
- package/dist/monitoring/constraint-doctor.d.ts.map +0 -1
- package/dist/monitoring/constraint-doctor.js +0 -191
- package/dist/monitoring/constraint-doctor.js.map +0 -1
- package/dist/monitoring/diagnosis-rules.d.ts +0 -18
- package/dist/monitoring/diagnosis-rules.d.ts.map +0 -1
- package/dist/monitoring/diagnosis-rules.js +0 -119
- package/dist/monitoring/diagnosis-rules.js.map +0 -1
- package/dist/monitoring/knowledge-doctor.d.ts +0 -78
- package/dist/monitoring/knowledge-doctor.d.ts.map +0 -1
- package/dist/monitoring/knowledge-doctor.js +0 -266
- package/dist/monitoring/knowledge-doctor.js.map +0 -1
- package/dist/monitoring/knowledge-evolver.d.ts +0 -72
- package/dist/monitoring/knowledge-evolver.d.ts.map +0 -1
- package/dist/monitoring/knowledge-evolver.js +0 -205
- package/dist/monitoring/knowledge-evolver.js.map +0 -1
- package/dist/monitoring/performance-analyzer.d.ts +0 -92
- package/dist/monitoring/performance-analyzer.d.ts.map +0 -1
- package/dist/monitoring/performance-analyzer.js +0 -343
- package/dist/monitoring/performance-analyzer.js.map +0 -1
- package/dist/monitoring/performance-collector.d.ts +0 -103
- package/dist/monitoring/performance-collector.d.ts.map +0 -1
- package/dist/monitoring/performance-collector.js +0 -298
- package/dist/monitoring/performance-collector.js.map +0 -1
- package/dist/safety/index.d.ts +0 -6
- package/dist/safety/index.d.ts.map +0 -1
- package/dist/safety/index.js +0 -22
- package/dist/safety/index.js.map +0 -1
- package/dist/safety/input-guardrail.d.ts +0 -36
- package/dist/safety/input-guardrail.d.ts.map +0 -1
- package/dist/safety/input-guardrail.js +0 -118
- package/dist/safety/input-guardrail.js.map +0 -1
- package/dist/safety/output-guardrail.d.ts +0 -39
- package/dist/safety/output-guardrail.d.ts.map +0 -1
- package/dist/safety/output-guardrail.js +0 -147
- package/dist/safety/output-guardrail.js.map +0 -1
- package/dist/safety/sandbox.d.ts +0 -45
- package/dist/safety/sandbox.d.ts.map +0 -1
- package/dist/safety/sandbox.js +0 -134
- package/dist/safety/sandbox.js.map +0 -1
- package/dist/safety/tool-guardrail.d.ts +0 -51
- package/dist/safety/tool-guardrail.d.ts.map +0 -1
- package/dist/safety/tool-guardrail.js +0 -147
- package/dist/safety/tool-guardrail.js.map +0 -1
- package/dist/safety/types.d.ts +0 -104
- package/dist/safety/types.d.ts.map +0 -1
- package/dist/safety/types.js +0 -6
- package/dist/safety/types.js.map +0 -1
- package/dist/spec/annotation-checker.d.ts +0 -47
- package/dist/spec/annotation-checker.d.ts.map +0 -1
- package/dist/spec/annotation-checker.js +0 -279
- package/dist/spec/annotation-checker.js.map +0 -1
- package/dist/types/enforcement.d.ts +0 -42
- package/dist/types/enforcement.d.ts.map +0 -1
- package/dist/types/enforcement.js +0 -6
- package/dist/types/enforcement.js.map +0 -1
- package/dist/types/monitoring-types.d.ts +0 -53
- package/dist/types/monitoring-types.d.ts.map +0 -1
- package/dist/types/monitoring-types.js +0 -10
- package/dist/types/monitoring-types.js.map +0 -1
- package/dist/types/performance.d.ts +0 -204
- package/dist/types/performance.d.ts.map +0 -1
- package/dist/types/performance.js +0 -12
- package/dist/types/performance.js.map +0 -1
- package/dist/verification/index.d.ts +0 -4
- package/dist/verification/index.d.ts.map +0 -1
- package/dist/verification/index.js +0 -20
- package/dist/verification/index.js.map +0 -1
- package/dist/verification/loop.d.ts +0 -30
- package/dist/verification/loop.d.ts.map +0 -1
- package/dist/verification/loop.js +0 -114
- package/dist/verification/loop.js.map +0 -1
- package/dist/verification/rules-based.d.ts +0 -40
- package/dist/verification/rules-based.d.ts.map +0 -1
- package/dist/verification/rules-based.js +0 -130
- package/dist/verification/rules-based.js.map +0 -1
- package/dist/verification/types.d.ts +0 -69
- package/dist/verification/types.d.ts.map +0 -1
- package/dist/verification/types.js +0 -6
- package/dist/verification/types.js.map +0 -1
- package/src/__tests__/annotation-checker.test.ts +0 -183
- package/src/__tests__/constraint-doctor.test.ts +0 -271
- package/src/__tests__/doctor-extra.test.ts +0 -155
- package/src/__tests__/extend-exceptions.test.ts +0 -149
- package/src/__tests__/interceptor.test.ts +0 -89
- package/src/__tests__/performance-analyzer.test.ts +0 -499
- package/src/__tests__/performance-collector.test.ts +0 -276
- package/src/__tests__/presets.test.ts +0 -65
- package/src/core/constraints/__tests__/interceptor.test.ts +0 -253
- package/src/core/constraints/interceptor.ts +0 -214
- package/src/dashboard/CONTEXT.md +0 -21
- package/src/dashboard/__tests__/data.test.ts +0 -111
- package/src/dashboard/__tests__/stats.test.ts +0 -159
- package/src/dashboard/data.ts +0 -103
- package/src/dashboard/index.ts +0 -3
- package/src/dashboard/stats.ts +0 -127
- package/src/dashboard/types.ts +0 -130
- package/src/monitoring/__tests__/knowledge-doctor.test.ts +0 -278
- package/src/monitoring/__tests__/knowledge-evolver.test.ts +0 -368
- package/src/monitoring/__tests__/performance-analyzer.test.ts +0 -137
- package/src/monitoring/__tests__/performance-collector.test.ts +0 -331
- package/src/monitoring/constraint-doctor.ts +0 -239
- package/src/monitoring/diagnosis-rules.ts +0 -132
- package/src/monitoring/knowledge-doctor.ts +0 -322
- package/src/monitoring/knowledge-evolver.ts +0 -289
- package/src/monitoring/performance-analyzer.ts +0 -400
- package/src/monitoring/performance-collector.ts +0 -326
- package/src/safety/CONTEXT.md +0 -23
- package/src/safety/__tests__/input-guardrail.test.ts +0 -105
- package/src/safety/__tests__/output-guardrail.test.ts +0 -108
- package/src/safety/__tests__/sandbox.test.ts +0 -158
- package/src/safety/__tests__/tool-guardrail.test.ts +0 -127
- package/src/safety/index.ts +0 -5
- package/src/safety/input-guardrail.ts +0 -133
- package/src/safety/output-guardrail.ts +0 -170
- package/src/safety/sandbox.ts +0 -148
- package/src/safety/tool-guardrail.ts +0 -176
- package/src/safety/types.ts +0 -124
- package/src/spec/__tests__/annotation-checker.test.ts +0 -294
- package/src/spec/annotation-checker.ts +0 -320
- package/src/types/enforcement.ts +0 -48
- package/src/types/monitoring-types.ts +0 -68
- package/src/types/performance.ts +0 -295
- package/src/verification/CONTEXT.md +0 -23
- package/src/verification/__tests__/loop.test.ts +0 -303
- package/src/verification/__tests__/rules-based.test.ts +0 -240
- package/src/verification/index.ts +0 -3
- package/src/verification/loop.ts +0 -137
- package/src/verification/rules-based.ts +0 -152
- package/src/verification/types.ts +0 -81
|
@@ -1,368 +0,0 @@
|
|
|
1
|
-
import { KnowledgeEvolver } from '../knowledge-evolver';
|
|
2
|
-
import type { KnowledgeDiagnosis } from '../knowledge-doctor';
|
|
3
|
-
import type { KnowledgeEntry } from '../../knowledge/types';
|
|
4
|
-
|
|
5
|
-
function makeEntry(overrides: Partial<KnowledgeEntry> = {}): KnowledgeEntry {
|
|
6
|
-
return {
|
|
7
|
-
id: 'entry-1',
|
|
8
|
-
type: 'guideline',
|
|
9
|
-
title: 'Test Entry',
|
|
10
|
-
content: 'content',
|
|
11
|
-
maturity: 'draft',
|
|
12
|
-
layer: 'team',
|
|
13
|
-
created: '2025-01-01T00:00:00Z',
|
|
14
|
-
lastReferenced: new Date().toISOString(),
|
|
15
|
-
contributors: ['user-1'],
|
|
16
|
-
projects: ['proj-1'],
|
|
17
|
-
tags: ['test'],
|
|
18
|
-
applicablePhases: ['implementation'],
|
|
19
|
-
sourceReferences: [],
|
|
20
|
-
referencedBy: ['ref-1'],
|
|
21
|
-
executionResults: [],
|
|
22
|
-
consumptionMode: 'reference',
|
|
23
|
-
origin: 'agent',
|
|
24
|
-
...overrides,
|
|
25
|
-
};
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
describe('KnowledgeEvolver', () => {
|
|
29
|
-
describe('升级提案', () => {
|
|
30
|
-
it('draft 有引用时提议升级为 verified', () => {
|
|
31
|
-
const evolver = new KnowledgeEvolver();
|
|
32
|
-
const entry = makeEntry({ maturity: 'draft', referencedBy: ['r1'] });
|
|
33
|
-
const proposals = evolver.generateProposals([entry]);
|
|
34
|
-
const promote = proposals.filter(p => p.action === 'promote');
|
|
35
|
-
expect(promote).toHaveLength(1);
|
|
36
|
-
expect(promote[0].targetMaturity).toBe('verified');
|
|
37
|
-
expect(promote[0].risk).toBe('low');
|
|
38
|
-
expect(promote[0].autoApprovable).toBe(true);
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
it('draft 无引用时不提议升级', () => {
|
|
42
|
-
const evolver = new KnowledgeEvolver();
|
|
43
|
-
const entry = makeEntry({ maturity: 'draft', referencedBy: [] });
|
|
44
|
-
const proposals = evolver.generateProposals([entry]);
|
|
45
|
-
expect(proposals.filter(p => p.action === 'promote')).toHaveLength(0);
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
it('verified 有足够项目验证时提议升级为 proven', () => {
|
|
49
|
-
const evolver = new KnowledgeEvolver({ promoteThreshold: 2 });
|
|
50
|
-
const entry = makeEntry({ maturity: 'verified', projects: ['p1', 'p2'] });
|
|
51
|
-
const proposals = evolver.generateProposals([entry]);
|
|
52
|
-
const promote = proposals.filter(p => p.action === 'promote');
|
|
53
|
-
expect(promote).toHaveLength(1);
|
|
54
|
-
expect(promote[0].targetMaturity).toBe('proven');
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
it('verified 项目数不足时不提议升级', () => {
|
|
58
|
-
const evolver = new KnowledgeEvolver({ promoteThreshold: 5 });
|
|
59
|
-
const entry = makeEntry({ maturity: 'verified', projects: ['p1'] });
|
|
60
|
-
const proposals = evolver.generateProposals([entry]);
|
|
61
|
-
expect(proposals.filter(p => p.action === 'promote')).toHaveLength(0);
|
|
62
|
-
});
|
|
63
|
-
|
|
64
|
-
it('proven 不会提议升级(已到顶)', () => {
|
|
65
|
-
const evolver = new KnowledgeEvolver();
|
|
66
|
-
const entry = makeEntry({ maturity: 'proven', referencedBy: ['r1', 'r2'], projects: ['p1', 'p2'] });
|
|
67
|
-
const proposals = evolver.generateProposals([entry]);
|
|
68
|
-
expect(proposals.filter(p => p.action === 'promote')).toHaveLength(0);
|
|
69
|
-
});
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
describe('降级提案', () => {
|
|
73
|
-
it('长期未引用的 verified 提议降级', () => {
|
|
74
|
-
const evolver = new KnowledgeEvolver({ demoteDays: 30 });
|
|
75
|
-
const entry = makeEntry({
|
|
76
|
-
maturity: 'verified',
|
|
77
|
-
lastReferenced: '2020-01-01T00:00:00Z',
|
|
78
|
-
});
|
|
79
|
-
const proposals = evolver.generateProposals([entry]);
|
|
80
|
-
const demote = proposals.filter(p => p.action === 'demote');
|
|
81
|
-
expect(demote).toHaveLength(1);
|
|
82
|
-
expect(demote[0].targetMaturity).toBe('draft');
|
|
83
|
-
});
|
|
84
|
-
|
|
85
|
-
it('长期未引用的 proven 提议降级为 verified', () => {
|
|
86
|
-
const evolver = new KnowledgeEvolver({ demoteDays: 30 });
|
|
87
|
-
const entry = makeEntry({
|
|
88
|
-
maturity: 'proven',
|
|
89
|
-
lastReferenced: '2020-01-01T00:00:00Z',
|
|
90
|
-
});
|
|
91
|
-
const proposals = evolver.generateProposals([entry]);
|
|
92
|
-
const demote = proposals.filter(p => p.action === 'demote');
|
|
93
|
-
expect(demote).toHaveLength(1);
|
|
94
|
-
expect(demote[0].targetMaturity).toBe('verified');
|
|
95
|
-
});
|
|
96
|
-
|
|
97
|
-
it('draft 不会提议降级(已到底)', () => {
|
|
98
|
-
const evolver = new KnowledgeEvolver({ demoteDays: 1 });
|
|
99
|
-
const entry = makeEntry({
|
|
100
|
-
maturity: 'draft',
|
|
101
|
-
lastReferenced: '2020-01-01T00:00:00Z',
|
|
102
|
-
});
|
|
103
|
-
const proposals = evolver.generateProposals([entry]);
|
|
104
|
-
expect(proposals.filter(p => p.action === 'demote')).toHaveLength(0);
|
|
105
|
-
});
|
|
106
|
-
|
|
107
|
-
it('近期有引用的不提议降级', () => {
|
|
108
|
-
const evolver = new KnowledgeEvolver({ demoteDays: 180 });
|
|
109
|
-
const entry = makeEntry({ maturity: 'verified' });
|
|
110
|
-
const proposals = evolver.generateProposals([entry]);
|
|
111
|
-
expect(proposals.filter(p => p.action === 'demote')).toHaveLength(0);
|
|
112
|
-
});
|
|
113
|
-
});
|
|
114
|
-
|
|
115
|
-
describe('archived 条目', () => {
|
|
116
|
-
it('跳过 archived 条目', () => {
|
|
117
|
-
const evolver = new KnowledgeEvolver();
|
|
118
|
-
const entry = makeEntry({ maturity: 'archived' });
|
|
119
|
-
const proposals = evolver.generateProposals([entry]);
|
|
120
|
-
expect(proposals).toHaveLength(0);
|
|
121
|
-
});
|
|
122
|
-
});
|
|
123
|
-
|
|
124
|
-
describe('矛盾诊断 → freeze 提案', () => {
|
|
125
|
-
it('从矛盾诊断生成 freeze 提案', () => {
|
|
126
|
-
const evolver = new KnowledgeEvolver();
|
|
127
|
-
const entry = makeEntry({ id: 'e1', maturity: 'verified' });
|
|
128
|
-
const diagnosis: KnowledgeDiagnosis = {
|
|
129
|
-
id: 'd1',
|
|
130
|
-
type: 'contradiction',
|
|
131
|
-
severity: 'high',
|
|
132
|
-
entryId: 'e1',
|
|
133
|
-
title: 'Contradiction',
|
|
134
|
-
description: 'Conflicting entries',
|
|
135
|
-
rootCause: 'Same tag different maturity',
|
|
136
|
-
impact: 'Confusion',
|
|
137
|
-
recommendations: ['Freeze'],
|
|
138
|
-
timestamp: new Date().toISOString(),
|
|
139
|
-
};
|
|
140
|
-
const proposals = evolver.generateProposals([entry], [diagnosis]);
|
|
141
|
-
const freeze = proposals.filter(p => p.action === 'freeze');
|
|
142
|
-
expect(freeze).toHaveLength(1);
|
|
143
|
-
expect(freeze[0].risk).toBe('medium');
|
|
144
|
-
expect(freeze[0].autoApprovable).toBe(false);
|
|
145
|
-
});
|
|
146
|
-
|
|
147
|
-
it('无 entryId 的矛盾诊断不生成提案', () => {
|
|
148
|
-
const evolver = new KnowledgeEvolver();
|
|
149
|
-
const diagnosis: KnowledgeDiagnosis = {
|
|
150
|
-
id: 'd1',
|
|
151
|
-
type: 'contradiction',
|
|
152
|
-
severity: 'high',
|
|
153
|
-
title: 'Contradiction',
|
|
154
|
-
description: 'Conflicting entries',
|
|
155
|
-
rootCause: 'Unknown',
|
|
156
|
-
impact: 'Unknown',
|
|
157
|
-
recommendations: [],
|
|
158
|
-
timestamp: new Date().toISOString(),
|
|
159
|
-
};
|
|
160
|
-
const proposals = evolver.generateProposals([], [diagnosis]);
|
|
161
|
-
expect(proposals).toHaveLength(0);
|
|
162
|
-
});
|
|
163
|
-
});
|
|
164
|
-
|
|
165
|
-
describe('审核', () => {
|
|
166
|
-
it('低风险自动通过提案自动批准', () => {
|
|
167
|
-
const evolver = new KnowledgeEvolver();
|
|
168
|
-
const entry = makeEntry({ maturity: 'draft', referencedBy: ['r1'] });
|
|
169
|
-
const proposals = evolver.generateProposals([entry]);
|
|
170
|
-
const result = evolver.review(proposals[0]);
|
|
171
|
-
expect(result.approved).toBe(true);
|
|
172
|
-
});
|
|
173
|
-
|
|
174
|
-
it('proven 直接归档被拒绝', () => {
|
|
175
|
-
const evolver = new KnowledgeEvolver();
|
|
176
|
-
const proposal = {
|
|
177
|
-
id: 'p1',
|
|
178
|
-
entryId: 'e1',
|
|
179
|
-
action: 'archive' as const,
|
|
180
|
-
currentMaturity: 'proven' as const,
|
|
181
|
-
targetMaturity: 'archived' as const,
|
|
182
|
-
reason: 'test',
|
|
183
|
-
evidence: [],
|
|
184
|
-
risk: 'low' as const,
|
|
185
|
-
autoApprovable: true,
|
|
186
|
-
status: 'pending' as const,
|
|
187
|
-
createdAt: new Date().toISOString(),
|
|
188
|
-
};
|
|
189
|
-
const result = evolver.review(proposal);
|
|
190
|
-
expect(result.approved).toBe(false);
|
|
191
|
-
expect(result.reason).toContain('proven');
|
|
192
|
-
});
|
|
193
|
-
|
|
194
|
-
it('高风险升级被拒绝', () => {
|
|
195
|
-
const evolver = new KnowledgeEvolver();
|
|
196
|
-
const proposal = {
|
|
197
|
-
id: 'p1',
|
|
198
|
-
entryId: 'e1',
|
|
199
|
-
action: 'promote' as const,
|
|
200
|
-
currentMaturity: 'draft' as const,
|
|
201
|
-
targetMaturity: 'verified' as const,
|
|
202
|
-
reason: 'test',
|
|
203
|
-
evidence: [],
|
|
204
|
-
risk: 'high' as const,
|
|
205
|
-
autoApprovable: false,
|
|
206
|
-
status: 'pending' as const,
|
|
207
|
-
createdAt: new Date().toISOString(),
|
|
208
|
-
};
|
|
209
|
-
const result = evolver.review(proposal);
|
|
210
|
-
expect(result.approved).toBe(false);
|
|
211
|
-
expect(result.reason).toContain('高风险');
|
|
212
|
-
});
|
|
213
|
-
|
|
214
|
-
it('中等风险提案通过审核', () => {
|
|
215
|
-
const evolver = new KnowledgeEvolver();
|
|
216
|
-
const proposal = {
|
|
217
|
-
id: 'p1',
|
|
218
|
-
entryId: 'e1',
|
|
219
|
-
action: 'freeze' as const,
|
|
220
|
-
currentMaturity: 'verified' as const,
|
|
221
|
-
targetMaturity: 'verified' as const,
|
|
222
|
-
reason: 'test',
|
|
223
|
-
evidence: [],
|
|
224
|
-
risk: 'medium' as const,
|
|
225
|
-
autoApprovable: false,
|
|
226
|
-
status: 'pending' as const,
|
|
227
|
-
createdAt: new Date().toISOString(),
|
|
228
|
-
};
|
|
229
|
-
const result = evolver.review(proposal);
|
|
230
|
-
expect(result.approved).toBe(true);
|
|
231
|
-
expect(result.reason).toBe('提案通过审核');
|
|
232
|
-
});
|
|
233
|
-
});
|
|
234
|
-
|
|
235
|
-
describe('执行提案', () => {
|
|
236
|
-
it('无 store 时返回 false', () => {
|
|
237
|
-
const evolver = new KnowledgeEvolver();
|
|
238
|
-
const proposal = {
|
|
239
|
-
id: 'p1',
|
|
240
|
-
entryId: 'e1',
|
|
241
|
-
action: 'promote' as const,
|
|
242
|
-
currentMaturity: 'draft' as const,
|
|
243
|
-
targetMaturity: 'verified' as const,
|
|
244
|
-
reason: 'test',
|
|
245
|
-
evidence: [],
|
|
246
|
-
risk: 'low' as const,
|
|
247
|
-
autoApprovable: true,
|
|
248
|
-
status: 'approved' as const,
|
|
249
|
-
createdAt: new Date().toISOString(),
|
|
250
|
-
};
|
|
251
|
-
expect(evolver.implement(proposal)).toBe(false);
|
|
252
|
-
});
|
|
253
|
-
|
|
254
|
-
it('非 approved 状态返回 false', () => {
|
|
255
|
-
const evolver = new KnowledgeEvolver();
|
|
256
|
-
const proposal = {
|
|
257
|
-
id: 'p1',
|
|
258
|
-
entryId: 'e1',
|
|
259
|
-
action: 'promote' as const,
|
|
260
|
-
currentMaturity: 'draft' as const,
|
|
261
|
-
targetMaturity: 'verified' as const,
|
|
262
|
-
reason: 'test',
|
|
263
|
-
evidence: [],
|
|
264
|
-
risk: 'low' as const,
|
|
265
|
-
autoApprovable: true,
|
|
266
|
-
status: 'pending' as const,
|
|
267
|
-
createdAt: new Date().toISOString(),
|
|
268
|
-
};
|
|
269
|
-
expect(evolver.implement(proposal)).toBe(false);
|
|
270
|
-
});
|
|
271
|
-
|
|
272
|
-
it('store 中不存在条目时返回 false', () => {
|
|
273
|
-
const mockStore = { get: () => undefined, update: jest.fn() };
|
|
274
|
-
const evolver = new KnowledgeEvolver({}, mockStore as any);
|
|
275
|
-
const proposal = {
|
|
276
|
-
id: 'p1', entryId: 'e1', action: 'promote' as const,
|
|
277
|
-
currentMaturity: 'draft' as const, targetMaturity: 'verified' as const,
|
|
278
|
-
reason: 'test', evidence: [], risk: 'low' as const,
|
|
279
|
-
autoApprovable: true, status: 'approved' as const,
|
|
280
|
-
createdAt: new Date().toISOString(),
|
|
281
|
-
};
|
|
282
|
-
expect(evolver.implement(proposal)).toBe(false);
|
|
283
|
-
});
|
|
284
|
-
|
|
285
|
-
it('archive 操作执行成功', () => {
|
|
286
|
-
const mockStore = { get: () => makeEntry(), update: jest.fn() };
|
|
287
|
-
const evolver = new KnowledgeEvolver({}, mockStore as any);
|
|
288
|
-
const proposal = {
|
|
289
|
-
id: 'p1', entryId: 'entry-1', action: 'archive' as const,
|
|
290
|
-
currentMaturity: 'draft' as const, targetMaturity: 'archived' as const,
|
|
291
|
-
reason: 'test', evidence: [], risk: 'low' as const,
|
|
292
|
-
autoApprovable: true, status: 'approved' as const,
|
|
293
|
-
createdAt: new Date().toISOString(),
|
|
294
|
-
};
|
|
295
|
-
expect(evolver.implement(proposal)).toBe(true);
|
|
296
|
-
expect(mockStore.update).toHaveBeenCalledWith('entry-1', { maturity: 'archived' });
|
|
297
|
-
expect(proposal.status).toBe('implemented');
|
|
298
|
-
});
|
|
299
|
-
|
|
300
|
-
it('freeze 操作不调用 update', () => {
|
|
301
|
-
const mockStore = { get: () => makeEntry(), update: jest.fn() };
|
|
302
|
-
const evolver = new KnowledgeEvolver({}, mockStore as any);
|
|
303
|
-
const proposal = {
|
|
304
|
-
id: 'p1', entryId: 'entry-1', action: 'freeze' as const,
|
|
305
|
-
currentMaturity: 'verified' as const, targetMaturity: 'verified' as const,
|
|
306
|
-
reason: 'test', evidence: [], risk: 'medium' as const,
|
|
307
|
-
autoApprovable: false, status: 'approved' as const,
|
|
308
|
-
createdAt: new Date().toISOString(),
|
|
309
|
-
};
|
|
310
|
-
expect(evolver.implement(proposal)).toBe(true);
|
|
311
|
-
expect(mockStore.update).not.toHaveBeenCalled();
|
|
312
|
-
expect(proposal.status).toBe('implemented');
|
|
313
|
-
});
|
|
314
|
-
|
|
315
|
-
it('未知 action 返回 false', () => {
|
|
316
|
-
const mockStore = { get: () => makeEntry(), update: jest.fn() };
|
|
317
|
-
const evolver = new KnowledgeEvolver({}, mockStore as any);
|
|
318
|
-
const proposal = {
|
|
319
|
-
id: 'p1', entryId: 'entry-1', action: 'merge' as const,
|
|
320
|
-
currentMaturity: 'draft' as const, targetMaturity: 'verified' as const,
|
|
321
|
-
reason: 'test', evidence: [], risk: 'low' as const,
|
|
322
|
-
autoApprovable: true, status: 'approved' as const,
|
|
323
|
-
createdAt: new Date().toISOString(),
|
|
324
|
-
};
|
|
325
|
-
expect(evolver.implement(proposal)).toBe(false);
|
|
326
|
-
});
|
|
327
|
-
});
|
|
328
|
-
|
|
329
|
-
describe('批量处理', () => {
|
|
330
|
-
it('processProposals 审核并生成报告', () => {
|
|
331
|
-
const evolver = new KnowledgeEvolver();
|
|
332
|
-
const entry = makeEntry({ maturity: 'draft', referencedBy: ['r1'] });
|
|
333
|
-
const proposals = evolver.generateProposals([entry]);
|
|
334
|
-
const report = evolver.processProposals(proposals);
|
|
335
|
-
expect(report.proposals.length).toBeGreaterThan(0);
|
|
336
|
-
expect(report.proposals[0].status).toBe('approved');
|
|
337
|
-
expect(report.summary).toBeDefined();
|
|
338
|
-
});
|
|
339
|
-
|
|
340
|
-
it('processProposals 拒绝高风险提案', () => {
|
|
341
|
-
const evolver = new KnowledgeEvolver();
|
|
342
|
-
const proposal = {
|
|
343
|
-
id: 'p1', entryId: 'e1', action: 'promote' as const,
|
|
344
|
-
currentMaturity: 'draft' as const, targetMaturity: 'verified' as const,
|
|
345
|
-
reason: 'test', evidence: [], risk: 'high' as const,
|
|
346
|
-
autoApprovable: false, status: 'pending' as const,
|
|
347
|
-
createdAt: new Date().toISOString(),
|
|
348
|
-
};
|
|
349
|
-
const report = evolver.processProposals([proposal]);
|
|
350
|
-
expect(report.proposals[0].status).toBe('rejected');
|
|
351
|
-
});
|
|
352
|
-
|
|
353
|
-
it('autoImplement 模式自动执行低风险提案', () => {
|
|
354
|
-
const mockStore = {
|
|
355
|
-
get: (id: string) => makeEntry({ id, maturity: 'draft' }),
|
|
356
|
-
update: jest.fn(),
|
|
357
|
-
};
|
|
358
|
-
const evolver = new KnowledgeEvolver({ autoImplement: true }, mockStore as any);
|
|
359
|
-
const entry = makeEntry({ maturity: 'draft', referencedBy: ['r1'] });
|
|
360
|
-
const proposals = evolver.generateProposals([entry]);
|
|
361
|
-
const report = evolver.processProposals(proposals);
|
|
362
|
-
const promote = report.proposals.find(p => p.action === 'promote');
|
|
363
|
-
if (promote?.autoApprovable) {
|
|
364
|
-
expect(promote.status).toBe('implemented');
|
|
365
|
-
}
|
|
366
|
-
});
|
|
367
|
-
});
|
|
368
|
-
});
|
|
@@ -1,137 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* PerformanceAnalyzer 测试
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import { PerformanceAnalyzer } from '../performance-analyzer';
|
|
6
|
-
import { PerformanceCollector } from '../performance-collector';
|
|
7
|
-
import type { PerformanceTrace } from '../../types/performance';
|
|
8
|
-
|
|
9
|
-
// Mock PerformanceCollector
|
|
10
|
-
jest.mock('../performance-collector');
|
|
11
|
-
|
|
12
|
-
// Mock fs
|
|
13
|
-
jest.mock('fs', () => ({
|
|
14
|
-
existsSync: jest.fn(),
|
|
15
|
-
mkdirSync: jest.fn(),
|
|
16
|
-
readFileSync: jest.fn(),
|
|
17
|
-
writeFileSync: jest.fn(),
|
|
18
|
-
}));
|
|
19
|
-
|
|
20
|
-
const MockPerformanceCollector = PerformanceCollector as jest.MockedClass<typeof PerformanceCollector>;
|
|
21
|
-
|
|
22
|
-
describe('PerformanceAnalyzer', () => {
|
|
23
|
-
let analyzer: PerformanceAnalyzer;
|
|
24
|
-
let mockCollector: PerformanceCollector;
|
|
25
|
-
|
|
26
|
-
const mockTraces: PerformanceTrace[] = [
|
|
27
|
-
{ operation: 'test', timestamp: Date.now(), duration: 100, result: 'ok' },
|
|
28
|
-
{ operation: 'test', timestamp: Date.now() + 1000, duration: 200, result: 'ok' },
|
|
29
|
-
{ operation: 'test', timestamp: Date.now() + 2000, duration: 35000, result: 'exceeded', threshold: 30000 },
|
|
30
|
-
{ operation: 'test2', timestamp: Date.now(), duration: 500, result: 'ok' },
|
|
31
|
-
];
|
|
32
|
-
|
|
33
|
-
beforeEach(() => {
|
|
34
|
-
jest.clearAllMocks();
|
|
35
|
-
mockCollector = new MockPerformanceCollector();
|
|
36
|
-
analyzer = new PerformanceAnalyzer(mockCollector);
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
describe('constructor', () => {
|
|
40
|
-
it('should create with default config', () => {
|
|
41
|
-
expect(analyzer).toBeDefined();
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
it('should accept custom config', () => {
|
|
45
|
-
const customAnalyzer = new PerformanceAnalyzer(mockCollector, {
|
|
46
|
-
periodMs: 7200 * 1000,
|
|
47
|
-
});
|
|
48
|
-
expect(customAnalyzer).toBeDefined();
|
|
49
|
-
});
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
describe('summarize()', () => {
|
|
53
|
-
it('should group by operation', () => {
|
|
54
|
-
const summaries = analyzer.summarize(mockTraces);
|
|
55
|
-
expect(summaries.length).toBeGreaterThan(0);
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
it('should calculate total calls', () => {
|
|
59
|
-
const summaries = analyzer.summarize(mockTraces);
|
|
60
|
-
const testSummary = summaries.find(s => s.operation === 'test');
|
|
61
|
-
expect(testSummary).toBeDefined();
|
|
62
|
-
expect(testSummary!.totalCalls).toBe(3);
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
it('should calculate ok rate', () => {
|
|
66
|
-
const summaries = analyzer.summarize(mockTraces);
|
|
67
|
-
const testSummary = summaries.find(s => s.operation === 'test');
|
|
68
|
-
expect(testSummary).toBeDefined();
|
|
69
|
-
});
|
|
70
|
-
|
|
71
|
-
it('should handle empty traces', () => {
|
|
72
|
-
const summaries = analyzer.summarize([]);
|
|
73
|
-
expect(summaries).toEqual([]);
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
it('should handle single trace', () => {
|
|
77
|
-
const summaries = analyzer.summarize([
|
|
78
|
-
{ operation: 'single', timestamp: Date.now(), duration: 100, result: 'ok' },
|
|
79
|
-
]);
|
|
80
|
-
expect(summaries.length).toBe(1);
|
|
81
|
-
});
|
|
82
|
-
});
|
|
83
|
-
|
|
84
|
-
describe('detectAnomalies()', () => {
|
|
85
|
-
it('should detect high exceeded rate', () => {
|
|
86
|
-
const highExceededTraces: PerformanceTrace[] = [
|
|
87
|
-
{ operation: 'test', timestamp: Date.now(), duration: 35000, result: 'exceeded', threshold: 30000 },
|
|
88
|
-
{ operation: 'test', timestamp: Date.now() + 1000, duration: 40000, result: 'exceeded', threshold: 30000 },
|
|
89
|
-
{ operation: 'test', timestamp: Date.now() + 2000, duration: 100, result: 'ok' },
|
|
90
|
-
];
|
|
91
|
-
|
|
92
|
-
const summaries = analyzer.summarize(highExceededTraces);
|
|
93
|
-
const anomalies = analyzer.detectAnomalies(summaries);
|
|
94
|
-
expect(anomalies.length).toBeGreaterThanOrEqual(0);
|
|
95
|
-
});
|
|
96
|
-
|
|
97
|
-
it('should return empty array for normal traces', () => {
|
|
98
|
-
const normalTraces: PerformanceTrace[] = [
|
|
99
|
-
{ operation: 'test', timestamp: Date.now(), duration: 100, result: 'ok' },
|
|
100
|
-
{ operation: 'test', timestamp: Date.now() + 1000, duration: 150, result: 'ok' },
|
|
101
|
-
];
|
|
102
|
-
|
|
103
|
-
const summaries = analyzer.summarize(normalTraces);
|
|
104
|
-
const anomalies = analyzer.detectAnomalies(summaries);
|
|
105
|
-
expect(Array.isArray(anomalies)).toBe(true);
|
|
106
|
-
});
|
|
107
|
-
});
|
|
108
|
-
|
|
109
|
-
describe('compareWithPrevious()', () => {
|
|
110
|
-
it('should compare two summaries', () => {
|
|
111
|
-
const current = analyzer.summarize(mockTraces);
|
|
112
|
-
const previous = [...current];
|
|
113
|
-
|
|
114
|
-
const compared = analyzer.compareWithPrevious(current, previous);
|
|
115
|
-
expect(Array.isArray(compared)).toBe(true);
|
|
116
|
-
});
|
|
117
|
-
|
|
118
|
-
it('should handle empty comparison', () => {
|
|
119
|
-
const compared = analyzer.compareWithPrevious([], []);
|
|
120
|
-
expect(compared).toEqual([]);
|
|
121
|
-
});
|
|
122
|
-
});
|
|
123
|
-
|
|
124
|
-
describe('runHourlySummary()', () => {
|
|
125
|
-
it('should run hourly summary', () => {
|
|
126
|
-
// Verify method exists - actual execution depends on collector state
|
|
127
|
-
expect(typeof analyzer.runHourlySummary).toBe('function');
|
|
128
|
-
});
|
|
129
|
-
});
|
|
130
|
-
|
|
131
|
-
describe('runDailyAnomalyCheck()', () => {
|
|
132
|
-
it('should have method', () => {
|
|
133
|
-
// Verify method exists
|
|
134
|
-
expect(typeof analyzer.runDailyAnomalyCheck).toBe('function');
|
|
135
|
-
});
|
|
136
|
-
});
|
|
137
|
-
});
|