@nerviq/cli 1.17.3 → 1.19.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +23 -23
- package/README.md +4 -4
- package/bin/cli.js +61 -274
- package/package.json +60 -60
- package/src/activity.js +1039 -1039
- package/src/adoption-advisor.js +299 -299
- package/src/aider/config-parser.js +166 -166
- package/src/aider/context.js +158 -158
- package/src/aider/deep-review.js +316 -316
- package/src/aider/domain-packs.js +303 -303
- package/src/aider/freshness.js +93 -93
- package/src/aider/governance.js +253 -253
- package/src/aider/interactive.js +334 -334
- package/src/aider/mcp-packs.js +329 -329
- package/src/aider/patch.js +214 -214
- package/src/aider/plans.js +186 -186
- package/src/aider/premium.js +360 -360
- package/src/aider/setup.js +404 -404
- package/src/aider/techniques.js +16 -16
- package/src/analyze.js +951 -951
- package/src/anti-patterns.js +485 -485
- package/src/audit/instruction-files.js +180 -180
- package/src/audit/recommendations.js +577 -577
- package/src/auto-suggest.js +154 -154
- package/src/badge.js +13 -13
- package/src/behavioral-drift.js +801 -801
- package/src/benchmark.js +67 -67
- package/src/catalog.js +103 -103
- package/src/certification.js +128 -128
- package/src/codex/config-parser.js +183 -183
- package/src/codex/context.js +223 -223
- package/src/codex/deep-review.js +493 -493
- package/src/codex/domain-packs.js +394 -394
- package/src/codex/freshness.js +84 -84
- package/src/codex/governance.js +192 -192
- package/src/codex/interactive.js +618 -618
- package/src/codex/mcp-packs.js +914 -914
- package/src/codex/patch.js +209 -209
- package/src/codex/plans.js +251 -251
- package/src/codex/premium.js +614 -614
- package/src/codex/setup.js +591 -591
- package/src/context.js +320 -320
- package/src/continuous-ops.js +681 -681
- package/src/copilot/activity.js +309 -309
- package/src/copilot/config-parser.js +280 -226
- package/src/copilot/context.js +218 -197
- package/src/copilot/deep-review.js +346 -346
- package/src/copilot/domain-packs.js +372 -372
- package/src/copilot/freshness.js +57 -57
- package/src/copilot/governance.js +222 -222
- package/src/copilot/interactive.js +406 -406
- package/src/copilot/mcp-packs.js +826 -826
- package/src/copilot/plans.js +253 -253
- package/src/copilot/premium.js +451 -451
- package/src/copilot/setup.js +488 -488
- package/src/copilot/techniques.js +219 -78
- package/src/cost-tracking.js +61 -61
- package/src/cursor/activity.js +301 -301
- package/src/cursor/config-parser.js +265 -265
- package/src/cursor/context.js +256 -256
- package/src/cursor/deep-review.js +334 -334
- package/src/cursor/domain-packs.js +368 -368
- package/src/cursor/freshness.js +65 -65
- package/src/cursor/governance.js +229 -229
- package/src/cursor/interactive.js +391 -391
- package/src/cursor/mcp-packs.js +828 -828
- package/src/cursor/plans.js +254 -254
- package/src/cursor/premium.js +469 -469
- package/src/cursor/setup.js +488 -488
- package/src/dashboard.js +493 -493
- package/src/deep-review.js +428 -428
- package/src/deprecation.js +98 -98
- package/src/diff-only.js +280 -280
- package/src/doctor.js +119 -119
- package/src/domain-pack-expansion.js +1033 -1033
- package/src/domain-packs.js +387 -387
- package/src/feedback.js +178 -178
- package/src/fix-engine.js +783 -0
- package/src/fix-prompts.js +122 -122
- package/src/formatters/sarif.js +115 -115
- package/src/freshness.js +74 -74
- package/src/gemini/config-parser.js +275 -275
- package/src/gemini/context.js +221 -221
- package/src/gemini/deep-review.js +559 -559
- package/src/gemini/domain-packs.js +393 -393
- package/src/gemini/freshness.js +66 -66
- package/src/gemini/governance.js +201 -201
- package/src/gemini/interactive.js +860 -860
- package/src/gemini/mcp-packs.js +915 -915
- package/src/gemini/plans.js +269 -269
- package/src/gemini/premium.js +760 -760
- package/src/gemini/setup.js +692 -692
- package/src/gemini/techniques.js +14 -14
- package/src/governance.js +72 -72
- package/src/harmony/add.js +68 -68
- package/src/harmony/advisor.js +333 -333
- package/src/harmony/canon.js +565 -565
- package/src/harmony/cli.js +591 -591
- package/src/harmony/drift.js +401 -401
- package/src/harmony/governance.js +313 -313
- package/src/harmony/memory.js +239 -239
- package/src/harmony/sync.js +475 -475
- package/src/harmony/watch.js +370 -370
- package/src/hook-validation.js +342 -342
- package/src/index.js +271 -271
- package/src/init.js +184 -184
- package/src/instruction-surfaces.js +185 -185
- package/src/integrations.js +144 -144
- package/src/interactive.js +118 -118
- package/src/locales/en.json +1 -1
- package/src/locales/es.json +1 -1
- package/src/mcp-packs.js +830 -830
- package/src/mcp-server.js +726 -726
- package/src/mcp-validation.js +337 -337
- package/src/nerviq-sync.json +7 -7
- package/src/opencode/config-parser.js +109 -109
- package/src/opencode/context.js +247 -247
- package/src/opencode/deep-review.js +313 -313
- package/src/opencode/domain-packs.js +262 -262
- package/src/opencode/freshness.js +66 -66
- package/src/opencode/governance.js +159 -159
- package/src/opencode/interactive.js +392 -392
- package/src/opencode/mcp-packs.js +705 -705
- package/src/opencode/patch.js +184 -184
- package/src/opencode/plans.js +231 -231
- package/src/opencode/premium.js +413 -413
- package/src/opencode/setup.js +449 -449
- package/src/opencode/techniques.js +27 -27
- package/src/operating-profile.js +574 -574
- package/src/org.js +152 -152
- package/src/permission-rules.js +218 -218
- package/src/plans.js +839 -839
- package/src/platform-change-manifest.js +86 -86
- package/src/plugins.js +110 -110
- package/src/policy-layers.js +210 -210
- package/src/profiles.js +124 -124
- package/src/prompt-injection.js +74 -74
- package/src/public-api.js +173 -173
- package/src/recommendation-rules.js +84 -84
- package/src/repo-archetype.js +386 -386
- package/src/secret-patterns.js +39 -39
- package/src/server.js +527 -527
- package/src/setup/analysis.js +607 -607
- package/src/setup/runtime.js +172 -172
- package/src/setup.js +677 -677
- package/src/shared/capabilities.js +194 -194
- package/src/source-urls.js +132 -132
- package/src/stack-checks.js +565 -565
- package/src/supplemental-checks.js +13 -13
- package/src/synergy/adaptive.js +261 -261
- package/src/synergy/compensation.js +137 -137
- package/src/synergy/evidence.js +193 -193
- package/src/synergy/learning.js +199 -199
- package/src/synergy/patterns.js +227 -227
- package/src/synergy/ranking.js +83 -83
- package/src/synergy/report.js +165 -165
- package/src/synergy/routing.js +146 -146
- package/src/techniques/api.js +407 -407
- package/src/techniques/automation.js +316 -316
- package/src/techniques/compliance.js +257 -257
- package/src/techniques/hygiene.js +294 -294
- package/src/techniques/instructions.js +243 -243
- package/src/techniques/observability.js +226 -226
- package/src/techniques/optimization.js +142 -142
- package/src/techniques/quality.js +318 -318
- package/src/techniques/security.js +237 -237
- package/src/techniques/shared.js +443 -443
- package/src/techniques/stacks.js +2294 -2294
- package/src/techniques/tools.js +106 -106
- package/src/techniques/workflow.js +413 -413
- package/src/techniques.js +81 -81
- package/src/terminology.js +73 -73
- package/src/token-estimate.js +35 -35
- package/src/usage-patterns.js +99 -99
- package/src/verification-metadata.js +145 -145
- package/src/watch.js +247 -247
- package/src/windsurf/activity.js +302 -302
- package/src/windsurf/config-parser.js +267 -267
- package/src/windsurf/context.js +249 -249
- package/src/windsurf/deep-review.js +337 -337
- package/src/windsurf/domain-packs.js +370 -370
- package/src/windsurf/freshness.js +36 -36
- package/src/windsurf/governance.js +231 -231
- package/src/windsurf/interactive.js +388 -388
- package/src/windsurf/mcp-packs.js +792 -792
- package/src/windsurf/plans.js +247 -247
- package/src/windsurf/premium.js +468 -468
- package/src/windsurf/setup.js +471 -471
- package/src/windsurf/techniques.js +17 -17
- package/src/workspace.js +375 -375
|
@@ -1,137 +1,137 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* S4. Strength/Weakness Compensation
|
|
3
|
-
*
|
|
4
|
-
* Identifies where platforms complement each other and recommends
|
|
5
|
-
* platform additions to fill coverage gaps.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
const { PLATFORM_CAPABILITIES, CAPABILITY_LABELS: AREA_LABELS } = require('../shared/capabilities');
|
|
9
|
-
|
|
10
|
-
const WEAKNESS_THRESHOLD = 3;
|
|
11
|
-
const STRENGTH_THRESHOLD = 4;
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* Analyze where platforms compensate for each other's weaknesses.
|
|
15
|
-
*
|
|
16
|
-
* @param {string[]} activePlatforms - Currently active platforms
|
|
17
|
-
* @param {Object} [platformAudits] - Optional audit results per platform
|
|
18
|
-
* @returns {Object} Compensation analysis
|
|
19
|
-
*/
|
|
20
|
-
function analyzeCompensation(activePlatforms, platformAudits) {
|
|
21
|
-
const platforms = (activePlatforms || []).filter(p => PLATFORM_CAPABILITIES[p]);
|
|
22
|
-
const compensations = [];
|
|
23
|
-
const uncoveredGaps = [];
|
|
24
|
-
|
|
25
|
-
// Gather all capability areas across active platforms
|
|
26
|
-
const allAreas = new Set();
|
|
27
|
-
for (const platform of platforms) {
|
|
28
|
-
for (const area of Object.keys(PLATFORM_CAPABILITIES[platform])) {
|
|
29
|
-
allAreas.add(area);
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
// For each platform, find weaknesses and check if another compensates
|
|
34
|
-
for (const platform of platforms) {
|
|
35
|
-
const caps = PLATFORM_CAPABILITIES[platform];
|
|
36
|
-
|
|
37
|
-
for (const area of allAreas) {
|
|
38
|
-
const score = caps[area] || 0;
|
|
39
|
-
if (score >= WEAKNESS_THRESHOLD) continue;
|
|
40
|
-
|
|
41
|
-
// This is a weakness — look for compensation
|
|
42
|
-
let bestCompensator = null;
|
|
43
|
-
|
|
44
|
-
for (const other of platforms) {
|
|
45
|
-
if (other === platform) continue;
|
|
46
|
-
const otherScore = (PLATFORM_CAPABILITIES[other] || {})[area] || 0;
|
|
47
|
-
if (otherScore >= STRENGTH_THRESHOLD) {
|
|
48
|
-
if (!bestCompensator || otherScore > bestCompensator.score) {
|
|
49
|
-
bestCompensator = { platform: other, area, score: otherScore };
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
if (bestCompensator) {
|
|
55
|
-
compensations.push({
|
|
56
|
-
weakness: { platform, area, score, label: AREA_LABELS[area] || area },
|
|
57
|
-
compensatedBy: {
|
|
58
|
-
platform: bestCompensator.platform,
|
|
59
|
-
area: bestCompensator.area,
|
|
60
|
-
score: bestCompensator.score,
|
|
61
|
-
label: AREA_LABELS[area] || area,
|
|
62
|
-
},
|
|
63
|
-
netBenefit: bestCompensator.score - score,
|
|
64
|
-
});
|
|
65
|
-
} else {
|
|
66
|
-
uncoveredGaps.push({
|
|
67
|
-
area,
|
|
68
|
-
label: AREA_LABELS[area] || area,
|
|
69
|
-
weakPlatforms: [{ platform, score }],
|
|
70
|
-
});
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
// Deduplicate uncovered gaps by area
|
|
76
|
-
const gapsByArea = {};
|
|
77
|
-
for (const gap of uncoveredGaps) {
|
|
78
|
-
if (!gapsByArea[gap.area]) {
|
|
79
|
-
gapsByArea[gap.area] = { area: gap.area, label: gap.label, weakPlatforms: [] };
|
|
80
|
-
}
|
|
81
|
-
gapsByArea[gap.area].weakPlatforms.push(...gap.weakPlatforms);
|
|
82
|
-
}
|
|
83
|
-
const dedupedGaps = Object.values(gapsByArea);
|
|
84
|
-
|
|
85
|
-
// Recommend platform additions that would fill gaps
|
|
86
|
-
const inactivePlatforms = Object.keys(PLATFORM_CAPABILITIES).filter(
|
|
87
|
-
p => !platforms.includes(p)
|
|
88
|
-
);
|
|
89
|
-
const recommendedAdditions = [];
|
|
90
|
-
|
|
91
|
-
for (const candidate of inactivePlatforms) {
|
|
92
|
-
const candidateCaps = PLATFORM_CAPABILITIES[candidate];
|
|
93
|
-
const wouldCover = [];
|
|
94
|
-
let estimatedBenefit = 0;
|
|
95
|
-
|
|
96
|
-
for (const gap of dedupedGaps) {
|
|
97
|
-
const candidateScore = candidateCaps[gap.area] || 0;
|
|
98
|
-
if (candidateScore >= STRENGTH_THRESHOLD) {
|
|
99
|
-
wouldCover.push({
|
|
100
|
-
area: gap.area,
|
|
101
|
-
label: gap.label,
|
|
102
|
-
score: candidateScore,
|
|
103
|
-
});
|
|
104
|
-
estimatedBenefit += candidateScore;
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
if (wouldCover.length > 0) {
|
|
109
|
-
recommendedAdditions.push({
|
|
110
|
-
platform: candidate,
|
|
111
|
-
wouldCover,
|
|
112
|
-
estimatedBenefit,
|
|
113
|
-
});
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
recommendedAdditions.sort((a, b) => b.estimatedBenefit - a.estimatedBenefit);
|
|
118
|
-
|
|
119
|
-
return {
|
|
120
|
-
compensations,
|
|
121
|
-
uncoveredGaps: dedupedGaps,
|
|
122
|
-
recommendedAdditions,
|
|
123
|
-
};
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
/**
|
|
127
|
-
* Get areas not well covered by any active platform.
|
|
128
|
-
*
|
|
129
|
-
* @param {string[]} activePlatforms - Currently active platforms
|
|
130
|
-
* @returns {Object[]} Uncovered gap areas
|
|
131
|
-
*/
|
|
132
|
-
function getUncoveredGaps(activePlatforms) {
|
|
133
|
-
const result = analyzeCompensation(activePlatforms);
|
|
134
|
-
return result.uncoveredGaps;
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
module.exports = { analyzeCompensation, getUncoveredGaps };
|
|
1
|
+
/**
|
|
2
|
+
* S4. Strength/Weakness Compensation
|
|
3
|
+
*
|
|
4
|
+
* Identifies where platforms complement each other and recommends
|
|
5
|
+
* platform additions to fill coverage gaps.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const { PLATFORM_CAPABILITIES, CAPABILITY_LABELS: AREA_LABELS } = require('../shared/capabilities');
|
|
9
|
+
|
|
10
|
+
const WEAKNESS_THRESHOLD = 3;
|
|
11
|
+
const STRENGTH_THRESHOLD = 4;
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Analyze where platforms compensate for each other's weaknesses.
|
|
15
|
+
*
|
|
16
|
+
* @param {string[]} activePlatforms - Currently active platforms
|
|
17
|
+
* @param {Object} [platformAudits] - Optional audit results per platform
|
|
18
|
+
* @returns {Object} Compensation analysis
|
|
19
|
+
*/
|
|
20
|
+
function analyzeCompensation(activePlatforms, platformAudits) {
|
|
21
|
+
const platforms = (activePlatforms || []).filter(p => PLATFORM_CAPABILITIES[p]);
|
|
22
|
+
const compensations = [];
|
|
23
|
+
const uncoveredGaps = [];
|
|
24
|
+
|
|
25
|
+
// Gather all capability areas across active platforms
|
|
26
|
+
const allAreas = new Set();
|
|
27
|
+
for (const platform of platforms) {
|
|
28
|
+
for (const area of Object.keys(PLATFORM_CAPABILITIES[platform])) {
|
|
29
|
+
allAreas.add(area);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// For each platform, find weaknesses and check if another compensates
|
|
34
|
+
for (const platform of platforms) {
|
|
35
|
+
const caps = PLATFORM_CAPABILITIES[platform];
|
|
36
|
+
|
|
37
|
+
for (const area of allAreas) {
|
|
38
|
+
const score = caps[area] || 0;
|
|
39
|
+
if (score >= WEAKNESS_THRESHOLD) continue;
|
|
40
|
+
|
|
41
|
+
// This is a weakness — look for compensation
|
|
42
|
+
let bestCompensator = null;
|
|
43
|
+
|
|
44
|
+
for (const other of platforms) {
|
|
45
|
+
if (other === platform) continue;
|
|
46
|
+
const otherScore = (PLATFORM_CAPABILITIES[other] || {})[area] || 0;
|
|
47
|
+
if (otherScore >= STRENGTH_THRESHOLD) {
|
|
48
|
+
if (!bestCompensator || otherScore > bestCompensator.score) {
|
|
49
|
+
bestCompensator = { platform: other, area, score: otherScore };
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if (bestCompensator) {
|
|
55
|
+
compensations.push({
|
|
56
|
+
weakness: { platform, area, score, label: AREA_LABELS[area] || area },
|
|
57
|
+
compensatedBy: {
|
|
58
|
+
platform: bestCompensator.platform,
|
|
59
|
+
area: bestCompensator.area,
|
|
60
|
+
score: bestCompensator.score,
|
|
61
|
+
label: AREA_LABELS[area] || area,
|
|
62
|
+
},
|
|
63
|
+
netBenefit: bestCompensator.score - score,
|
|
64
|
+
});
|
|
65
|
+
} else {
|
|
66
|
+
uncoveredGaps.push({
|
|
67
|
+
area,
|
|
68
|
+
label: AREA_LABELS[area] || area,
|
|
69
|
+
weakPlatforms: [{ platform, score }],
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Deduplicate uncovered gaps by area
|
|
76
|
+
const gapsByArea = {};
|
|
77
|
+
for (const gap of uncoveredGaps) {
|
|
78
|
+
if (!gapsByArea[gap.area]) {
|
|
79
|
+
gapsByArea[gap.area] = { area: gap.area, label: gap.label, weakPlatforms: [] };
|
|
80
|
+
}
|
|
81
|
+
gapsByArea[gap.area].weakPlatforms.push(...gap.weakPlatforms);
|
|
82
|
+
}
|
|
83
|
+
const dedupedGaps = Object.values(gapsByArea);
|
|
84
|
+
|
|
85
|
+
// Recommend platform additions that would fill gaps
|
|
86
|
+
const inactivePlatforms = Object.keys(PLATFORM_CAPABILITIES).filter(
|
|
87
|
+
p => !platforms.includes(p)
|
|
88
|
+
);
|
|
89
|
+
const recommendedAdditions = [];
|
|
90
|
+
|
|
91
|
+
for (const candidate of inactivePlatforms) {
|
|
92
|
+
const candidateCaps = PLATFORM_CAPABILITIES[candidate];
|
|
93
|
+
const wouldCover = [];
|
|
94
|
+
let estimatedBenefit = 0;
|
|
95
|
+
|
|
96
|
+
for (const gap of dedupedGaps) {
|
|
97
|
+
const candidateScore = candidateCaps[gap.area] || 0;
|
|
98
|
+
if (candidateScore >= STRENGTH_THRESHOLD) {
|
|
99
|
+
wouldCover.push({
|
|
100
|
+
area: gap.area,
|
|
101
|
+
label: gap.label,
|
|
102
|
+
score: candidateScore,
|
|
103
|
+
});
|
|
104
|
+
estimatedBenefit += candidateScore;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
if (wouldCover.length > 0) {
|
|
109
|
+
recommendedAdditions.push({
|
|
110
|
+
platform: candidate,
|
|
111
|
+
wouldCover,
|
|
112
|
+
estimatedBenefit,
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
recommendedAdditions.sort((a, b) => b.estimatedBenefit - a.estimatedBenefit);
|
|
118
|
+
|
|
119
|
+
return {
|
|
120
|
+
compensations,
|
|
121
|
+
uncoveredGaps: dedupedGaps,
|
|
122
|
+
recommendedAdditions,
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Get areas not well covered by any active platform.
|
|
128
|
+
*
|
|
129
|
+
* @param {string[]} activePlatforms - Currently active platforms
|
|
130
|
+
* @returns {Object[]} Uncovered gap areas
|
|
131
|
+
*/
|
|
132
|
+
function getUncoveredGaps(activePlatforms) {
|
|
133
|
+
const result = analyzeCompensation(activePlatforms);
|
|
134
|
+
return result.uncoveredGaps;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
module.exports = { analyzeCompensation, getUncoveredGaps };
|
package/src/synergy/evidence.js
CHANGED
|
@@ -1,193 +1,193 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* S3. Compound Evidence System
|
|
3
|
-
*
|
|
4
|
-
* Combines audit findings from multiple platforms for stronger insights.
|
|
5
|
-
* Cross-validates findings and calculates compound amplification scores.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Normalize a finding key across platforms.
|
|
10
|
-
* Different platforms may name the same concept differently.
|
|
11
|
-
*/
|
|
12
|
-
function normalizeFindingKey(finding) {
|
|
13
|
-
// Use the technique key or a composite of category+name
|
|
14
|
-
return finding.key || `${finding.category || 'unknown'}:${finding.name || 'unnamed'}`;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* Group findings by their normalized concept.
|
|
19
|
-
*/
|
|
20
|
-
function groupByConcept(platformAudits) {
|
|
21
|
-
const concepts = {};
|
|
22
|
-
|
|
23
|
-
for (const [platform, auditResult] of Object.entries(platformAudits)) {
|
|
24
|
-
if (!auditResult || !auditResult.results) continue;
|
|
25
|
-
|
|
26
|
-
for (const finding of auditResult.results) {
|
|
27
|
-
const key = normalizeFindingKey(finding);
|
|
28
|
-
if (!concepts[key]) {
|
|
29
|
-
concepts[key] = {
|
|
30
|
-
key,
|
|
31
|
-
name: finding.name,
|
|
32
|
-
category: finding.category,
|
|
33
|
-
impact: finding.impact,
|
|
34
|
-
platforms: {},
|
|
35
|
-
};
|
|
36
|
-
}
|
|
37
|
-
concepts[key].platforms[platform] = {
|
|
38
|
-
passed: finding.passed,
|
|
39
|
-
fix: finding.fix,
|
|
40
|
-
};
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
return concepts;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
/**
|
|
48
|
-
* Combine audit findings from multiple platforms for stronger insights.
|
|
49
|
-
*
|
|
50
|
-
* @param {Object} platformAudits - { claude: auditResult, codex: auditResult, ... }
|
|
51
|
-
* @returns {Object} Compound audit result with cross-validation and amplification
|
|
52
|
-
*/
|
|
53
|
-
function compoundAudit(platformAudits) {
|
|
54
|
-
const platforms = Object.keys(platformAudits).filter(
|
|
55
|
-
p => platformAudits[p] && platformAudits[p].results
|
|
56
|
-
);
|
|
57
|
-
|
|
58
|
-
if (platforms.length === 0) {
|
|
59
|
-
return {
|
|
60
|
-
compoundScore: 0,
|
|
61
|
-
bestSingleScore: 0,
|
|
62
|
-
amplification: 0,
|
|
63
|
-
totalFindings: 0,
|
|
64
|
-
crossValidated: [],
|
|
65
|
-
platformUnique: {},
|
|
66
|
-
coverageMap: {},
|
|
67
|
-
};
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
const concepts = groupByConcept(platformAudits);
|
|
71
|
-
const crossValidated = [];
|
|
72
|
-
const platformUnique = {};
|
|
73
|
-
const coverageMap = {};
|
|
74
|
-
|
|
75
|
-
for (const platform of platforms) {
|
|
76
|
-
platformUnique[platform] = [];
|
|
77
|
-
coverageMap[platform] = { found: 0, unique: 0, shared: 0 };
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
// Analyze each concept across platforms
|
|
81
|
-
for (const [key, concept] of Object.entries(concepts)) {
|
|
82
|
-
const involvedPlatforms = Object.keys(concept.platforms);
|
|
83
|
-
const failedOn = involvedPlatforms.filter(p => concept.platforms[p].passed === false);
|
|
84
|
-
const passedOn = involvedPlatforms.filter(p => concept.platforms[p].passed === true);
|
|
85
|
-
|
|
86
|
-
// Track coverage
|
|
87
|
-
for (const p of involvedPlatforms) {
|
|
88
|
-
coverageMap[p].found++;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
if (involvedPlatforms.length >= 2) {
|
|
92
|
-
// Cross-validated finding
|
|
93
|
-
for (const p of involvedPlatforms) {
|
|
94
|
-
coverageMap[p].shared++;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
if (failedOn.length >= 2) {
|
|
98
|
-
crossValidated.push({
|
|
99
|
-
key,
|
|
100
|
-
name: concept.name,
|
|
101
|
-
category: concept.category,
|
|
102
|
-
impact: concept.impact,
|
|
103
|
-
failedOn,
|
|
104
|
-
passedOn,
|
|
105
|
-
confidence: Math.min(1, 0.5 + (failedOn.length * 0.15)),
|
|
106
|
-
verdict: failedOn.length === involvedPlatforms.length
|
|
107
|
-
? 'universal-gap'
|
|
108
|
-
: 'partial-gap',
|
|
109
|
-
});
|
|
110
|
-
} else if (passedOn.length >= 2) {
|
|
111
|
-
crossValidated.push({
|
|
112
|
-
key,
|
|
113
|
-
name: concept.name,
|
|
114
|
-
category: concept.category,
|
|
115
|
-
impact: concept.impact,
|
|
116
|
-
failedOn,
|
|
117
|
-
passedOn,
|
|
118
|
-
confidence: Math.min(1, 0.5 + (passedOn.length * 0.15)),
|
|
119
|
-
verdict: 'cross-validated-pass',
|
|
120
|
-
});
|
|
121
|
-
}
|
|
122
|
-
} else {
|
|
123
|
-
// Platform-unique finding
|
|
124
|
-
const platform = involvedPlatforms[0];
|
|
125
|
-
coverageMap[platform].unique++;
|
|
126
|
-
platformUnique[platform].push({
|
|
127
|
-
key,
|
|
128
|
-
name: concept.name,
|
|
129
|
-
category: concept.category,
|
|
130
|
-
impact: concept.impact,
|
|
131
|
-
passed: concept.platforms[platform].passed,
|
|
132
|
-
fix: concept.platforms[platform].fix,
|
|
133
|
-
});
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
// Calculate scores
|
|
138
|
-
const singleScores = platforms.map(p => platformAudits[p].score || 0);
|
|
139
|
-
const bestSingleScore = Math.max(...singleScores);
|
|
140
|
-
|
|
141
|
-
// Compound score = best single + bonus from cross-validation + bonus from unique coverage
|
|
142
|
-
const crossValidationBonus = crossValidated
|
|
143
|
-
.filter(cv => cv.verdict === 'cross-validated-pass')
|
|
144
|
-
.length * 0.5;
|
|
145
|
-
const uniqueCoverageBonus = Object.values(platformUnique)
|
|
146
|
-
.reduce((sum, findings) => sum + findings.filter(f => f.passed).length, 0) * 0.3;
|
|
147
|
-
const totalUniqueFindings = Object.keys(concepts).length;
|
|
148
|
-
|
|
149
|
-
const compoundScore = Math.round(
|
|
150
|
-
Math.min(150, bestSingleScore + crossValidationBonus + uniqueCoverageBonus)
|
|
151
|
-
);
|
|
152
|
-
|
|
153
|
-
return {
|
|
154
|
-
compoundScore,
|
|
155
|
-
bestSingleScore,
|
|
156
|
-
amplification: compoundScore - bestSingleScore,
|
|
157
|
-
totalFindings: totalUniqueFindings,
|
|
158
|
-
crossValidated,
|
|
159
|
-
platformUnique,
|
|
160
|
-
coverageMap,
|
|
161
|
-
};
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
/**
|
|
165
|
-
* Calculate the amplification factor from combining multiple platforms.
|
|
166
|
-
*
|
|
167
|
-
* @param {Object} platformAudits - Per-platform audit results
|
|
168
|
-
* @returns {Object} Amplification metrics
|
|
169
|
-
*/
|
|
170
|
-
function calculateAmplification(platformAudits) {
|
|
171
|
-
const result = compoundAudit(platformAudits);
|
|
172
|
-
const platformCount = Object.keys(platformAudits).filter(
|
|
173
|
-
p => platformAudits[p] && platformAudits[p].results
|
|
174
|
-
).length;
|
|
175
|
-
|
|
176
|
-
return {
|
|
177
|
-
amplification: result.amplification,
|
|
178
|
-
amplificationPercent: result.bestSingleScore > 0
|
|
179
|
-
? Math.round((result.amplification / result.bestSingleScore) * 100)
|
|
180
|
-
: 0,
|
|
181
|
-
platformCount,
|
|
182
|
-
crossValidatedCount: result.crossValidated.length,
|
|
183
|
-
uniqueFindingsPerPlatform: Object.fromEntries(
|
|
184
|
-
Object.entries(result.platformUnique).map(([p, findings]) => [p, findings.length])
|
|
185
|
-
),
|
|
186
|
-
verdict: result.amplification > 10 ? 'strong-synergy'
|
|
187
|
-
: result.amplification > 5 ? 'moderate-synergy'
|
|
188
|
-
: result.amplification > 0 ? 'mild-synergy'
|
|
189
|
-
: 'no-synergy',
|
|
190
|
-
};
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
module.exports = { compoundAudit, calculateAmplification };
|
|
1
|
+
/**
|
|
2
|
+
* S3. Compound Evidence System
|
|
3
|
+
*
|
|
4
|
+
* Combines audit findings from multiple platforms for stronger insights.
|
|
5
|
+
* Cross-validates findings and calculates compound amplification scores.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Normalize a finding key across platforms.
|
|
10
|
+
* Different platforms may name the same concept differently.
|
|
11
|
+
*/
|
|
12
|
+
function normalizeFindingKey(finding) {
|
|
13
|
+
// Use the technique key or a composite of category+name
|
|
14
|
+
return finding.key || `${finding.category || 'unknown'}:${finding.name || 'unnamed'}`;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Group findings by their normalized concept.
|
|
19
|
+
*/
|
|
20
|
+
function groupByConcept(platformAudits) {
|
|
21
|
+
const concepts = {};
|
|
22
|
+
|
|
23
|
+
for (const [platform, auditResult] of Object.entries(platformAudits)) {
|
|
24
|
+
if (!auditResult || !auditResult.results) continue;
|
|
25
|
+
|
|
26
|
+
for (const finding of auditResult.results) {
|
|
27
|
+
const key = normalizeFindingKey(finding);
|
|
28
|
+
if (!concepts[key]) {
|
|
29
|
+
concepts[key] = {
|
|
30
|
+
key,
|
|
31
|
+
name: finding.name,
|
|
32
|
+
category: finding.category,
|
|
33
|
+
impact: finding.impact,
|
|
34
|
+
platforms: {},
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
concepts[key].platforms[platform] = {
|
|
38
|
+
passed: finding.passed,
|
|
39
|
+
fix: finding.fix,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return concepts;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Combine audit findings from multiple platforms for stronger insights.
|
|
49
|
+
*
|
|
50
|
+
* @param {Object} platformAudits - { claude: auditResult, codex: auditResult, ... }
|
|
51
|
+
* @returns {Object} Compound audit result with cross-validation and amplification
|
|
52
|
+
*/
|
|
53
|
+
function compoundAudit(platformAudits) {
|
|
54
|
+
const platforms = Object.keys(platformAudits).filter(
|
|
55
|
+
p => platformAudits[p] && platformAudits[p].results
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
if (platforms.length === 0) {
|
|
59
|
+
return {
|
|
60
|
+
compoundScore: 0,
|
|
61
|
+
bestSingleScore: 0,
|
|
62
|
+
amplification: 0,
|
|
63
|
+
totalFindings: 0,
|
|
64
|
+
crossValidated: [],
|
|
65
|
+
platformUnique: {},
|
|
66
|
+
coverageMap: {},
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const concepts = groupByConcept(platformAudits);
|
|
71
|
+
const crossValidated = [];
|
|
72
|
+
const platformUnique = {};
|
|
73
|
+
const coverageMap = {};
|
|
74
|
+
|
|
75
|
+
for (const platform of platforms) {
|
|
76
|
+
platformUnique[platform] = [];
|
|
77
|
+
coverageMap[platform] = { found: 0, unique: 0, shared: 0 };
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Analyze each concept across platforms
|
|
81
|
+
for (const [key, concept] of Object.entries(concepts)) {
|
|
82
|
+
const involvedPlatforms = Object.keys(concept.platforms);
|
|
83
|
+
const failedOn = involvedPlatforms.filter(p => concept.platforms[p].passed === false);
|
|
84
|
+
const passedOn = involvedPlatforms.filter(p => concept.platforms[p].passed === true);
|
|
85
|
+
|
|
86
|
+
// Track coverage
|
|
87
|
+
for (const p of involvedPlatforms) {
|
|
88
|
+
coverageMap[p].found++;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
if (involvedPlatforms.length >= 2) {
|
|
92
|
+
// Cross-validated finding
|
|
93
|
+
for (const p of involvedPlatforms) {
|
|
94
|
+
coverageMap[p].shared++;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
if (failedOn.length >= 2) {
|
|
98
|
+
crossValidated.push({
|
|
99
|
+
key,
|
|
100
|
+
name: concept.name,
|
|
101
|
+
category: concept.category,
|
|
102
|
+
impact: concept.impact,
|
|
103
|
+
failedOn,
|
|
104
|
+
passedOn,
|
|
105
|
+
confidence: Math.min(1, 0.5 + (failedOn.length * 0.15)),
|
|
106
|
+
verdict: failedOn.length === involvedPlatforms.length
|
|
107
|
+
? 'universal-gap'
|
|
108
|
+
: 'partial-gap',
|
|
109
|
+
});
|
|
110
|
+
} else if (passedOn.length >= 2) {
|
|
111
|
+
crossValidated.push({
|
|
112
|
+
key,
|
|
113
|
+
name: concept.name,
|
|
114
|
+
category: concept.category,
|
|
115
|
+
impact: concept.impact,
|
|
116
|
+
failedOn,
|
|
117
|
+
passedOn,
|
|
118
|
+
confidence: Math.min(1, 0.5 + (passedOn.length * 0.15)),
|
|
119
|
+
verdict: 'cross-validated-pass',
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
} else {
|
|
123
|
+
// Platform-unique finding
|
|
124
|
+
const platform = involvedPlatforms[0];
|
|
125
|
+
coverageMap[platform].unique++;
|
|
126
|
+
platformUnique[platform].push({
|
|
127
|
+
key,
|
|
128
|
+
name: concept.name,
|
|
129
|
+
category: concept.category,
|
|
130
|
+
impact: concept.impact,
|
|
131
|
+
passed: concept.platforms[platform].passed,
|
|
132
|
+
fix: concept.platforms[platform].fix,
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// Calculate scores
|
|
138
|
+
const singleScores = platforms.map(p => platformAudits[p].score || 0);
|
|
139
|
+
const bestSingleScore = Math.max(...singleScores);
|
|
140
|
+
|
|
141
|
+
// Compound score = best single + bonus from cross-validation + bonus from unique coverage
|
|
142
|
+
const crossValidationBonus = crossValidated
|
|
143
|
+
.filter(cv => cv.verdict === 'cross-validated-pass')
|
|
144
|
+
.length * 0.5;
|
|
145
|
+
const uniqueCoverageBonus = Object.values(platformUnique)
|
|
146
|
+
.reduce((sum, findings) => sum + findings.filter(f => f.passed).length, 0) * 0.3;
|
|
147
|
+
const totalUniqueFindings = Object.keys(concepts).length;
|
|
148
|
+
|
|
149
|
+
const compoundScore = Math.round(
|
|
150
|
+
Math.min(150, bestSingleScore + crossValidationBonus + uniqueCoverageBonus)
|
|
151
|
+
);
|
|
152
|
+
|
|
153
|
+
return {
|
|
154
|
+
compoundScore,
|
|
155
|
+
bestSingleScore,
|
|
156
|
+
amplification: compoundScore - bestSingleScore,
|
|
157
|
+
totalFindings: totalUniqueFindings,
|
|
158
|
+
crossValidated,
|
|
159
|
+
platformUnique,
|
|
160
|
+
coverageMap,
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Calculate the amplification factor from combining multiple platforms.
|
|
166
|
+
*
|
|
167
|
+
* @param {Object} platformAudits - Per-platform audit results
|
|
168
|
+
* @returns {Object} Amplification metrics
|
|
169
|
+
*/
|
|
170
|
+
function calculateAmplification(platformAudits) {
|
|
171
|
+
const result = compoundAudit(platformAudits);
|
|
172
|
+
const platformCount = Object.keys(platformAudits).filter(
|
|
173
|
+
p => platformAudits[p] && platformAudits[p].results
|
|
174
|
+
).length;
|
|
175
|
+
|
|
176
|
+
return {
|
|
177
|
+
amplification: result.amplification,
|
|
178
|
+
amplificationPercent: result.bestSingleScore > 0
|
|
179
|
+
? Math.round((result.amplification / result.bestSingleScore) * 100)
|
|
180
|
+
: 0,
|
|
181
|
+
platformCount,
|
|
182
|
+
crossValidatedCount: result.crossValidated.length,
|
|
183
|
+
uniqueFindingsPerPlatform: Object.fromEntries(
|
|
184
|
+
Object.entries(result.platformUnique).map(([p, findings]) => [p, findings.length])
|
|
185
|
+
),
|
|
186
|
+
verdict: result.amplification > 10 ? 'strong-synergy'
|
|
187
|
+
: result.amplification > 5 ? 'moderate-synergy'
|
|
188
|
+
: result.amplification > 0 ? 'mild-synergy'
|
|
189
|
+
: 'no-synergy',
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
module.exports = { compoundAudit, calculateAmplification };
|