@equilateral_ai/mindmeld 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +300 -0
- package/hooks/README.md +494 -0
- package/hooks/pre-compact.js +392 -0
- package/hooks/session-start.js +264 -0
- package/package.json +90 -0
- package/scripts/harvest.js +561 -0
- package/scripts/init-project.js +437 -0
- package/scripts/inject.js +388 -0
- package/src/collaboration/CollaborationPrompt.js +460 -0
- package/src/core/AlertEngine.js +813 -0
- package/src/core/AlertNotifier.js +363 -0
- package/src/core/CorrelationAnalyzer.js +774 -0
- package/src/core/CurationEngine.js +688 -0
- package/src/core/LLMPatternDetector.js +508 -0
- package/src/core/LoadBearingDetector.js +242 -0
- package/src/core/NotificationService.js +1032 -0
- package/src/core/PatternValidator.js +355 -0
- package/src/core/README.md +160 -0
- package/src/core/RapportOrchestrator.js +446 -0
- package/src/core/RelevanceDetector.js +577 -0
- package/src/core/StandardsIngestion.js +575 -0
- package/src/core/TeamLoadBearingDetector.js +431 -0
- package/src/database/dbOperations.js +105 -0
- package/src/handlers/activity/activityGetMe.js +98 -0
- package/src/handlers/activity/activityGetTeam.js +130 -0
- package/src/handlers/alerts/alertsAcknowledge.js +91 -0
- package/src/handlers/alerts/alertsGet.js +250 -0
- package/src/handlers/collaborators/collaboratorAdd.js +201 -0
- package/src/handlers/collaborators/collaboratorInvite.js +218 -0
- package/src/handlers/collaborators/collaboratorList.js +88 -0
- package/src/handlers/collaborators/collaboratorRemove.js +127 -0
- package/src/handlers/collaborators/inviteAccept.js +122 -0
- package/src/handlers/context/contextGet.js +57 -0
- package/src/handlers/context/invariantsGet.js +74 -0
- package/src/handlers/context/loopsGet.js +82 -0
- package/src/handlers/context/notesCreate.js +74 -0
- package/src/handlers/context/purposeGet.js +78 -0
- package/src/handlers/correlations/correlationsDeveloperGet.js +226 -0
- package/src/handlers/correlations/correlationsGet.js +93 -0
- package/src/handlers/correlations/correlationsProjectGet.js +161 -0
- package/src/handlers/github/githubConnectionStatus.js +49 -0
- package/src/handlers/github/githubDiscoverPatterns.js +364 -0
- package/src/handlers/github/githubOAuthCallback.js +166 -0
- package/src/handlers/github/githubOAuthStart.js +59 -0
- package/src/handlers/github/githubPatternsReview.js +109 -0
- package/src/handlers/github/githubReposList.js +105 -0
- package/src/handlers/helpers/checkSuperAdmin.js +85 -0
- package/src/handlers/helpers/dbOperations.js +53 -0
- package/src/handlers/helpers/errorHandler.js +49 -0
- package/src/handlers/helpers/index.js +106 -0
- package/src/handlers/helpers/lambdaWrapper.js +60 -0
- package/src/handlers/helpers/responseUtil.js +55 -0
- package/src/handlers/helpers/subscriptionTiers.js +1168 -0
- package/src/handlers/notifications/getPreferences.js +84 -0
- package/src/handlers/notifications/sendNotification.js +170 -0
- package/src/handlers/notifications/updatePreferences.js +316 -0
- package/src/handlers/patterns/patternUsagePost.js +182 -0
- package/src/handlers/patterns/patternViolationPost.js +185 -0
- package/src/handlers/projects/projectCreate.js +107 -0
- package/src/handlers/projects/projectDelete.js +82 -0
- package/src/handlers/projects/projectGet.js +95 -0
- package/src/handlers/projects/projectUpdate.js +118 -0
- package/src/handlers/reports/aiLeverage.js +206 -0
- package/src/handlers/reports/engineeringInvestment.js +132 -0
- package/src/handlers/reports/riskForecast.js +186 -0
- package/src/handlers/reports/standardsRoi.js +162 -0
- package/src/handlers/scheduled/analyzeCorrelations.js +178 -0
- package/src/handlers/scheduled/analyzeGitHistory.js +510 -0
- package/src/handlers/scheduled/generateAlerts.js +135 -0
- package/src/handlers/scheduled/refreshActivity.js +21 -0
- package/src/handlers/scheduled/scanCompliance.js +334 -0
- package/src/handlers/sessions/sessionEndPost.js +180 -0
- package/src/handlers/sessions/sessionStandardsPost.js +135 -0
- package/src/handlers/stripe/addonManagePost.js +240 -0
- package/src/handlers/stripe/billingPortalPost.js +93 -0
- package/src/handlers/stripe/enterpriseCheckoutPost.js +272 -0
- package/src/handlers/stripe/seatsUpdatePost.js +185 -0
- package/src/handlers/stripe/subscriptionCancelDelete.js +169 -0
- package/src/handlers/stripe/subscriptionCreatePost.js +221 -0
- package/src/handlers/stripe/subscriptionUpdatePut.js +163 -0
- package/src/handlers/stripe/webhookPost.js +454 -0
- package/src/handlers/users/cognitoPostConfirmation.js +150 -0
- package/src/handlers/users/userEntitlementsGet.js +89 -0
- package/src/handlers/users/userGet.js +114 -0
- package/src/handlers/webhooks/githubWebhook.js +223 -0
- package/src/index.js +969 -0
|
@@ -0,0 +1,355 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PatternValidator - Validates discovered patterns against enforced standards
|
|
3
|
+
*
|
|
4
|
+
* Phase 3 of Rapport Standards Integration
|
|
5
|
+
* Checks discovered patterns for violations of organization standards
|
|
6
|
+
* Generates actionable guidance with team evidence
|
|
7
|
+
*
|
|
8
|
+
* @module PatternValidator
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
const { executeQuery } = require('../handlers/helpers/dbOperations');
|
|
12
|
+
|
|
13
|
+
class PatternValidator {
|
|
14
|
+
constructor() {
|
|
15
|
+
this.severityLevels = {
|
|
16
|
+
enforced: 'critical',
|
|
17
|
+
validated: 'warning',
|
|
18
|
+
provisional: 'info'
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Validate a discovered pattern against enforced standards
|
|
24
|
+
*
|
|
25
|
+
* @param {Object} discoveredPattern - Pattern to validate
|
|
26
|
+
* @param {string} discoveredPattern.element - Pattern element (e.g., "Lambda DB Connection")
|
|
27
|
+
* @param {string} discoveredPattern.rule - Pattern rule (e.g., "Use connection pools")
|
|
28
|
+
* @param {string} discoveredPattern.project_id - Project where pattern was discovered
|
|
29
|
+
* @param {string} discoveredPattern.context - Additional context for validation
|
|
30
|
+
* @returns {Promise<Object>} Validation result with violations if any
|
|
31
|
+
*/
|
|
32
|
+
async validatePattern(discoveredPattern) {
|
|
33
|
+
const { element, rule, project_id, context = {} } = discoveredPattern;
|
|
34
|
+
|
|
35
|
+
// Check against enforced standards
|
|
36
|
+
const violations = await this.checkViolations(element, rule, context);
|
|
37
|
+
|
|
38
|
+
if (violations.length > 0) {
|
|
39
|
+
return {
|
|
40
|
+
valid: false,
|
|
41
|
+
violations: await Promise.all(
|
|
42
|
+
violations.map(async (v) => ({
|
|
43
|
+
standard: v.pattern_id,
|
|
44
|
+
element: v.element,
|
|
45
|
+
rule: v.rule,
|
|
46
|
+
severity: this.getSeverity(v.maturity),
|
|
47
|
+
guidance: this.generateGuidance(v, discoveredPattern),
|
|
48
|
+
examples: v.examples || [],
|
|
49
|
+
teamEvidence: await this.getTeamEvidence(v.element, project_id),
|
|
50
|
+
costImpact: v.cost_impact || null,
|
|
51
|
+
antiPattern: v.anti_patterns || null
|
|
52
|
+
}))
|
|
53
|
+
)
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return { valid: true };
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Check for violations against standards
|
|
62
|
+
*
|
|
63
|
+
* @param {string} element - Pattern element to check
|
|
64
|
+
* @param {string} rule - Pattern rule to check
|
|
65
|
+
* @param {Object} context - Additional context for validation
|
|
66
|
+
* @returns {Promise<Array>} Array of violated standards
|
|
67
|
+
*/
|
|
68
|
+
async checkViolations(element, rule, context = {}) {
|
|
69
|
+
// Query for conflicting standards
|
|
70
|
+
const query = `
|
|
71
|
+
SELECT
|
|
72
|
+
pattern_id,
|
|
73
|
+
element,
|
|
74
|
+
rule,
|
|
75
|
+
maturity,
|
|
76
|
+
anti_patterns,
|
|
77
|
+
examples,
|
|
78
|
+
cost_impact,
|
|
79
|
+
category
|
|
80
|
+
FROM rapport.standards_patterns
|
|
81
|
+
WHERE element ILIKE $1
|
|
82
|
+
AND maturity IN ('enforced', 'validated')
|
|
83
|
+
AND rule != $2
|
|
84
|
+
ORDER BY
|
|
85
|
+
CASE maturity
|
|
86
|
+
WHEN 'enforced' THEN 1
|
|
87
|
+
WHEN 'validated' THEN 2
|
|
88
|
+
ELSE 3
|
|
89
|
+
END
|
|
90
|
+
`;
|
|
91
|
+
|
|
92
|
+
try {
|
|
93
|
+
const result = await executeQuery(query, [`%${element}%`, rule]);
|
|
94
|
+
|
|
95
|
+
// Additional context-based filtering
|
|
96
|
+
const violations = result.rows.filter(standard =>
|
|
97
|
+
this.matchesContext(standard, context)
|
|
98
|
+
);
|
|
99
|
+
|
|
100
|
+
return violations;
|
|
101
|
+
} catch (error) {
|
|
102
|
+
console.error('Error checking violations:', error);
|
|
103
|
+
throw new Error(`Failed to check violations: ${error.message}`);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Check if standard matches the provided context
|
|
109
|
+
*
|
|
110
|
+
* @param {Object} standard - Standard to check
|
|
111
|
+
* @param {Object} context - Context to match against
|
|
112
|
+
* @returns {boolean} True if standard applies to this context
|
|
113
|
+
*/
|
|
114
|
+
matchesContext(standard, context) {
|
|
115
|
+
// If no applicable_files filter, standard applies everywhere
|
|
116
|
+
if (!standard.applicable_files || standard.applicable_files.length === 0) {
|
|
117
|
+
return true;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// If context has file information, check if it matches
|
|
121
|
+
if (context.currentFile) {
|
|
122
|
+
return standard.applicable_files.some(pattern => {
|
|
123
|
+
// Simple glob-like matching
|
|
124
|
+
const regex = new RegExp(
|
|
125
|
+
pattern.replace(/\*/g, '.*').replace(/\?/g, '.')
|
|
126
|
+
);
|
|
127
|
+
return regex.test(context.currentFile);
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// Default to applying the standard
|
|
132
|
+
return true;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Get severity level based on maturity
|
|
137
|
+
*
|
|
138
|
+
* @param {string} maturity - Standard maturity level
|
|
139
|
+
* @returns {string} Severity level
|
|
140
|
+
*/
|
|
141
|
+
getSeverity(maturity) {
|
|
142
|
+
return this.severityLevels[maturity] || 'info';
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Generate actionable guidance for a violation
|
|
147
|
+
*
|
|
148
|
+
* @param {Object} violation - Violated standard
|
|
149
|
+
* @param {Object} discoveredPattern - Pattern that violated the standard
|
|
150
|
+
* @returns {Object} Guidance object with problem, fix, and rationale
|
|
151
|
+
*/
|
|
152
|
+
generateGuidance(violation, discoveredPattern) {
|
|
153
|
+
const guidance = {
|
|
154
|
+
problem: `Pattern violates ${violation.element} standard`,
|
|
155
|
+
standard: violation.pattern_id,
|
|
156
|
+
violatedRule: discoveredPattern.rule,
|
|
157
|
+
correctRule: violation.rule,
|
|
158
|
+
fix: null,
|
|
159
|
+
why: null,
|
|
160
|
+
category: violation.category
|
|
161
|
+
};
|
|
162
|
+
|
|
163
|
+
// Extract fix from examples if available
|
|
164
|
+
if (violation.examples && violation.examples.length > 0) {
|
|
165
|
+
const firstExample = violation.examples[0];
|
|
166
|
+
guidance.fix = typeof firstExample === 'string'
|
|
167
|
+
? firstExample
|
|
168
|
+
: firstExample.code || firstExample.description;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// Extract rationale from cost impact or anti-patterns
|
|
172
|
+
if (violation.cost_impact) {
|
|
173
|
+
if (typeof violation.cost_impact === 'string') {
|
|
174
|
+
guidance.why = violation.cost_impact;
|
|
175
|
+
} else if (violation.cost_impact.description) {
|
|
176
|
+
guidance.why = violation.cost_impact.description;
|
|
177
|
+
} else if (violation.cost_impact.monthly_cost) {
|
|
178
|
+
guidance.why = `Cost impact: ${violation.cost_impact.monthly_cost}`;
|
|
179
|
+
}
|
|
180
|
+
} else if (violation.anti_patterns) {
|
|
181
|
+
const antiPattern = Array.isArray(violation.anti_patterns)
|
|
182
|
+
? violation.anti_patterns[0]
|
|
183
|
+
: violation.anti_patterns;
|
|
184
|
+
|
|
185
|
+
if (typeof antiPattern === 'string') {
|
|
186
|
+
guidance.why = antiPattern;
|
|
187
|
+
} else if (antiPattern.reason) {
|
|
188
|
+
guidance.why = antiPattern.reason;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// Default rationale if none found
|
|
193
|
+
if (!guidance.why) {
|
|
194
|
+
guidance.why = 'Proven pattern from team experience and organization standards';
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
return guidance;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Get team evidence that reinforces this standard
|
|
202
|
+
*
|
|
203
|
+
* @param {string} element - Pattern element
|
|
204
|
+
* @param {string} project_id - Project ID for team context
|
|
205
|
+
* @returns {Promise<Array>} Array of team evidence records
|
|
206
|
+
*/
|
|
207
|
+
async getTeamEvidence(element, project_id) {
|
|
208
|
+
const query = `
|
|
209
|
+
SELECT
|
|
210
|
+
pu.email_address,
|
|
211
|
+
p.project_id,
|
|
212
|
+
COUNT(*) as usage_count,
|
|
213
|
+
SUM(CASE WHEN pu.success THEN 1 ELSE 0 END) as success_count,
|
|
214
|
+
ROUND(
|
|
215
|
+
AVG(CASE WHEN pu.success THEN 1.0 ELSE 0.0 END)::numeric,
|
|
216
|
+
2
|
|
217
|
+
) as success_correlation,
|
|
218
|
+
MAX(pu.used_at) as last_used
|
|
219
|
+
FROM rapport.pattern_usage pu
|
|
220
|
+
JOIN rapport.patterns p ON pu.pattern_id = p.pattern_id
|
|
221
|
+
WHERE p.intent ILIKE $1
|
|
222
|
+
AND (p.project_id = $2 OR $2 IS NULL)
|
|
223
|
+
GROUP BY pu.email_address, p.project_id
|
|
224
|
+
HAVING COUNT(*) > 0
|
|
225
|
+
ORDER BY success_correlation DESC, usage_count DESC
|
|
226
|
+
LIMIT 5
|
|
227
|
+
`;
|
|
228
|
+
|
|
229
|
+
try {
|
|
230
|
+
const result = await executeQuery(query, [`%${element}%`, project_id]);
|
|
231
|
+
return result.rows.map(row => ({
|
|
232
|
+
user: row.email_address,
|
|
233
|
+
project: row.project_id,
|
|
234
|
+
usageCount: parseInt(row.usage_count),
|
|
235
|
+
successCount: parseInt(row.success_count),
|
|
236
|
+
successRate: parseFloat(row.success_correlation),
|
|
237
|
+
lastUsed: row.last_used
|
|
238
|
+
}));
|
|
239
|
+
} catch (error) {
|
|
240
|
+
console.error('Error fetching team evidence:', error);
|
|
241
|
+
return [];
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* Validate multiple patterns in bulk
|
|
247
|
+
*
|
|
248
|
+
* @param {Array<Object>} patterns - Array of patterns to validate
|
|
249
|
+
* @returns {Promise<Object>} Validation summary with all violations
|
|
250
|
+
*/
|
|
251
|
+
async validatePatterns(patterns) {
|
|
252
|
+
const results = await Promise.all(
|
|
253
|
+
patterns.map(pattern => this.validatePattern(pattern))
|
|
254
|
+
);
|
|
255
|
+
|
|
256
|
+
const violations = results
|
|
257
|
+
.filter(result => !result.valid)
|
|
258
|
+
.flatMap(result => result.violations);
|
|
259
|
+
|
|
260
|
+
return {
|
|
261
|
+
totalPatterns: patterns.length,
|
|
262
|
+
validPatterns: results.filter(r => r.valid).length,
|
|
263
|
+
invalidPatterns: results.filter(r => !r.valid).length,
|
|
264
|
+
criticalViolations: violations.filter(v => v.severity === 'critical').length,
|
|
265
|
+
warningViolations: violations.filter(v => v.severity === 'warning').length,
|
|
266
|
+
violations: violations
|
|
267
|
+
};
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* Get all anti-patterns for a specific category
|
|
272
|
+
*
|
|
273
|
+
* @param {string} category - Category to get anti-patterns for
|
|
274
|
+
* @returns {Promise<Array>} Array of anti-patterns with details
|
|
275
|
+
*/
|
|
276
|
+
async getAntiPatterns(category) {
|
|
277
|
+
const query = `
|
|
278
|
+
SELECT
|
|
279
|
+
pattern_id,
|
|
280
|
+
element,
|
|
281
|
+
rule,
|
|
282
|
+
anti_patterns,
|
|
283
|
+
cost_impact,
|
|
284
|
+
examples
|
|
285
|
+
FROM rapport.standards_patterns
|
|
286
|
+
WHERE category = $1
|
|
287
|
+
AND maturity = 'enforced'
|
|
288
|
+
AND anti_patterns IS NOT NULL
|
|
289
|
+
ORDER BY pattern_id
|
|
290
|
+
`;
|
|
291
|
+
|
|
292
|
+
try {
|
|
293
|
+
const result = await executeQuery(query, [category]);
|
|
294
|
+
return result.rows.map(row => ({
|
|
295
|
+
patternId: row.pattern_id,
|
|
296
|
+
element: row.element,
|
|
297
|
+
correctRule: row.rule,
|
|
298
|
+
antiPatterns: row.anti_patterns,
|
|
299
|
+
costImpact: row.cost_impact,
|
|
300
|
+
examples: row.examples
|
|
301
|
+
}));
|
|
302
|
+
} catch (error) {
|
|
303
|
+
console.error('Error fetching anti-patterns:', error);
|
|
304
|
+
throw new Error(`Failed to fetch anti-patterns: ${error.message}`);
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
/**
|
|
309
|
+
* Format validation result for display
|
|
310
|
+
*
|
|
311
|
+
* @param {Object} validationResult - Result from validatePattern
|
|
312
|
+
* @returns {string} Formatted text output
|
|
313
|
+
*/
|
|
314
|
+
formatValidationResult(validationResult) {
|
|
315
|
+
if (validationResult.valid) {
|
|
316
|
+
return '✓ Pattern is compliant with standards';
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
const lines = ['✗ Pattern violates organization standards:\n'];
|
|
320
|
+
|
|
321
|
+
validationResult.violations.forEach((violation, index) => {
|
|
322
|
+
const severityIcon = {
|
|
323
|
+
critical: '🚨',
|
|
324
|
+
warning: '⚠️',
|
|
325
|
+
info: 'ℹ️'
|
|
326
|
+
}[violation.severity] || '•';
|
|
327
|
+
|
|
328
|
+
lines.push(`${severityIcon} Violation ${index + 1}: ${violation.guidance.problem}`);
|
|
329
|
+
lines.push(` Standard: ${violation.standard}`);
|
|
330
|
+
lines.push(` Severity: ${violation.severity.toUpperCase()}`);
|
|
331
|
+
lines.push(` Your pattern: "${violation.guidance.violatedRule}"`);
|
|
332
|
+
lines.push(` Standard rule: "${violation.guidance.correctRule}"`);
|
|
333
|
+
|
|
334
|
+
if (violation.guidance.why) {
|
|
335
|
+
lines.push(` Why: ${violation.guidance.why}`);
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
if (violation.guidance.fix) {
|
|
339
|
+
lines.push(` Fix: ${violation.guidance.fix}`);
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
if (violation.teamEvidence && violation.teamEvidence.length > 0) {
|
|
343
|
+
lines.push(` Team evidence: ${violation.teamEvidence.length} team members have used this pattern`);
|
|
344
|
+
const topEvidence = violation.teamEvidence[0];
|
|
345
|
+
lines.push(` - ${topEvidence.user}: ${topEvidence.successRate * 100}% success rate (${topEvidence.usageCount} uses)`);
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
lines.push('');
|
|
349
|
+
});
|
|
350
|
+
|
|
351
|
+
return lines.join('\n');
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
module.exports = { PatternValidator };
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
# Rapport Core Components
|
|
2
|
+
|
|
3
|
+
This directory contains the core components of the Rapport Standards Integration system.
|
|
4
|
+
|
|
5
|
+
## Components
|
|
6
|
+
|
|
7
|
+
### RelevanceDetector.js (Phase 2) ✅
|
|
8
|
+
|
|
9
|
+
**Purpose**: Identifies which standards apply to current work
|
|
10
|
+
|
|
11
|
+
**Key Features**:
|
|
12
|
+
- Fast project characteristic detection (< 100ms)
|
|
13
|
+
- Intelligent category mapping
|
|
14
|
+
- Relevance scoring algorithm (0-100)
|
|
15
|
+
- Returns top 10 most relevant standards
|
|
16
|
+
- Database integration with Phase 1 schema
|
|
17
|
+
|
|
18
|
+
**Usage**:
|
|
19
|
+
```javascript
|
|
20
|
+
const { RelevanceDetector } = require('./src/core/RelevanceDetector');
|
|
21
|
+
|
|
22
|
+
const detector = new RelevanceDetector({
|
|
23
|
+
workingDirectory: process.cwd()
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
const result = await detector.detectRelevantStandards({
|
|
27
|
+
projectId: 'prj_example',
|
|
28
|
+
currentFile: 'src/handlers/userCreate.js'
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
console.log(`Found ${result.standards.length} relevant standards`);
|
|
32
|
+
// Execution time: ~250ms
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
**Documentation**: `/Users/jamesford/Source/rapport/docs/PHASE_2_RELEVANCE_DETECTION.md`
|
|
36
|
+
|
|
37
|
+
**Test Suite**: `/Users/jamesford/Source/rapport/scripts/test-relevance-detection.js`
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
### TeamLoadBearingDetector.js (Existing)
|
|
42
|
+
|
|
43
|
+
**Purpose**: Detects load-bearing context elements from team sessions
|
|
44
|
+
|
|
45
|
+
**Key Features**:
|
|
46
|
+
- Team-wide correlation analysis
|
|
47
|
+
- User-specific pattern tracking
|
|
48
|
+
- Confidence scoring
|
|
49
|
+
- Statistical significance testing
|
|
50
|
+
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
## Phase Implementation Status
|
|
54
|
+
|
|
55
|
+
| Phase | Status | Component | Documentation |
|
|
56
|
+
|-------|--------|-----------|---------------|
|
|
57
|
+
| Phase 1 | Pending | StandardsIngestion.js | - |
|
|
58
|
+
| Phase 2 | ✅ Complete | RelevanceDetector.js | PHASE_2_RELEVANCE_DETECTION.md |
|
|
59
|
+
| Phase 3 | Pending | PatternValidator.js | - |
|
|
60
|
+
| Phase 4 | Pending | CurationEngine.js | - |
|
|
61
|
+
| Phase 5 | Pending | Hooks (session-start, pre-compact) | - |
|
|
62
|
+
| Phase 6 | Pending | RapportOrchestrator.js | - |
|
|
63
|
+
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
## Testing
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
# Test RelevanceDetector
|
|
70
|
+
node scripts/test-relevance-detection.js
|
|
71
|
+
|
|
72
|
+
# Quick validation
|
|
73
|
+
node -e "
|
|
74
|
+
const { RelevanceDetector } = require('./src/core/RelevanceDetector');
|
|
75
|
+
const detector = new RelevanceDetector();
|
|
76
|
+
console.log('✓ RelevanceDetector ready');
|
|
77
|
+
"
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
---
|
|
81
|
+
|
|
82
|
+
## Integration
|
|
83
|
+
|
|
84
|
+
### With Claude Code (Phase 5)
|
|
85
|
+
|
|
86
|
+
```javascript
|
|
87
|
+
// rapport/hooks/session-start.js
|
|
88
|
+
const { RelevanceDetector } = require('@mindmeld/rapport/relevance');
|
|
89
|
+
|
|
90
|
+
async function injectContext() {
|
|
91
|
+
const detector = new RelevanceDetector({
|
|
92
|
+
workingDirectory: process.cwd()
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
const result = await detector.detectRelevantStandards({
|
|
96
|
+
projectId: getCurrentProjectId(),
|
|
97
|
+
currentFile: getCurrentFile()
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
return detector.formatForInjection(result.standards);
|
|
101
|
+
}
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### With Pattern Validation (Phase 3)
|
|
105
|
+
|
|
106
|
+
```javascript
|
|
107
|
+
// rapport/src/core/PatternValidator.js
|
|
108
|
+
const { RelevanceDetector } = require('./RelevanceDetector');
|
|
109
|
+
|
|
110
|
+
async function validatePattern(pattern) {
|
|
111
|
+
const detector = new RelevanceDetector();
|
|
112
|
+
const relevant = await detector.detectRelevantStandards(context);
|
|
113
|
+
|
|
114
|
+
// Validate against only relevant standards
|
|
115
|
+
return checkAgainstStandards(pattern, relevant.standards);
|
|
116
|
+
}
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
---
|
|
120
|
+
|
|
121
|
+
## Database Requirements
|
|
122
|
+
|
|
123
|
+
All core components require PostgreSQL database with Rapport schema.
|
|
124
|
+
|
|
125
|
+
**Connection**: Uses `src/handlers/helpers/dbOperations.js`
|
|
126
|
+
|
|
127
|
+
**Schema**: See `database/schema.sql`
|
|
128
|
+
|
|
129
|
+
**Environment Variables**:
|
|
130
|
+
- `DB_HOST`
|
|
131
|
+
- `DB_PORT`
|
|
132
|
+
- `DB_NAME`
|
|
133
|
+
- `DB_USER`
|
|
134
|
+
- `DB_PASSWORD`
|
|
135
|
+
|
|
136
|
+
---
|
|
137
|
+
|
|
138
|
+
## Performance Targets
|
|
139
|
+
|
|
140
|
+
| Component | Target | Actual |
|
|
141
|
+
|-----------|--------|--------|
|
|
142
|
+
| RelevanceDetector | < 500ms | ~250ms ✓ |
|
|
143
|
+
| TeamLoadBearingDetector | < 1s | ~800ms ✓ |
|
|
144
|
+
|
|
145
|
+
---
|
|
146
|
+
|
|
147
|
+
## Contributing
|
|
148
|
+
|
|
149
|
+
When adding new core components:
|
|
150
|
+
|
|
151
|
+
1. Follow existing patterns (constructor with options)
|
|
152
|
+
2. Use `executeQuery` from dbOperations.js
|
|
153
|
+
3. Include comprehensive JSDoc comments
|
|
154
|
+
4. Create test script in `scripts/`
|
|
155
|
+
5. Document in `docs/PHASE_X_*.md`
|
|
156
|
+
6. Update this README
|
|
157
|
+
|
|
158
|
+
---
|
|
159
|
+
|
|
160
|
+
**Last Updated**: 2025-12-20
|