autosnippet 3.3.0 → 3.3.3
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/dashboard/dist/assets/icons-BJ2mUBi8.js +1 -0
- package/dashboard/dist/assets/index-B659K9t5.js +128 -0
- package/dashboard/dist/assets/index-NCm40PMD.css +1 -0
- package/dashboard/dist/index.html +3 -3
- package/dist/bin/cli.d.ts +1 -0
- package/dist/bin/cli.js +284 -142
- package/dist/lib/agent/context/ExplorationTracker.d.ts +2 -0
- package/dist/lib/agent/context/ExplorationTracker.js +21 -3
- package/dist/lib/agent/core/ToolExecutionPipeline.d.ts +3 -1
- package/dist/lib/agent/core/ToolExecutionPipeline.js +8 -1
- package/dist/lib/agent/forge/DynamicComposer.d.ts +58 -0
- package/dist/lib/agent/forge/DynamicComposer.js +99 -0
- package/dist/lib/agent/forge/SandboxRunner.d.ts +60 -0
- package/dist/lib/agent/forge/SandboxRunner.js +251 -0
- package/dist/lib/agent/forge/TemporaryToolRegistry.d.ts +76 -0
- package/dist/lib/agent/forge/TemporaryToolRegistry.js +154 -0
- package/dist/lib/agent/forge/ToolForge.d.ts +92 -0
- package/dist/lib/agent/forge/ToolForge.js +239 -0
- package/dist/lib/agent/forge/ToolRequirementAnalyzer.d.ts +44 -0
- package/dist/lib/agent/forge/ToolRequirementAnalyzer.js +119 -0
- package/dist/lib/agent/tools/ToolRegistry.d.ts +2 -0
- package/dist/lib/agent/tools/ToolRegistry.js +4 -0
- package/dist/lib/agent/tools/composite.js +0 -1
- package/dist/lib/agent/tools/index.d.ts +2 -50
- package/dist/lib/agent/tools/index.js +2 -3
- package/dist/lib/agent/tools/lifecycle.d.ts +1 -58
- package/dist/lib/agent/tools/lifecycle.js +2 -75
- package/dist/lib/cli/KnowledgeSyncService.d.ts +26 -0
- package/dist/lib/cli/KnowledgeSyncService.js +33 -1
- package/dist/lib/cli/deploy/FileManifest.d.ts +0 -21
- package/dist/lib/cli/deploy/FileManifest.js +0 -11
- package/dist/lib/domain/knowledge/KnowledgeEntry.d.ts +10 -0
- package/dist/lib/domain/knowledge/KnowledgeEntry.js +2 -0
- package/dist/lib/domain/knowledge/Lifecycle.d.ts +19 -2
- package/dist/lib/domain/knowledge/Lifecycle.js +32 -6
- package/dist/lib/domain/knowledge/UnifiedValidator.d.ts +1 -5
- package/dist/lib/domain/knowledge/UnifiedValidator.js +7 -44
- package/dist/lib/domain/knowledge/values/Stats.d.ts +29 -0
- package/dist/lib/domain/knowledge/values/Stats.js +41 -0
- package/dist/lib/external/mcp/McpServer.d.ts +19 -38
- package/dist/lib/external/mcp/McpServer.js +145 -117
- package/dist/lib/external/mcp/autoApproveInjector.js +0 -2
- package/dist/lib/external/mcp/handlers/bootstrap/MissionBriefingBuilder.d.ts +26 -1
- package/dist/lib/external/mcp/handlers/bootstrap/MissionBriefingBuilder.js +41 -0
- package/dist/lib/external/mcp/handlers/bootstrap/pipeline/orchestrator.js +49 -0
- package/dist/lib/external/mcp/handlers/bootstrap/shared/bootstrap-phases.d.ts +3 -0
- package/dist/lib/external/mcp/handlers/bootstrap/shared/bootstrap-phases.js +27 -0
- package/dist/lib/external/mcp/handlers/bootstrap/skills.js +1 -1
- package/dist/lib/external/mcp/handlers/bootstrap-external.js +1 -0
- package/dist/lib/external/mcp/handlers/bootstrap-internal.js +2 -0
- package/dist/lib/external/mcp/handlers/browse.d.ts +1 -0
- package/dist/lib/external/mcp/handlers/browse.js +2 -1
- package/dist/lib/external/mcp/handlers/consolidated.d.ts +117 -6
- package/dist/lib/external/mcp/handlers/consolidated.js +251 -71
- package/dist/lib/external/mcp/handlers/guard.d.ts +150 -0
- package/dist/lib/external/mcp/handlers/guard.js +239 -5
- package/dist/lib/external/mcp/handlers/knowledge.d.ts +0 -29
- package/dist/lib/external/mcp/handlers/knowledge.js +1 -76
- package/dist/lib/external/mcp/handlers/panorama.d.ts +36 -0
- package/dist/lib/external/mcp/handlers/panorama.js +156 -0
- package/dist/lib/external/mcp/handlers/system.d.ts +2 -54
- package/dist/lib/external/mcp/handlers/system.js +3 -113
- package/dist/lib/external/mcp/handlers/task.d.ts +13 -24
- package/dist/lib/external/mcp/handlers/task.js +218 -557
- package/dist/lib/external/mcp/handlers/types.d.ts +91 -8
- package/dist/lib/external/mcp/handlers/types.js +18 -1
- package/dist/lib/external/mcp/handlers/wiki-external.d.ts +18 -1
- package/dist/lib/external/mcp/handlers/wiki-external.js +16 -1
- package/dist/lib/external/mcp/tools.d.ts +18 -24
- package/dist/lib/external/mcp/tools.js +132 -159
- package/dist/lib/http/HttpServer.js +52 -0
- package/dist/lib/http/middleware/validate.js +7 -3
- package/dist/lib/http/routes/audit.d.ts +8 -0
- package/dist/lib/http/routes/audit.js +51 -0
- package/dist/lib/http/routes/guardReport.d.ts +10 -0
- package/dist/lib/http/routes/guardReport.js +143 -0
- package/dist/lib/http/routes/knowledge.js +32 -1
- package/dist/lib/http/routes/panorama.d.ts +11 -0
- package/dist/lib/http/routes/panorama.js +322 -0
- package/dist/lib/http/routes/signals.d.ts +10 -0
- package/dist/lib/http/routes/signals.js +104 -0
- package/dist/lib/http/routes/task.d.ts +2 -3
- package/dist/lib/http/routes/task.js +17 -347
- package/dist/lib/http/routes/violations.js +1 -1
- package/dist/lib/infrastructure/audit/AuditLogger.d.ts +6 -1
- package/dist/lib/infrastructure/audit/AuditLogger.js +14 -1
- package/dist/lib/infrastructure/database/drizzle/schema.d.ts +202 -504
- package/dist/lib/infrastructure/database/drizzle/schema.js +38 -69
- package/dist/lib/infrastructure/database/migrations/004_evolution_proposals.d.ts +8 -0
- package/dist/lib/infrastructure/database/migrations/004_evolution_proposals.js +43 -0
- package/dist/lib/infrastructure/database/migrations/005_recipe_source_refs.d.ts +9 -0
- package/dist/lib/infrastructure/database/migrations/005_recipe_source_refs.js +24 -0
- package/dist/lib/infrastructure/logging/Logger.d.ts +2 -0
- package/dist/lib/infrastructure/logging/Logger.js +34 -7
- package/dist/lib/infrastructure/monitoring/ErrorTracker.js +3 -1
- package/dist/lib/infrastructure/monitoring/PerformanceMonitor.d.ts +2 -2
- package/dist/lib/infrastructure/monitoring/PerformanceMonitor.js +12 -10
- package/dist/lib/infrastructure/notification/LarkNotifier.d.ts +24 -0
- package/dist/lib/infrastructure/notification/LarkNotifier.js +97 -0
- package/dist/lib/infrastructure/report/ReportStore.d.ts +45 -0
- package/dist/lib/infrastructure/report/ReportStore.js +133 -0
- package/dist/lib/infrastructure/signal/SignalAggregator.d.ts +18 -0
- package/dist/lib/infrastructure/signal/SignalAggregator.js +84 -0
- package/dist/lib/infrastructure/signal/SignalBridge.d.ts +13 -0
- package/dist/lib/infrastructure/signal/SignalBridge.js +20 -0
- package/dist/lib/infrastructure/signal/SignalBus.d.ts +63 -0
- package/dist/lib/infrastructure/signal/SignalBus.js +106 -0
- package/dist/lib/infrastructure/signal/SignalTraceWriter.d.ts +36 -0
- package/dist/lib/infrastructure/signal/SignalTraceWriter.js +130 -0
- package/dist/lib/infrastructure/vector/HnswVectorAdapter.js +18 -2
- package/dist/lib/injection/ServiceContainer.js +8 -0
- package/dist/lib/injection/ServiceMap.d.ts +16 -10
- package/dist/lib/injection/modules/AgentModule.d.ts +1 -1
- package/dist/lib/injection/modules/AgentModule.js +7 -1
- package/dist/lib/injection/modules/AppModule.d.ts +1 -1
- package/dist/lib/injection/modules/AppModule.js +4 -13
- package/dist/lib/injection/modules/GuardModule.js +27 -2
- package/dist/lib/injection/modules/InfraModule.d.ts +0 -1
- package/dist/lib/injection/modules/InfraModule.js +9 -7
- package/dist/lib/injection/modules/KnowledgeModule.d.ts +5 -0
- package/dist/lib/injection/modules/KnowledgeModule.js +131 -0
- package/dist/lib/injection/modules/PanoramaModule.d.ts +18 -0
- package/dist/lib/injection/modules/PanoramaModule.js +76 -0
- package/dist/lib/injection/modules/SignalModule.d.ts +10 -0
- package/dist/lib/injection/modules/SignalModule.js +84 -0
- package/dist/lib/repository/knowledge/KnowledgeRepository.impl.d.ts +1 -0
- package/dist/lib/repository/knowledge/KnowledgeRepository.impl.js +6 -0
- package/dist/lib/service/bootstrap/BootstrapTaskManager.d.ts +3 -1
- package/dist/lib/service/bootstrap/BootstrapTaskManager.js +20 -1
- package/dist/lib/service/bootstrap/UiStartupTasks.d.ts +45 -0
- package/dist/lib/service/bootstrap/UiStartupTasks.js +101 -0
- package/dist/lib/service/delivery/AgentInstructionsGenerator.js +4 -5
- package/dist/lib/service/delivery/CursorDeliveryPipeline.d.ts +3 -1
- package/dist/lib/service/delivery/CursorDeliveryPipeline.js +13 -10
- package/dist/lib/service/delivery/RulesGenerator.js +3 -2
- package/dist/lib/service/evolution/ConsolidationAdvisor.d.ts +114 -0
- package/dist/lib/service/evolution/ConsolidationAdvisor.js +542 -0
- package/dist/lib/service/evolution/ContradictionDetector.d.ts +54 -0
- package/dist/lib/service/evolution/ContradictionDetector.js +253 -0
- package/dist/lib/service/evolution/DecayDetector.d.ts +71 -0
- package/dist/lib/service/evolution/DecayDetector.js +244 -0
- package/dist/lib/service/evolution/EnhancementSuggester.d.ts +38 -0
- package/dist/lib/service/evolution/EnhancementSuggester.js +220 -0
- package/dist/lib/service/evolution/KnowledgeMetabolism.d.ts +82 -0
- package/dist/lib/service/evolution/KnowledgeMetabolism.js +167 -0
- package/dist/lib/service/evolution/RedundancyAnalyzer.d.ts +53 -0
- package/dist/lib/service/evolution/RedundancyAnalyzer.js +210 -0
- package/dist/lib/service/evolution/StagingManager.d.ts +57 -0
- package/dist/lib/service/evolution/StagingManager.js +201 -0
- package/dist/lib/service/guard/ComplianceReporter.d.ts +42 -2
- package/dist/lib/service/guard/ComplianceReporter.js +43 -5
- package/dist/lib/service/guard/CoverageAnalyzer.d.ts +54 -0
- package/dist/lib/service/guard/CoverageAnalyzer.js +149 -0
- package/dist/lib/service/guard/GuardCheckEngine.d.ts +42 -0
- package/dist/lib/service/guard/GuardCheckEngine.js +465 -14
- package/dist/lib/service/guard/GuardFeedbackLoop.d.ts +3 -0
- package/dist/lib/service/guard/GuardFeedbackLoop.js +9 -0
- package/dist/lib/service/guard/ReverseGuard.d.ts +73 -0
- package/dist/lib/service/guard/ReverseGuard.js +256 -0
- package/dist/lib/service/guard/RuleLearner.d.ts +12 -0
- package/dist/lib/service/guard/RuleLearner.js +38 -0
- package/dist/lib/service/guard/UncertaintyCollector.d.ts +83 -0
- package/dist/lib/service/guard/UncertaintyCollector.js +149 -0
- package/dist/lib/service/guard/ViolationsStore.d.ts +1 -0
- package/dist/lib/service/guard/ViolationsStore.js +33 -3
- package/dist/lib/service/knowledge/ConfidenceRouter.d.ts +13 -0
- package/dist/lib/service/knowledge/ConfidenceRouter.js +14 -0
- package/dist/lib/service/knowledge/KnowledgeService.js +22 -4
- package/dist/lib/service/knowledge/SourceRefReconciler.d.ts +68 -0
- package/dist/lib/service/knowledge/SourceRefReconciler.js +309 -0
- package/dist/lib/service/panorama/CouplingAnalyzer.d.ts +27 -0
- package/dist/lib/service/panorama/CouplingAnalyzer.js +192 -0
- package/dist/lib/service/panorama/DimensionAnalyzer.d.ts +28 -0
- package/dist/lib/service/panorama/DimensionAnalyzer.js +320 -0
- package/dist/lib/service/panorama/LayerInferrer.d.ts +19 -0
- package/dist/lib/service/panorama/LayerInferrer.js +182 -0
- package/dist/lib/service/panorama/ModuleDiscoverer.d.ts +24 -0
- package/dist/lib/service/panorama/ModuleDiscoverer.js +185 -0
- package/dist/lib/service/panorama/PanoramaAggregator.d.ts +29 -0
- package/dist/lib/service/panorama/PanoramaAggregator.js +228 -0
- package/dist/lib/service/panorama/PanoramaScanner.d.ts +52 -0
- package/dist/lib/service/panorama/PanoramaScanner.js +188 -0
- package/dist/lib/service/panorama/PanoramaService.d.ts +125 -0
- package/dist/lib/service/panorama/PanoramaService.js +363 -0
- package/dist/lib/service/panorama/PanoramaTypes.d.ts +134 -0
- package/dist/lib/service/panorama/PanoramaTypes.js +6 -0
- package/dist/lib/service/panorama/RoleRefiner.d.ts +48 -0
- package/dist/lib/service/panorama/RoleRefiner.js +535 -0
- package/dist/lib/service/search/BM25Scorer.d.ts +2 -2
- package/dist/lib/service/search/CoarseRanker.d.ts +7 -6
- package/dist/lib/service/search/CoarseRanker.js +11 -10
- package/dist/lib/service/search/FieldWeightedScorer.d.ts +81 -0
- package/dist/lib/service/search/FieldWeightedScorer.js +318 -0
- package/dist/lib/service/search/MultiSignalRanker.d.ts +3 -2
- package/dist/lib/service/search/MultiSignalRanker.js +17 -1
- package/dist/lib/service/search/SearchEngine.d.ts +9 -7
- package/dist/lib/service/search/SearchEngine.js +67 -10
- package/dist/lib/service/search/SearchTypes.d.ts +25 -3
- package/dist/lib/service/search/SearchTypes.js +6 -1
- package/dist/lib/service/signal/HitRecorder.d.ts +68 -0
- package/dist/lib/service/signal/HitRecorder.js +173 -0
- package/dist/lib/service/skills/SignalCollector.d.ts +3 -1
- package/dist/lib/service/skills/SignalCollector.js +31 -1
- package/dist/lib/service/task/IntentExtractor.d.ts +66 -0
- package/dist/lib/service/task/IntentExtractor.js +256 -0
- package/dist/lib/service/task/PrimeSearchPipeline.d.ts +54 -0
- package/dist/lib/service/task/PrimeSearchPipeline.js +113 -0
- package/dist/lib/service/vector/VectorService.d.ts +3 -0
- package/dist/lib/service/vector/VectorService.js +38 -4
- package/dist/lib/shared/schemas/mcp-tools.d.ts +41 -96
- package/dist/lib/shared/schemas/mcp-tools.js +59 -119
- package/dist/scripts/analyze-signals.d.ts +20 -0
- package/dist/scripts/analyze-signals.js +155 -0
- package/dist/scripts/diagnose-mcp.js +1 -1
- package/package.json +1 -1
- package/skills/autosnippet-create/SKILL.md +98 -89
- package/skills/autosnippet-devdocs/SKILL.md +55 -57
- package/templates/claude-code/hooks/autosnippet-session.sh +10 -15
- package/templates/cursor-hooks/hooks/session-start.sh +1 -1
- package/templates/guard-ci.yml +2 -2
- package/templates/instructions/agent-static.md +2 -1
- package/templates/instructions/conventions.md +5 -6
- package/templates/recipes-setup/README.md +1 -2
- package/templates/recipes-setup/_template.md +39 -39
- package/dashboard/dist/assets/icons-BofcEZ3f.js +0 -1
- package/dashboard/dist/assets/index-D0whuycy.css +0 -1
- package/dashboard/dist/assets/index-SiN1GChm.js +0 -128
- package/dist/lib/domain/task/Task.d.ts +0 -140
- package/dist/lib/domain/task/Task.js +0 -254
- package/dist/lib/domain/task/TaskDependency.d.ts +0 -23
- package/dist/lib/domain/task/TaskDependency.js +0 -34
- package/dist/lib/domain/task/TaskIdGenerator.d.ts +0 -40
- package/dist/lib/domain/task/TaskIdGenerator.js +0 -75
- package/dist/lib/domain/task/index.d.ts +0 -4
- package/dist/lib/domain/task/index.js +0 -4
- package/dist/lib/infrastructure/database/migrations/002_add_tasks.d.ts +0 -11
- package/dist/lib/infrastructure/database/migrations/002_add_tasks.js +0 -86
- package/dist/lib/repository/task/TaskRepository.impl.d.ts +0 -171
- package/dist/lib/repository/task/TaskRepository.impl.js +0 -347
- package/dist/lib/service/task/TaskGraphService.d.ts +0 -222
- package/dist/lib/service/task/TaskGraphService.js +0 -597
- package/dist/lib/service/task/TaskKnowledgeBridge.d.ts +0 -95
- package/dist/lib/service/task/TaskKnowledgeBridge.js +0 -298
- package/dist/lib/service/task/TaskReadyEngine.d.ts +0 -84
- package/dist/lib/service/task/TaskReadyEngine.js +0 -115
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* RedundancyAnalyzer — 多维冗余检测
|
|
3
|
+
*
|
|
4
|
+
* 从 CandidateAggregator 的标题 Jaccard 扩展到四维内容级相似度:
|
|
5
|
+
* 维度 1: title Jaccard ≥ 0.7
|
|
6
|
+
* 维度 2: doClause + dontClause 文本相似度 ≥ 0.6
|
|
7
|
+
* 维度 3: coreCode 去空白后字符级相似度 ≥ 0.8
|
|
8
|
+
* 维度 4: guard regex 完全相同
|
|
9
|
+
*
|
|
10
|
+
* 综合: weighted_sum(0.2*d1 + 0.3*d2 + 0.3*d3 + 0.2*d4) ≥ 0.65
|
|
11
|
+
*/
|
|
12
|
+
import Logger from '../../infrastructure/logging/Logger.js';
|
|
13
|
+
import { ContradictionDetector } from './ContradictionDetector.js';
|
|
14
|
+
/* ────────────────────── Constants ────────────────────── */
|
|
15
|
+
const WEIGHTS = { title: 0.2, clause: 0.3, code: 0.3, guard: 0.2 };
|
|
16
|
+
const REDUNDANCY_THRESHOLD = 0.65;
|
|
17
|
+
/* ────────────────────── Class ────────────────────── */
|
|
18
|
+
export class RedundancyAnalyzer {
|
|
19
|
+
#db;
|
|
20
|
+
#signalBus;
|
|
21
|
+
#reportStore;
|
|
22
|
+
#logger = Logger.getInstance();
|
|
23
|
+
constructor(db, options = {}) {
|
|
24
|
+
this.#db = db;
|
|
25
|
+
this.#signalBus = options.signalBus ?? null;
|
|
26
|
+
this.#reportStore = options.reportStore ?? null;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* 分析所有 active/staging 条目之间的冗余
|
|
30
|
+
*/
|
|
31
|
+
analyzeAll() {
|
|
32
|
+
const recipes = this.#loadRecipes();
|
|
33
|
+
const results = [];
|
|
34
|
+
for (let i = 0; i < recipes.length; i++) {
|
|
35
|
+
for (let j = i + 1; j < recipes.length; j++) {
|
|
36
|
+
const result = this.analyzePair(recipes[i], recipes[j]);
|
|
37
|
+
if (result) {
|
|
38
|
+
results.push(result);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
if (this.#reportStore && results.length > 0) {
|
|
43
|
+
for (const r of results) {
|
|
44
|
+
void this.#reportStore.write({
|
|
45
|
+
category: 'analysis',
|
|
46
|
+
type: 'redundancy_report',
|
|
47
|
+
producer: 'RedundancyAnalyzer',
|
|
48
|
+
data: {
|
|
49
|
+
recipeA: r.recipeA,
|
|
50
|
+
redundantWith: r.recipeB,
|
|
51
|
+
dimensions: r.dimensions,
|
|
52
|
+
similarity: r.similarity,
|
|
53
|
+
},
|
|
54
|
+
timestamp: Date.now(),
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
if (this.#signalBus && results.length > 0) {
|
|
59
|
+
this.#signalBus.send('lifecycle', 'RedundancyAnalyzer', 1, {
|
|
60
|
+
metadata: { redundantPairCount: results.length },
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
this.#logger.debug(`RedundancyAnalyzer: found ${results.length} redundant pairs`);
|
|
64
|
+
return results;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* 分析两条 Recipe 的冗余度
|
|
68
|
+
*/
|
|
69
|
+
analyzePair(a, b) {
|
|
70
|
+
const d1 = RedundancyAnalyzer.#titleJaccard(a.title, b.title);
|
|
71
|
+
const d2 = this.#clauseSimilarity(a, b);
|
|
72
|
+
const d3 = RedundancyAnalyzer.#codeSimilarity(a.coreCode, b.coreCode);
|
|
73
|
+
const d4 = a.guardPattern && b.guardPattern && a.guardPattern === b.guardPattern ? 1.0 : 0;
|
|
74
|
+
const similarity = WEIGHTS.title * d1 + WEIGHTS.clause * d2 + WEIGHTS.code * d3 + WEIGHTS.guard * d4;
|
|
75
|
+
if (similarity < REDUNDANCY_THRESHOLD) {
|
|
76
|
+
return null;
|
|
77
|
+
}
|
|
78
|
+
return {
|
|
79
|
+
recipeA: a.id,
|
|
80
|
+
recipeB: b.id,
|
|
81
|
+
similarity: Math.round(similarity * 100) / 100,
|
|
82
|
+
dimensions: {
|
|
83
|
+
title: Math.round(d1 * 100) / 100,
|
|
84
|
+
clause: Math.round(d2 * 100) / 100,
|
|
85
|
+
code: Math.round(d3 * 100) / 100,
|
|
86
|
+
guard: d4,
|
|
87
|
+
},
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
/* ── Internal ── */
|
|
91
|
+
#loadRecipes() {
|
|
92
|
+
try {
|
|
93
|
+
const rows = this.#db
|
|
94
|
+
.prepare(`SELECT id, title,
|
|
95
|
+
doClause,
|
|
96
|
+
dontClause,
|
|
97
|
+
json_extract(content, '$.pattern') AS guardPattern,
|
|
98
|
+
json_extract(content, '$.coreCode') AS coreCode
|
|
99
|
+
FROM knowledge_entries
|
|
100
|
+
WHERE lifecycle IN ('active', 'staging', 'evolving')`)
|
|
101
|
+
.all();
|
|
102
|
+
return rows.map((r) => ({
|
|
103
|
+
id: r.id,
|
|
104
|
+
title: r.title,
|
|
105
|
+
doClause: r.doClause ?? null,
|
|
106
|
+
dontClause: r.dontClause ?? null,
|
|
107
|
+
coreCode: r.coreCode ?? null,
|
|
108
|
+
guardPattern: r.guardPattern ?? null,
|
|
109
|
+
}));
|
|
110
|
+
}
|
|
111
|
+
catch {
|
|
112
|
+
return [];
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
/** 维度 1: 标题 Jaccard 相似度 */
|
|
116
|
+
static #titleJaccard(titleA, titleB) {
|
|
117
|
+
const wordsA = ContradictionDetector.extractTopicWords(titleA);
|
|
118
|
+
const wordsB = ContradictionDetector.extractTopicWords(titleB);
|
|
119
|
+
if (wordsA.size === 0 && wordsB.size === 0) {
|
|
120
|
+
return 0;
|
|
121
|
+
}
|
|
122
|
+
let intersection = 0;
|
|
123
|
+
for (const w of wordsA) {
|
|
124
|
+
if (wordsB.has(w)) {
|
|
125
|
+
intersection++;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
const union = wordsA.size + wordsB.size - intersection;
|
|
129
|
+
return union === 0 ? 0 : intersection / union;
|
|
130
|
+
}
|
|
131
|
+
/** 维度 2: doClause + dontClause 文本相似度 */
|
|
132
|
+
#clauseSimilarity(a, b) {
|
|
133
|
+
const textA = [a.doClause, a.dontClause].filter(Boolean).join(' ');
|
|
134
|
+
const textB = [b.doClause, b.dontClause].filter(Boolean).join(' ');
|
|
135
|
+
if (!textA || !textB) {
|
|
136
|
+
return 0;
|
|
137
|
+
}
|
|
138
|
+
const wordsA = ContradictionDetector.extractTopicWords(textA);
|
|
139
|
+
const wordsB = ContradictionDetector.extractTopicWords(textB);
|
|
140
|
+
if (wordsA.size === 0 && wordsB.size === 0) {
|
|
141
|
+
return 0;
|
|
142
|
+
}
|
|
143
|
+
let intersection = 0;
|
|
144
|
+
for (const w of wordsA) {
|
|
145
|
+
if (wordsB.has(w)) {
|
|
146
|
+
intersection++;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
const union = wordsA.size + wordsB.size - intersection;
|
|
150
|
+
return union === 0 ? 0 : intersection / union;
|
|
151
|
+
}
|
|
152
|
+
/** 维度 3: coreCode 去空白后字符级相似度 (简化 Levenshtein → 公共子串比率) */
|
|
153
|
+
static #codeSimilarity(codeA, codeB) {
|
|
154
|
+
if (!codeA || !codeB) {
|
|
155
|
+
return 0;
|
|
156
|
+
}
|
|
157
|
+
const a = codeA.replace(/\s+/g, '');
|
|
158
|
+
const b = codeB.replace(/\s+/g, '');
|
|
159
|
+
if (a.length === 0 && b.length === 0) {
|
|
160
|
+
return 0;
|
|
161
|
+
}
|
|
162
|
+
// 使用最长公共子串(LCS)比率作为相似度的近似
|
|
163
|
+
// 对于较长的代码,使用 n-gram 方法避免 O(n²) 开销
|
|
164
|
+
const maxLen = Math.max(a.length, b.length);
|
|
165
|
+
if (maxLen > 2000) {
|
|
166
|
+
return RedundancyAnalyzer.#ngramSimilarity(a, b, 4);
|
|
167
|
+
}
|
|
168
|
+
const lcsLen = RedundancyAnalyzer.#lcsLength(a, b);
|
|
169
|
+
return (2 * lcsLen) / (a.length + b.length);
|
|
170
|
+
}
|
|
171
|
+
/** 最长公共子序列长度(O(n*m) 但只用 2 行空间) */
|
|
172
|
+
static #lcsLength(a, b) {
|
|
173
|
+
const m = a.length;
|
|
174
|
+
const n = b.length;
|
|
175
|
+
let prev = new Uint16Array(n + 1);
|
|
176
|
+
let curr = new Uint16Array(n + 1);
|
|
177
|
+
for (let i = 1; i <= m; i++) {
|
|
178
|
+
for (let j = 1; j <= n; j++) {
|
|
179
|
+
if (a[i - 1] === b[j - 1]) {
|
|
180
|
+
curr[j] = prev[j - 1] + 1;
|
|
181
|
+
}
|
|
182
|
+
else {
|
|
183
|
+
curr[j] = Math.max(prev[j], curr[j - 1]);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
[prev, curr] = [curr, prev];
|
|
187
|
+
curr.fill(0);
|
|
188
|
+
}
|
|
189
|
+
return prev[n];
|
|
190
|
+
}
|
|
191
|
+
/** n-gram 相似度(大文本用) */
|
|
192
|
+
static #ngramSimilarity(a, b, n) {
|
|
193
|
+
const ngramsA = new Set();
|
|
194
|
+
for (let i = 0; i <= a.length - n; i++) {
|
|
195
|
+
ngramsA.add(a.slice(i, i + n));
|
|
196
|
+
}
|
|
197
|
+
const ngramsB = new Set();
|
|
198
|
+
for (let i = 0; i <= b.length - n; i++) {
|
|
199
|
+
ngramsB.add(b.slice(i, i + n));
|
|
200
|
+
}
|
|
201
|
+
let intersection = 0;
|
|
202
|
+
for (const ng of ngramsA) {
|
|
203
|
+
if (ngramsB.has(ng)) {
|
|
204
|
+
intersection++;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
const union = ngramsA.size + ngramsB.size - intersection;
|
|
208
|
+
return union === 0 ? 0 : intersection / union;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* StagingManager — staging Grace Period 管理 + 自动发布
|
|
3
|
+
*
|
|
4
|
+
* 核心职责:
|
|
5
|
+
* 1. 条目进入 staging 后记录 deadline
|
|
6
|
+
* 2. 定时检查:deadline 到期 + 无异议 → 自动转 active
|
|
7
|
+
* 3. 异常回滚:Guard 检测到冲突 → 回滚到 pending
|
|
8
|
+
* 4. 发射信号通知 Dashboard
|
|
9
|
+
*
|
|
10
|
+
* 分级 Grace Period(由 ConfidenceRouter 决定):
|
|
11
|
+
* ≥ 0.90 → 24h
|
|
12
|
+
* 0.85-0.89 → 72h
|
|
13
|
+
*/
|
|
14
|
+
import type { SignalBus } from '../../infrastructure/signal/SignalBus.js';
|
|
15
|
+
interface DatabaseLike {
|
|
16
|
+
prepare(sql: string): {
|
|
17
|
+
all(...params: unknown[]): Record<string, unknown>[];
|
|
18
|
+
get(...params: unknown[]): Record<string, unknown> | undefined;
|
|
19
|
+
run(...params: unknown[]): {
|
|
20
|
+
changes: number;
|
|
21
|
+
};
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
export interface StagingEntry {
|
|
25
|
+
id: string;
|
|
26
|
+
title: string;
|
|
27
|
+
stagingDeadline: number;
|
|
28
|
+
confidence: number;
|
|
29
|
+
}
|
|
30
|
+
export interface StagingCheckResult {
|
|
31
|
+
promoted: StagingEntry[];
|
|
32
|
+
rolledBack: StagingEntry[];
|
|
33
|
+
waiting: StagingEntry[];
|
|
34
|
+
}
|
|
35
|
+
export declare class StagingManager {
|
|
36
|
+
#private;
|
|
37
|
+
constructor(db: DatabaseLike, options?: {
|
|
38
|
+
signalBus?: SignalBus;
|
|
39
|
+
});
|
|
40
|
+
/**
|
|
41
|
+
* 将条目推入 staging 状态并记录 deadline
|
|
42
|
+
*/
|
|
43
|
+
enterStaging(entryId: string, gracePeriodMs: number, confidence: number): boolean;
|
|
44
|
+
/**
|
|
45
|
+
* 检查所有 staging 条目,执行自动发布或回滚
|
|
46
|
+
*/
|
|
47
|
+
checkAndPromote(): StagingCheckResult;
|
|
48
|
+
/**
|
|
49
|
+
* 回滚 staging 条目到 pending(Guard 检测到冲突时调用)
|
|
50
|
+
*/
|
|
51
|
+
rollback(entryId: string, reason: string): boolean;
|
|
52
|
+
/**
|
|
53
|
+
* 获取所有 staging 条目及其状态
|
|
54
|
+
*/
|
|
55
|
+
listStaging(): StagingEntry[];
|
|
56
|
+
}
|
|
57
|
+
export {};
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* StagingManager — staging Grace Period 管理 + 自动发布
|
|
3
|
+
*
|
|
4
|
+
* 核心职责:
|
|
5
|
+
* 1. 条目进入 staging 后记录 deadline
|
|
6
|
+
* 2. 定时检查:deadline 到期 + 无异议 → 自动转 active
|
|
7
|
+
* 3. 异常回滚:Guard 检测到冲突 → 回滚到 pending
|
|
8
|
+
* 4. 发射信号通知 Dashboard
|
|
9
|
+
*
|
|
10
|
+
* 分级 Grace Period(由 ConfidenceRouter 决定):
|
|
11
|
+
* ≥ 0.90 → 24h
|
|
12
|
+
* 0.85-0.89 → 72h
|
|
13
|
+
*/
|
|
14
|
+
import Logger from '../../infrastructure/logging/Logger.js';
|
|
15
|
+
/* ────────────────────── Class ────────────────────── */
|
|
16
|
+
export class StagingManager {
|
|
17
|
+
#db;
|
|
18
|
+
#signalBus;
|
|
19
|
+
#logger = Logger.getInstance();
|
|
20
|
+
constructor(db, options = {}) {
|
|
21
|
+
this.#db = db;
|
|
22
|
+
this.#signalBus = options.signalBus ?? null;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* 将条目推入 staging 状态并记录 deadline
|
|
26
|
+
*/
|
|
27
|
+
enterStaging(entryId, gracePeriodMs, confidence) {
|
|
28
|
+
const now = Date.now();
|
|
29
|
+
const deadline = now + gracePeriodMs;
|
|
30
|
+
const entry = this.#db
|
|
31
|
+
.prepare(`SELECT id, title, lifecycle FROM knowledge_entries WHERE id = ?`)
|
|
32
|
+
.get(entryId);
|
|
33
|
+
if (!entry) {
|
|
34
|
+
this.#logger.warn(`StagingManager: entry not found: ${entryId}`);
|
|
35
|
+
return false;
|
|
36
|
+
}
|
|
37
|
+
if (entry.lifecycle !== 'pending') {
|
|
38
|
+
this.#logger.warn(`StagingManager: entry ${entryId} is "${entry.lifecycle}", not pending`);
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
// 更新 lifecycle → staging,记录 deadline 到 stats JSON
|
|
42
|
+
const statsRaw = this.#db
|
|
43
|
+
.prepare(`SELECT stats FROM knowledge_entries WHERE id = ?`)
|
|
44
|
+
.get(entryId);
|
|
45
|
+
let stats = {};
|
|
46
|
+
try {
|
|
47
|
+
stats = JSON.parse(statsRaw?.stats || '{}');
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
stats = {};
|
|
51
|
+
}
|
|
52
|
+
stats.stagingDeadline = deadline;
|
|
53
|
+
stats.stagingConfidence = confidence;
|
|
54
|
+
stats.stagingEnteredAt = now;
|
|
55
|
+
this.#db
|
|
56
|
+
.prepare(`UPDATE knowledge_entries SET lifecycle = 'staging', stats = ?, updatedAt = ? WHERE id = ?`)
|
|
57
|
+
.run(JSON.stringify(stats), now, entryId);
|
|
58
|
+
// 发射信号
|
|
59
|
+
if (this.#signalBus) {
|
|
60
|
+
this.#signalBus.send('lifecycle', 'StagingManager.enter', confidence, {
|
|
61
|
+
target: entryId,
|
|
62
|
+
metadata: {
|
|
63
|
+
action: 'enter_staging',
|
|
64
|
+
deadline,
|
|
65
|
+
gracePeriodMs,
|
|
66
|
+
title: entry.title,
|
|
67
|
+
},
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
this.#logger.info(`StagingManager: ${entry.title} → staging (deadline: ${new Date(deadline).toISOString()})`);
|
|
71
|
+
return true;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* 检查所有 staging 条目,执行自动发布或回滚
|
|
75
|
+
*/
|
|
76
|
+
checkAndPromote() {
|
|
77
|
+
const now = Date.now();
|
|
78
|
+
const result = { promoted: [], rolledBack: [], waiting: [] };
|
|
79
|
+
const rows = this.#db
|
|
80
|
+
.prepare(`SELECT id, title, stats FROM knowledge_entries WHERE lifecycle = 'staging'`)
|
|
81
|
+
.all();
|
|
82
|
+
for (const row of rows) {
|
|
83
|
+
let stats = {};
|
|
84
|
+
try {
|
|
85
|
+
stats = JSON.parse(row.stats || '{}');
|
|
86
|
+
}
|
|
87
|
+
catch {
|
|
88
|
+
stats = {};
|
|
89
|
+
}
|
|
90
|
+
const deadline = stats.stagingDeadline || 0;
|
|
91
|
+
const confidence = stats.stagingConfidence || 0;
|
|
92
|
+
const entry = {
|
|
93
|
+
id: row.id,
|
|
94
|
+
title: row.title,
|
|
95
|
+
stagingDeadline: deadline,
|
|
96
|
+
confidence,
|
|
97
|
+
};
|
|
98
|
+
if (deadline === 0) {
|
|
99
|
+
// 无 deadline 数据(旧数据兼容)→ 保持 waiting
|
|
100
|
+
result.waiting.push(entry);
|
|
101
|
+
continue;
|
|
102
|
+
}
|
|
103
|
+
if (now < deadline) {
|
|
104
|
+
// 未到期
|
|
105
|
+
result.waiting.push(entry);
|
|
106
|
+
continue;
|
|
107
|
+
}
|
|
108
|
+
// 到期 → 自动发布
|
|
109
|
+
this.#promote(entry, stats, now);
|
|
110
|
+
result.promoted.push(entry);
|
|
111
|
+
}
|
|
112
|
+
if (result.promoted.length > 0) {
|
|
113
|
+
this.#logger.info(`StagingManager: promoted ${result.promoted.length} entries to active`);
|
|
114
|
+
}
|
|
115
|
+
return result;
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* 回滚 staging 条目到 pending(Guard 检测到冲突时调用)
|
|
119
|
+
*/
|
|
120
|
+
rollback(entryId, reason) {
|
|
121
|
+
const now = Date.now();
|
|
122
|
+
const entry = this.#db
|
|
123
|
+
.prepare(`SELECT id, title, lifecycle, stats FROM knowledge_entries WHERE id = ?`)
|
|
124
|
+
.get(entryId);
|
|
125
|
+
if (!entry || entry.lifecycle !== 'staging') {
|
|
126
|
+
return false;
|
|
127
|
+
}
|
|
128
|
+
let stats = {};
|
|
129
|
+
try {
|
|
130
|
+
stats = JSON.parse(entry.stats || '{}');
|
|
131
|
+
}
|
|
132
|
+
catch {
|
|
133
|
+
stats = {};
|
|
134
|
+
}
|
|
135
|
+
// 清除 staging 元数据
|
|
136
|
+
delete stats.stagingDeadline;
|
|
137
|
+
delete stats.stagingConfidence;
|
|
138
|
+
delete stats.stagingEnteredAt;
|
|
139
|
+
stats.lastRollbackReason = reason;
|
|
140
|
+
stats.lastRollbackAt = now;
|
|
141
|
+
this.#db
|
|
142
|
+
.prepare(`UPDATE knowledge_entries SET lifecycle = 'pending', stats = ?, updatedAt = ? WHERE id = ?`)
|
|
143
|
+
.run(JSON.stringify(stats), now, entryId);
|
|
144
|
+
if (this.#signalBus) {
|
|
145
|
+
this.#signalBus.send('lifecycle', 'StagingManager.rollback', 0.8, {
|
|
146
|
+
target: entryId,
|
|
147
|
+
metadata: {
|
|
148
|
+
action: 'staging_rollback',
|
|
149
|
+
reason,
|
|
150
|
+
title: entry.title,
|
|
151
|
+
},
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
this.#logger.info(`StagingManager: ${entry.title} rolled back to pending — ${reason}`);
|
|
155
|
+
return true;
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* 获取所有 staging 条目及其状态
|
|
159
|
+
*/
|
|
160
|
+
listStaging() {
|
|
161
|
+
const rows = this.#db
|
|
162
|
+
.prepare(`SELECT id, title, stats FROM knowledge_entries WHERE lifecycle = 'staging'`)
|
|
163
|
+
.all();
|
|
164
|
+
return rows.map((row) => {
|
|
165
|
+
let stats = {};
|
|
166
|
+
try {
|
|
167
|
+
stats = JSON.parse(row.stats || '{}');
|
|
168
|
+
}
|
|
169
|
+
catch {
|
|
170
|
+
stats = {};
|
|
171
|
+
}
|
|
172
|
+
return {
|
|
173
|
+
id: row.id,
|
|
174
|
+
title: row.title,
|
|
175
|
+
stagingDeadline: stats.stagingDeadline || 0,
|
|
176
|
+
confidence: stats.stagingConfidence || 0,
|
|
177
|
+
};
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
/* ── Private ── */
|
|
181
|
+
#promote(entry, stats, now) {
|
|
182
|
+
// 清除 staging 元数据,记录发布信息
|
|
183
|
+
delete stats.stagingDeadline;
|
|
184
|
+
delete stats.stagingConfidence;
|
|
185
|
+
delete stats.stagingEnteredAt;
|
|
186
|
+
stats.autoPublishedAt = now;
|
|
187
|
+
this.#db
|
|
188
|
+
.prepare(`UPDATE knowledge_entries SET lifecycle = 'active', publishedAt = ?, stats = ?, updatedAt = ? WHERE id = ?`)
|
|
189
|
+
.run(now, JSON.stringify(stats), now, entry.id);
|
|
190
|
+
if (this.#signalBus) {
|
|
191
|
+
this.#signalBus.send('lifecycle', 'StagingManager.promote', 1.0, {
|
|
192
|
+
target: entry.id,
|
|
193
|
+
metadata: {
|
|
194
|
+
action: 'auto_publish',
|
|
195
|
+
title: entry.title,
|
|
196
|
+
confidence: entry.confidence,
|
|
197
|
+
},
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
@@ -43,9 +43,34 @@ interface GuardCheckEngineLike {
|
|
|
43
43
|
files: {
|
|
44
44
|
filePath: string;
|
|
45
45
|
violations: ViolationItem[];
|
|
46
|
-
|
|
46
|
+
uncertainResults?: {
|
|
47
|
+
ruleId: string;
|
|
48
|
+
message: string;
|
|
49
|
+
layer: string;
|
|
50
|
+
reason: string;
|
|
51
|
+
detail: string;
|
|
52
|
+
}[];
|
|
53
|
+
summary: ViolationSummary & {
|
|
54
|
+
uncertain?: number;
|
|
55
|
+
};
|
|
47
56
|
}[];
|
|
48
57
|
crossFileViolations: ViolationItem[];
|
|
58
|
+
capabilityReport?: {
|
|
59
|
+
checkCoverage: number;
|
|
60
|
+
uncertainResults: {
|
|
61
|
+
ruleId: string;
|
|
62
|
+
message: string;
|
|
63
|
+
layer: string;
|
|
64
|
+
reason: string;
|
|
65
|
+
detail: string;
|
|
66
|
+
}[];
|
|
67
|
+
boundaries: {
|
|
68
|
+
type: string;
|
|
69
|
+
description: string;
|
|
70
|
+
affectedRules: string[];
|
|
71
|
+
suggestedAction: string;
|
|
72
|
+
}[];
|
|
73
|
+
};
|
|
49
74
|
};
|
|
50
75
|
}
|
|
51
76
|
interface ViolationItem {
|
|
@@ -84,6 +109,7 @@ interface ExclusionManagerLike {
|
|
|
84
109
|
isRuleExcluded?(ruleId: string, filePath: string): boolean;
|
|
85
110
|
}
|
|
86
111
|
export declare class ComplianceReporter {
|
|
112
|
+
#private;
|
|
87
113
|
engine: GuardCheckEngineLike;
|
|
88
114
|
exclusionManager: ExclusionManagerLike | null;
|
|
89
115
|
logger: ReturnType<typeof Logger.getInstance>;
|
|
@@ -91,7 +117,7 @@ export declare class ComplianceReporter {
|
|
|
91
117
|
ruleLearner: RuleLearnerLike | null;
|
|
92
118
|
violationsStore: ViolationsStoreLike | null;
|
|
93
119
|
/** @param qualityGateConfig { maxErrors, maxWarnings, minScore } */
|
|
94
|
-
constructor(guardCheckEngine: GuardCheckEngineLike, violationsStore: ViolationsStoreLike | null, ruleLearner: RuleLearnerLike | null, exclusionManager: ExclusionManagerLike | null, qualityGateConfig?: QualityGateThresholds);
|
|
120
|
+
constructor(guardCheckEngine: GuardCheckEngineLike, violationsStore: ViolationsStoreLike | null, ruleLearner: RuleLearnerLike | null, exclusionManager: ExclusionManagerLike | null, qualityGateConfig?: QualityGateThresholds, signalBus?: import('../../infrastructure/signal/SignalBus.js').SignalBus | null);
|
|
95
121
|
/**
|
|
96
122
|
* 生成全项目合规报告
|
|
97
123
|
* @param projectRoot 项目根目录
|
|
@@ -113,6 +139,20 @@ export declare class ComplianceReporter {
|
|
|
113
139
|
minScore: number;
|
|
114
140
|
};
|
|
115
141
|
};
|
|
142
|
+
complianceScore: number;
|
|
143
|
+
coverageScore: number;
|
|
144
|
+
confidenceScore: number;
|
|
145
|
+
uncertainSummary: {
|
|
146
|
+
total: number;
|
|
147
|
+
byLayer: Record<string, number>;
|
|
148
|
+
byReason: Record<string, number>;
|
|
149
|
+
};
|
|
150
|
+
boundaries: {
|
|
151
|
+
type: string;
|
|
152
|
+
description: string;
|
|
153
|
+
affectedRules: string[];
|
|
154
|
+
suggestedAction: string;
|
|
155
|
+
}[];
|
|
116
156
|
summary: {
|
|
117
157
|
filesScanned: number;
|
|
118
158
|
totalViolations: number;
|
|
@@ -54,8 +54,11 @@ export class ComplianceReporter {
|
|
|
54
54
|
qualityGateConfig;
|
|
55
55
|
ruleLearner;
|
|
56
56
|
violationsStore;
|
|
57
|
+
/** 实时规则精度追踪(由 SignalBus 更新) */
|
|
58
|
+
#rulePrecision = new Map();
|
|
59
|
+
#recentViolationCount = 0;
|
|
57
60
|
/** @param qualityGateConfig { maxErrors, maxWarnings, minScore } */
|
|
58
|
-
constructor(guardCheckEngine, violationsStore, ruleLearner, exclusionManager, qualityGateConfig = {}) {
|
|
61
|
+
constructor(guardCheckEngine, violationsStore, ruleLearner, exclusionManager, qualityGateConfig = {}, signalBus) {
|
|
59
62
|
this.engine = guardCheckEngine;
|
|
60
63
|
this.violationsStore = violationsStore;
|
|
61
64
|
this.ruleLearner = ruleLearner;
|
|
@@ -67,6 +70,17 @@ export class ComplianceReporter {
|
|
|
67
70
|
...qualityGateConfig,
|
|
68
71
|
};
|
|
69
72
|
this.logger = Logger.getInstance();
|
|
73
|
+
// Phase 2: 订阅 guard|quality 信号维护实时精度
|
|
74
|
+
if (signalBus) {
|
|
75
|
+
signalBus.subscribe('guard|quality', (signal) => {
|
|
76
|
+
if (signal.type === 'quality' && signal.source === 'RuleLearner' && signal.target) {
|
|
77
|
+
this.#rulePrecision.set(signal.target, signal.value);
|
|
78
|
+
}
|
|
79
|
+
if (signal.type === 'guard') {
|
|
80
|
+
this.#recentViolationCount++;
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
}
|
|
70
84
|
}
|
|
71
85
|
/**
|
|
72
86
|
* 生成全项目合规报告
|
|
@@ -185,8 +199,27 @@ export class ComplianceReporter {
|
|
|
185
199
|
// ViolationsStore not available
|
|
186
200
|
}
|
|
187
201
|
// 9. 评分 + Gate
|
|
188
|
-
const
|
|
189
|
-
|
|
202
|
+
const complianceScore = computeScore(summary, ruleHealth);
|
|
203
|
+
// 9b. 三维度评分: coverage + confidence(来自 capabilityReport)
|
|
204
|
+
const capabilityReport = auditResult.capabilityReport;
|
|
205
|
+
const coverageScore = capabilityReport?.checkCoverage ?? 100;
|
|
206
|
+
const totalChecks = summary.totalViolations + (capabilityReport?.uncertainResults.length ?? 0);
|
|
207
|
+
const uncertainCount = capabilityReport?.uncertainResults.length ?? 0;
|
|
208
|
+
const confidenceScore = totalChecks > 0
|
|
209
|
+
? Math.round((1 - uncertainCount / Math.max(1, totalChecks + filteredFiles.length)) * 100)
|
|
210
|
+
: 100;
|
|
211
|
+
const uncertainSummary = {
|
|
212
|
+
total: uncertainCount,
|
|
213
|
+
byLayer: {},
|
|
214
|
+
byReason: {},
|
|
215
|
+
};
|
|
216
|
+
if (capabilityReport) {
|
|
217
|
+
for (const u of capabilityReport.uncertainResults) {
|
|
218
|
+
uncertainSummary.byLayer[u.layer] = (uncertainSummary.byLayer[u.layer] || 0) + 1;
|
|
219
|
+
uncertainSummary.byReason[u.reason] = (uncertainSummary.byReason[u.reason] || 0) + 1;
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
const gateStatus = evaluateGate(summary, complianceScore, thresholds);
|
|
190
223
|
// 10. 写入 ViolationsStore(记录本次运行)
|
|
191
224
|
try {
|
|
192
225
|
if (this.violationsStore?.appendRun) {
|
|
@@ -194,7 +227,7 @@ export class ComplianceReporter {
|
|
|
194
227
|
this.violationsStore.appendRun({
|
|
195
228
|
filePath: projectRoot,
|
|
196
229
|
violations: allViolations,
|
|
197
|
-
summary: `Compliance scan: score=${
|
|
230
|
+
summary: `Compliance scan: score=${complianceScore} ${gateStatus} | ${summary.errors}E ${summary.warnings}W | cov=${coverageScore} conf=${confidenceScore}`,
|
|
198
231
|
});
|
|
199
232
|
}
|
|
200
233
|
}
|
|
@@ -206,9 +239,14 @@ export class ComplianceReporter {
|
|
|
206
239
|
projectRoot,
|
|
207
240
|
qualityGate: {
|
|
208
241
|
status: gateStatus,
|
|
209
|
-
score,
|
|
242
|
+
score: complianceScore,
|
|
210
243
|
thresholds,
|
|
211
244
|
},
|
|
245
|
+
complianceScore,
|
|
246
|
+
coverageScore,
|
|
247
|
+
confidenceScore,
|
|
248
|
+
uncertainSummary,
|
|
249
|
+
boundaries: capabilityReport?.boundaries ?? [],
|
|
212
250
|
summary,
|
|
213
251
|
topViolations,
|
|
214
252
|
fileHotspots,
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CoverageAnalyzer — Guard 覆盖率矩阵 + Panorama 协同
|
|
3
|
+
*
|
|
4
|
+
* 计算模块级 Rule 覆盖率,识别零覆盖和低覆盖模块。
|
|
5
|
+
* 与 PanoramaService 协同:利用模块划分 + gaps 数据做精准评估。
|
|
6
|
+
*/
|
|
7
|
+
interface DatabaseLike {
|
|
8
|
+
prepare(sql: string): {
|
|
9
|
+
all(...params: unknown[]): Record<string, unknown>[];
|
|
10
|
+
get(...params: unknown[]): Record<string, unknown> | undefined;
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
interface RuleLearnerLike {
|
|
14
|
+
getMetrics(ruleId: string): {
|
|
15
|
+
precision: number;
|
|
16
|
+
recall: number;
|
|
17
|
+
f1: number;
|
|
18
|
+
triggers: number;
|
|
19
|
+
falsePositiveRate: number;
|
|
20
|
+
};
|
|
21
|
+
getAllStats(): Record<string, {
|
|
22
|
+
triggers: number;
|
|
23
|
+
metrics?: {
|
|
24
|
+
precision?: number;
|
|
25
|
+
recall?: number;
|
|
26
|
+
f1?: number;
|
|
27
|
+
};
|
|
28
|
+
}>;
|
|
29
|
+
}
|
|
30
|
+
export interface ModuleCoverage {
|
|
31
|
+
module: string;
|
|
32
|
+
ruleCount: number;
|
|
33
|
+
fpRate: number;
|
|
34
|
+
coverage: number;
|
|
35
|
+
level: 'good' | 'low' | 'zero';
|
|
36
|
+
}
|
|
37
|
+
export interface CoverageMatrix {
|
|
38
|
+
modules: ModuleCoverage[];
|
|
39
|
+
overallCoverage: number;
|
|
40
|
+
zeroModules: string[];
|
|
41
|
+
lowModules: string[];
|
|
42
|
+
}
|
|
43
|
+
export declare class CoverageAnalyzer {
|
|
44
|
+
#private;
|
|
45
|
+
constructor(db: DatabaseLike, options?: {
|
|
46
|
+
ruleLearner?: RuleLearnerLike;
|
|
47
|
+
});
|
|
48
|
+
/**
|
|
49
|
+
* 计算覆盖率矩阵
|
|
50
|
+
* @param moduleFiles 模块名 → 文件路径列表的映射
|
|
51
|
+
*/
|
|
52
|
+
analyze(moduleFiles: Map<string, string[]>): CoverageMatrix;
|
|
53
|
+
}
|
|
54
|
+
export {};
|