@codeledger/engine 0.7.2 → 0.7.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/dist/claims/claims.d.ts +14 -0
- package/dist/claims/claims.d.ts.map +1 -0
- package/dist/claims/claims.js +125 -0
- package/dist/claims/claims.js.map +1 -0
- package/dist/claims/index.d.ts +2 -0
- package/dist/claims/index.d.ts.map +1 -0
- package/dist/claims/index.js +2 -0
- package/dist/claims/index.js.map +1 -0
- package/dist/dashboard/index.d.ts +3 -0
- package/dist/dashboard/index.d.ts.map +1 -0
- package/dist/dashboard/index.js +3 -0
- package/dist/dashboard/index.js.map +1 -0
- package/dist/dashboard/metrics.d.ts +24 -0
- package/dist/dashboard/metrics.d.ts.map +1 -0
- package/dist/dashboard/metrics.js +358 -0
- package/dist/dashboard/metrics.js.map +1 -0
- package/dist/dashboard/store.d.ts +26 -0
- package/dist/dashboard/store.d.ts.map +1 -0
- package/dist/dashboard/store.js +97 -0
- package/dist/dashboard/store.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +19 -0
- package/dist/index.js.map +1 -1
- package/dist/integration/ambient-coordinator.d.ts +75 -0
- package/dist/integration/ambient-coordinator.d.ts.map +1 -0
- package/dist/integration/ambient-coordinator.js +183 -0
- package/dist/integration/ambient-coordinator.js.map +1 -0
- package/dist/integration/index.d.ts +4 -0
- package/dist/integration/index.d.ts.map +1 -0
- package/dist/integration/index.js +3 -0
- package/dist/integration/index.js.map +1 -0
- package/dist/integration/warning-throttle.d.ts +63 -0
- package/dist/integration/warning-throttle.d.ts.map +1 -0
- package/dist/integration/warning-throttle.js +347 -0
- package/dist/integration/warning-throttle.js.map +1 -0
- package/dist/intervention/escalation.d.ts +23 -0
- package/dist/intervention/escalation.d.ts.map +1 -0
- package/dist/intervention/escalation.js +149 -0
- package/dist/intervention/escalation.js.map +1 -0
- package/dist/intervention/generator.d.ts +12 -0
- package/dist/intervention/generator.d.ts.map +1 -0
- package/dist/intervention/generator.js +191 -0
- package/dist/intervention/generator.js.map +1 -0
- package/dist/intervention/index.d.ts +4 -0
- package/dist/intervention/index.d.ts.map +1 -0
- package/dist/intervention/index.js +4 -0
- package/dist/intervention/index.js.map +1 -0
- package/dist/intervention/signal-aggregator.d.ts +26 -0
- package/dist/intervention/signal-aggregator.d.ts.map +1 -0
- package/dist/intervention/signal-aggregator.js +274 -0
- package/dist/intervention/signal-aggregator.js.map +1 -0
- package/dist/layer-d/conflict-detector.d.ts +12 -0
- package/dist/layer-d/conflict-detector.d.ts.map +1 -0
- package/dist/layer-d/conflict-detector.js +150 -0
- package/dist/layer-d/conflict-detector.js.map +1 -0
- package/dist/layer-d/index.d.ts +3 -0
- package/dist/layer-d/index.d.ts.map +1 -0
- package/dist/layer-d/index.js +3 -0
- package/dist/layer-d/index.js.map +1 -0
- package/dist/layer-d/surface-extractor.d.ts +10 -0
- package/dist/layer-d/surface-extractor.d.ts.map +1 -0
- package/dist/layer-d/surface-extractor.js +96 -0
- package/dist/layer-d/surface-extractor.js.map +1 -0
- package/dist/policy-domains/domains.d.ts +31 -0
- package/dist/policy-domains/domains.d.ts.map +1 -0
- package/dist/policy-domains/domains.js +445 -0
- package/dist/policy-domains/domains.js.map +1 -0
- package/dist/policy-domains/index.d.ts +8 -0
- package/dist/policy-domains/index.d.ts.map +1 -0
- package/dist/policy-domains/index.js +8 -0
- package/dist/policy-domains/index.js.map +1 -0
- package/dist/pulse/index.d.ts +2 -0
- package/dist/pulse/index.d.ts.map +1 -0
- package/dist/pulse/index.js +2 -0
- package/dist/pulse/index.js.map +1 -0
- package/dist/pulse/pulse.d.ts +20 -0
- package/dist/pulse/pulse.d.ts.map +1 -0
- package/dist/pulse/pulse.js +253 -0
- package/dist/pulse/pulse.js.map +1 -0
- package/dist/severity/index.d.ts +2 -0
- package/dist/severity/index.d.ts.map +1 -0
- package/dist/severity/index.js +2 -0
- package/dist/severity/index.js.map +1 -0
- package/dist/severity/severity.d.ts +48 -0
- package/dist/severity/severity.d.ts.map +1 -0
- package/dist/severity/severity.js +134 -0
- package/dist/severity/severity.js.map +1 -0
- package/dist/staleness/index.d.ts +2 -0
- package/dist/staleness/index.d.ts.map +1 -0
- package/dist/staleness/index.js +2 -0
- package/dist/staleness/index.js.map +1 -0
- package/dist/staleness/jit-staleness.d.ts +29 -0
- package/dist/staleness/jit-staleness.d.ts.map +1 -0
- package/dist/staleness/jit-staleness.js +240 -0
- package/dist/staleness/jit-staleness.js.map +1 -0
- package/dist/team-policy/index.d.ts +1 -1
- package/dist/team-policy/index.d.ts.map +1 -1
- package/dist/team-policy/index.js +1 -1
- package/dist/team-policy/index.js.map +1 -1
- package/dist/team-policy/policy.d.ts +7 -0
- package/dist/team-policy/policy.d.ts.map +1 -1
- package/dist/team-policy/policy.js +38 -0
- package/dist/team-policy/policy.js.map +1 -1
- package/dist/trust/approval.d.ts +16 -0
- package/dist/trust/approval.d.ts.map +1 -0
- package/dist/trust/approval.js +183 -0
- package/dist/trust/approval.js.map +1 -0
- package/dist/trust/capsule.d.ts +36 -0
- package/dist/trust/capsule.d.ts.map +1 -0
- package/dist/trust/capsule.js +206 -0
- package/dist/trust/capsule.js.map +1 -0
- package/dist/trust/index.d.ts +6 -0
- package/dist/trust/index.d.ts.map +1 -0
- package/dist/trust/index.js +6 -0
- package/dist/trust/index.js.map +1 -0
- package/dist/trust/learning-feedback.d.ts +18 -0
- package/dist/trust/learning-feedback.d.ts.map +1 -0
- package/dist/trust/learning-feedback.js +146 -0
- package/dist/trust/learning-feedback.js.map +1 -0
- package/dist/trust/risk-scoring.d.ts +16 -0
- package/dist/trust/risk-scoring.d.ts.map +1 -0
- package/dist/trust/risk-scoring.js +142 -0
- package/dist/trust/risk-scoring.js.map +1 -0
- package/dist/trust/timeline.d.ts +42 -0
- package/dist/trust/timeline.d.ts.map +1 -0
- package/dist/trust/timeline.js +154 -0
- package/dist/trust/timeline.js.map +1 -0
- package/package.json +6 -2
|
@@ -0,0 +1,347 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ambient Conflict Warning — Throttling & Deduplication (Hardened v2.5.1)
|
|
3
|
+
*
|
|
4
|
+
* Generates conflict warnings when sessions overlap, with
|
|
5
|
+
* throttle logic to prevent warning spam. Warnings are
|
|
6
|
+
* deduplicated by content hash and throttled by time interval.
|
|
7
|
+
*
|
|
8
|
+
* Hardening guarantees:
|
|
9
|
+
* - Per-session warning deduplication (same hash never repeats within cooldown)
|
|
10
|
+
* - Severity-aware cooldown windows (HIGH=5min, MEDIUM=15min, LOW=30min)
|
|
11
|
+
* - "Same signal" suppression: if the underlying data hasn't materially changed,
|
|
12
|
+
* the warning is suppressed even after cooldown expires
|
|
13
|
+
* - One-warning-per-surface: overlapping file warnings and severity warnings
|
|
14
|
+
* for the same session pair are merged into a single warning
|
|
15
|
+
* - Staleness warnings only escalate (low→medium→high), never re-emit at same level
|
|
16
|
+
*/
|
|
17
|
+
import { createHash } from 'node:crypto';
|
|
18
|
+
import { readFileSync, writeFileSync, existsSync, mkdirSync } from 'node:fs';
|
|
19
|
+
import { join, dirname } from 'node:path';
|
|
20
|
+
const THROTTLE_FILE = '.codeledger/warning-throttle.json';
|
|
21
|
+
const MAX_WARNINGS_RETAINED = 100;
|
|
22
|
+
/**
|
|
23
|
+
* Severity-aware cooldown intervals.
|
|
24
|
+
* HIGH warnings have short cooldowns (they represent real risk).
|
|
25
|
+
* LOW warnings have long cooldowns (they are informational noise).
|
|
26
|
+
*/
|
|
27
|
+
const COOLDOWN_BY_SEVERITY = {
|
|
28
|
+
HIGH: 5 * 60 * 1000, // 5 minutes — real risk, show relatively quickly
|
|
29
|
+
MEDIUM: 15 * 60 * 1000, // 15 minutes — advisory, moderate cooldown
|
|
30
|
+
LOW: 30 * 60 * 1000, // 30 minutes — informational, long cooldown
|
|
31
|
+
};
|
|
32
|
+
/**
|
|
33
|
+
* Resolve the throttle file path. When a sessionId is provided, the throttle
|
|
34
|
+
* state is stored per-session to avoid cross-session warning suppression.
|
|
35
|
+
*/
|
|
36
|
+
function resolveThrottlePath(repoRoot, sessionId) {
|
|
37
|
+
if (sessionId) {
|
|
38
|
+
return join(repoRoot, '.codeledger', 'sessions', sessionId, 'warning-throttle.json');
|
|
39
|
+
}
|
|
40
|
+
return join(repoRoot, THROTTLE_FILE);
|
|
41
|
+
}
|
|
42
|
+
// ─── Warning Generation ────────────────────────────────────────────────────
|
|
43
|
+
/**
|
|
44
|
+
* Generate conflict warnings from file overlap zones.
|
|
45
|
+
*
|
|
46
|
+
* Hardened: severity is based on overlapping file count with graduated thresholds.
|
|
47
|
+
* Only MEDIUM+ severity overlaps generate warnings (1-file overlap = LOW = silent).
|
|
48
|
+
*/
|
|
49
|
+
export function generateFileOverlapWarnings(sessionId, zones) {
|
|
50
|
+
if (zones.length === 0)
|
|
51
|
+
return [];
|
|
52
|
+
// Group zones by other session
|
|
53
|
+
const bySession = new Map();
|
|
54
|
+
for (const z of zones) {
|
|
55
|
+
const existing = bySession.get(z.other_session) ?? [];
|
|
56
|
+
existing.push(z);
|
|
57
|
+
bySession.set(z.other_session, existing);
|
|
58
|
+
}
|
|
59
|
+
const warnings = [];
|
|
60
|
+
const now = new Date().toISOString();
|
|
61
|
+
for (const [otherSession, sessionZones] of bySession) {
|
|
62
|
+
const files = [...new Set(sessionZones.map(z => z.file))];
|
|
63
|
+
const severity = files.length >= 5 ? 'HIGH' :
|
|
64
|
+
files.length >= 3 ? 'MEDIUM' :
|
|
65
|
+
files.length >= 2 ? 'MEDIUM' :
|
|
66
|
+
'LOW';
|
|
67
|
+
// Hardened: single-file overlaps are LOW and will be suppressed by default.
|
|
68
|
+
// Only surface them if they are in the same module (meaningful overlap).
|
|
69
|
+
const fileList = files.slice(0, 4).join(', ');
|
|
70
|
+
const suffix = files.length > 4 ? ` (+${files.length - 4} more)` : '';
|
|
71
|
+
// Suppress single-file LOW overlap — not actionable enough to surface
|
|
72
|
+
if (severity === 'LOW')
|
|
73
|
+
continue;
|
|
74
|
+
warnings.push({
|
|
75
|
+
sessionId,
|
|
76
|
+
message: `${files.length} shared file(s) with session ${otherSession}: ${fileList}${suffix}`,
|
|
77
|
+
severity,
|
|
78
|
+
overlappingFiles: files,
|
|
79
|
+
relatedSessions: [otherSession],
|
|
80
|
+
timestamp: now,
|
|
81
|
+
warningType: 'file_overlap',
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
return warnings;
|
|
85
|
+
}
|
|
86
|
+
/** Generate warnings from severity assessments (MEDIUM+ only) */
|
|
87
|
+
export function generateSeverityWarnings(sessionId, assessments) {
|
|
88
|
+
const warnings = [];
|
|
89
|
+
const now = new Date().toISOString();
|
|
90
|
+
for (const assessment of assessments) {
|
|
91
|
+
if (assessment.level === 'LOW')
|
|
92
|
+
continue; // Only warn on MEDIUM+
|
|
93
|
+
const otherSession = assessment.sessionPair.find(s => s !== sessionId) ?? assessment.sessionPair[1];
|
|
94
|
+
// Hardened: produce concise, technical signal summaries
|
|
95
|
+
const signalSummaries = assessment.signals
|
|
96
|
+
.filter(s => s.weight >= 0.4) // Only include meaningful signals in message
|
|
97
|
+
.map(s => s.details);
|
|
98
|
+
const signalText = signalSummaries.length > 0
|
|
99
|
+
? signalSummaries.join('; ')
|
|
100
|
+
: `aggregate score ${assessment.aggregateScore.toFixed(2)}`;
|
|
101
|
+
warnings.push({
|
|
102
|
+
sessionId,
|
|
103
|
+
message: `${assessment.level} conflict risk with session ${otherSession}: ${signalText}`,
|
|
104
|
+
severity: assessment.level,
|
|
105
|
+
overlappingFiles: [],
|
|
106
|
+
relatedSessions: [otherSession],
|
|
107
|
+
timestamp: now,
|
|
108
|
+
warningType: 'severity_assessment',
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
return warnings;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Generate staleness warnings.
|
|
115
|
+
*
|
|
116
|
+
* Hardened: only generates warnings for MEDIUM+ staleness.
|
|
117
|
+
* LOW staleness is too noisy for user-facing warnings — it is recorded
|
|
118
|
+
* in the PRCheckResult for programmatic consumers but not surfaced.
|
|
119
|
+
*/
|
|
120
|
+
export function generateStalenessWarnings(updates) {
|
|
121
|
+
const warnings = [];
|
|
122
|
+
const now = new Date().toISOString();
|
|
123
|
+
for (const update of updates) {
|
|
124
|
+
// Hardened: suppress fresh and low staleness entirely
|
|
125
|
+
if (update.stalenessLevel === 'fresh' || update.stalenessLevel === 'low')
|
|
126
|
+
continue;
|
|
127
|
+
const severity = update.stalenessLevel === 'high' ? 'HIGH' : 'MEDIUM';
|
|
128
|
+
const changedFiles = update.changedFiles.map(f => f.path);
|
|
129
|
+
// Hardened: provide specific, actionable summary
|
|
130
|
+
const bundleChanges = update.changedFiles.filter(f => f.inBundle);
|
|
131
|
+
const depChanges = update.changedFiles.filter(f => !f.inBundle && f.inDependencySurface);
|
|
132
|
+
const parts = [];
|
|
133
|
+
if (bundleChanges.length > 0) {
|
|
134
|
+
parts.push(`${bundleChanges.length} bundle file(s) changed`);
|
|
135
|
+
}
|
|
136
|
+
if (depChanges.length > 0) {
|
|
137
|
+
parts.push(`${depChanges.length} dependency file(s) changed`);
|
|
138
|
+
}
|
|
139
|
+
const detail = parts.length > 0 ? parts.join(', ') : update.summary;
|
|
140
|
+
warnings.push({
|
|
141
|
+
sessionId: update.sessionId,
|
|
142
|
+
message: `Context staleness (${update.stalenessLevel}): ${detail}. Refresh recommended before PR.`,
|
|
143
|
+
severity,
|
|
144
|
+
overlappingFiles: changedFiles,
|
|
145
|
+
relatedSessions: [],
|
|
146
|
+
timestamp: now,
|
|
147
|
+
warningType: 'staleness',
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
return warnings;
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Merge overlapping warnings for the same session pair.
|
|
154
|
+
* Prevents both a file-overlap warning and a severity warning for the
|
|
155
|
+
* same pair from reaching the user — keeps only the higher-severity one.
|
|
156
|
+
*/
|
|
157
|
+
export function deduplicateWarningsByPair(warnings) {
|
|
158
|
+
if (warnings.length <= 1)
|
|
159
|
+
return warnings;
|
|
160
|
+
// Build a key for each warning based on session pair
|
|
161
|
+
const pairMap = new Map();
|
|
162
|
+
const severityOrder = { HIGH: 3, MEDIUM: 2, LOW: 1 };
|
|
163
|
+
for (const w of warnings) {
|
|
164
|
+
// Staleness warnings have no related sessions — keep them separate
|
|
165
|
+
if (w.relatedSessions.length === 0) {
|
|
166
|
+
pairMap.set(`staleness:${w.sessionId}:${w.severity}`, w);
|
|
167
|
+
continue;
|
|
168
|
+
}
|
|
169
|
+
const pairKey = [w.sessionId, ...w.relatedSessions].sort().join('::');
|
|
170
|
+
const existing = pairMap.get(pairKey);
|
|
171
|
+
if (!existing || severityOrder[w.severity] > severityOrder[existing.severity]) {
|
|
172
|
+
// Merge overlapping files from both warnings
|
|
173
|
+
if (existing) {
|
|
174
|
+
const mergedFiles = [...new Set([...w.overlappingFiles, ...existing.overlappingFiles])];
|
|
175
|
+
pairMap.set(pairKey, { ...w, overlappingFiles: mergedFiles });
|
|
176
|
+
}
|
|
177
|
+
else {
|
|
178
|
+
pairMap.set(pairKey, w);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
else if (existing && severityOrder[w.severity] === severityOrder[existing.severity]) {
|
|
182
|
+
// Same severity — merge files
|
|
183
|
+
const mergedFiles = [...new Set([...existing.overlappingFiles, ...w.overlappingFiles])];
|
|
184
|
+
pairMap.set(pairKey, { ...existing, overlappingFiles: mergedFiles });
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
return [...pairMap.values()];
|
|
188
|
+
}
|
|
189
|
+
// ─── Throttle State ────────────────────────────────────────────────────────
|
|
190
|
+
/**
|
|
191
|
+
* Compute a content hash for a warning (for dedup).
|
|
192
|
+
* Hardened: includes severity in hash so severity changes bypass throttle.
|
|
193
|
+
*/
|
|
194
|
+
export function warningHash(warning) {
|
|
195
|
+
const hash = createHash('sha256');
|
|
196
|
+
hash.update(warning.sessionId);
|
|
197
|
+
hash.update(warning.severity);
|
|
198
|
+
hash.update(warning.overlappingFiles.sort().join(','));
|
|
199
|
+
hash.update(warning.relatedSessions.sort().join(','));
|
|
200
|
+
return hash.digest('hex').slice(0, 16);
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* Compute a dedup key for a warning based on type and session pair.
|
|
204
|
+
*/
|
|
205
|
+
export function warningDedupKey(warning) {
|
|
206
|
+
const sessions = [warning.sessionId, ...warning.relatedSessions].sort().join('::');
|
|
207
|
+
return `${warning.warningType}:${sessions}`;
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* Coalesce redundant warnings for the same session pair.
|
|
211
|
+
* Alias for deduplicateWarningsByPair.
|
|
212
|
+
*/
|
|
213
|
+
export const coalesceWarnings = deduplicateWarningsByPair;
|
|
214
|
+
/**
|
|
215
|
+
* Compute a "signal fingerprint" that captures the material content of a warning.
|
|
216
|
+
* Used for same-signal suppression: if the fingerprint hasn't changed since last
|
|
217
|
+
* emission, the warning is suppressed even after cooldown expires.
|
|
218
|
+
*/
|
|
219
|
+
function signalFingerprint(warning) {
|
|
220
|
+
const hash = createHash('sha256');
|
|
221
|
+
hash.update(warning.sessionId);
|
|
222
|
+
// Don't include severity — we want to detect when severity changes
|
|
223
|
+
hash.update(warning.overlappingFiles.sort().join(','));
|
|
224
|
+
hash.update(warning.relatedSessions.sort().join(','));
|
|
225
|
+
return hash.digest('hex').slice(0, 12);
|
|
226
|
+
}
|
|
227
|
+
/** Load throttle state from disk */
|
|
228
|
+
export function loadThrottleState(repoRoot, sessionId) {
|
|
229
|
+
const statePath = resolveThrottlePath(repoRoot, sessionId);
|
|
230
|
+
if (existsSync(statePath)) {
|
|
231
|
+
try {
|
|
232
|
+
const raw = JSON.parse(readFileSync(statePath, 'utf-8'));
|
|
233
|
+
// Migrate v1 entries that lack dedupKey/severity
|
|
234
|
+
for (const entry of raw.lastWarnings) {
|
|
235
|
+
if (!entry.dedupKey)
|
|
236
|
+
entry.dedupKey = entry.hash;
|
|
237
|
+
if (!entry.severity)
|
|
238
|
+
entry.severity = 'LOW';
|
|
239
|
+
}
|
|
240
|
+
return raw;
|
|
241
|
+
}
|
|
242
|
+
catch {
|
|
243
|
+
// Corrupted — start fresh
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
return { schema_version: 'warning-throttle/v1', lastWarnings: [] };
|
|
247
|
+
}
|
|
248
|
+
/** Save throttle state to disk */
|
|
249
|
+
export function saveThrottleState(repoRoot, state, sessionId) {
|
|
250
|
+
const statePath = resolveThrottlePath(repoRoot, sessionId);
|
|
251
|
+
const dir = dirname(statePath);
|
|
252
|
+
if (!existsSync(dir))
|
|
253
|
+
mkdirSync(dir, { recursive: true });
|
|
254
|
+
writeFileSync(statePath, JSON.stringify(state, null, 2) + '\n', 'utf-8');
|
|
255
|
+
}
|
|
256
|
+
// ─── Throttle & Dedup ──────────────────────────────────────────────────────
|
|
257
|
+
/**
|
|
258
|
+
* Filter warnings through throttle/dedup.
|
|
259
|
+
* Returns only warnings that should be shown to the user.
|
|
260
|
+
*
|
|
261
|
+
* Hardened algorithm:
|
|
262
|
+
* 1. Deduplicate by session pair (one-warning-per-surface)
|
|
263
|
+
* 2. Apply severity-aware cooldown windows
|
|
264
|
+
* 3. Same-signal suppression (skip if material content unchanged)
|
|
265
|
+
* 4. Severity escalation bypass (always show if severity increased)
|
|
266
|
+
*/
|
|
267
|
+
export function throttleWarnings(repoRoot, warnings, throttleIntervalMs, sessionId) {
|
|
268
|
+
if (warnings.length === 0)
|
|
269
|
+
return [];
|
|
270
|
+
// Step 1: deduplicate by session pair before throttling
|
|
271
|
+
const deduped = deduplicateWarningsByPair(warnings);
|
|
272
|
+
const state = loadThrottleState(repoRoot, sessionId);
|
|
273
|
+
const now = Date.now();
|
|
274
|
+
// Build lookups from stored state
|
|
275
|
+
const recentByHash = new Map();
|
|
276
|
+
const recentByFingerprint = new Map();
|
|
277
|
+
for (const entry of state.lastWarnings) {
|
|
278
|
+
recentByHash.set(entry.hash, new Date(entry.timestamp).getTime());
|
|
279
|
+
if (entry.fingerprint && entry.severity) {
|
|
280
|
+
recentByFingerprint.set(entry.fingerprint, {
|
|
281
|
+
severity: entry.severity,
|
|
282
|
+
timestamp: new Date(entry.timestamp).getTime(),
|
|
283
|
+
});
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
const passed = [];
|
|
287
|
+
const newEntries = [];
|
|
288
|
+
const severityOrder = { HIGH: 3, MEDIUM: 2, LOW: 1 };
|
|
289
|
+
for (const warning of deduped) {
|
|
290
|
+
const hash = warningHash(warning);
|
|
291
|
+
const fp = signalFingerprint(warning);
|
|
292
|
+
const cooldown = throttleIntervalMs ?? COOLDOWN_BY_SEVERITY[warning.severity];
|
|
293
|
+
const lastSeen = recentByHash.get(hash);
|
|
294
|
+
const lastSignal = recentByFingerprint.get(fp);
|
|
295
|
+
// Check 1: exact duplicate within cooldown → suppress
|
|
296
|
+
if (lastSeen !== undefined && now - lastSeen < cooldown) {
|
|
297
|
+
continue;
|
|
298
|
+
}
|
|
299
|
+
// Check 2: same-signal suppression — if the fingerprint matches and severity
|
|
300
|
+
// hasn't escalated, suppress (the user already saw this signal)
|
|
301
|
+
if (lastSignal !== undefined) {
|
|
302
|
+
const severityEscalated = severityOrder[warning.severity] > severityOrder[lastSignal.severity];
|
|
303
|
+
if (!severityEscalated && now - lastSignal.timestamp < cooldown * 2) {
|
|
304
|
+
// Same signal, same or lower severity, within 2× cooldown → suppress
|
|
305
|
+
continue;
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
passed.push(warning);
|
|
309
|
+
newEntries.push({
|
|
310
|
+
hash,
|
|
311
|
+
dedupKey: `${warning.sessionId}:${warning.severity}`,
|
|
312
|
+
timestamp: new Date(now).toISOString(),
|
|
313
|
+
fingerprint: fp,
|
|
314
|
+
severity: warning.severity,
|
|
315
|
+
});
|
|
316
|
+
}
|
|
317
|
+
// Update state: merge new entries, prune old (4× longest cooldown)
|
|
318
|
+
const maxRetention = COOLDOWN_BY_SEVERITY.LOW * 4;
|
|
319
|
+
const updatedWarnings = [...state.lastWarnings, ...newEntries]
|
|
320
|
+
.filter(e => now - new Date(e.timestamp).getTime() < maxRetention)
|
|
321
|
+
.slice(-MAX_WARNINGS_RETAINED);
|
|
322
|
+
saveThrottleState(repoRoot, {
|
|
323
|
+
schema_version: 'warning-throttle/v1',
|
|
324
|
+
lastWarnings: updatedWarnings,
|
|
325
|
+
}, sessionId);
|
|
326
|
+
return passed;
|
|
327
|
+
}
|
|
328
|
+
// ─── Formatting ─────────────────────────────────────────────────────────────
|
|
329
|
+
/**
|
|
330
|
+
* Format warnings as human-readable lines.
|
|
331
|
+
*
|
|
332
|
+
* Hardened tone: measured, technical, precise.
|
|
333
|
+
* - HIGH → "Warning" (not "CRITICAL" or "ALERT")
|
|
334
|
+
* - MEDIUM → "Notice"
|
|
335
|
+
* - LOW → "Info"
|
|
336
|
+
*/
|
|
337
|
+
export function formatWarnings(warnings) {
|
|
338
|
+
if (warnings.length === 0)
|
|
339
|
+
return [];
|
|
340
|
+
const lines = [];
|
|
341
|
+
for (const w of warnings) {
|
|
342
|
+
const prefix = w.severity === 'HIGH' ? 'Warning' : w.severity === 'MEDIUM' ? 'Notice' : 'Info';
|
|
343
|
+
lines.push(` [${prefix}] ${w.message}`);
|
|
344
|
+
}
|
|
345
|
+
return lines;
|
|
346
|
+
}
|
|
347
|
+
//# sourceMappingURL=warning-throttle.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"warning-throttle.js","sourceRoot":"","sources":["../../src/integration/warning-throttle.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Escalation Engine — Architecture Intervention Engine
|
|
3
|
+
*
|
|
4
|
+
* Takes aggregated signals and determines the escalation level
|
|
5
|
+
* based on severity distribution and compound escalation rules.
|
|
6
|
+
*/
|
|
7
|
+
import type { AggregatedSignal, EscalationResult } from '@codeledger/types';
|
|
8
|
+
/**
|
|
9
|
+
* Determine the escalation level from aggregated signals.
|
|
10
|
+
*
|
|
11
|
+
* Rules (evaluated top to bottom, first match wins):
|
|
12
|
+
* 1. Any critical signal → blocking
|
|
13
|
+
* 2. 3+ high signals in the same category → blocking
|
|
14
|
+
* 3. 2+ high signals across different categories → warning
|
|
15
|
+
* 4. Any high signal → advisory
|
|
16
|
+
* 5. Any medium signal → advisory
|
|
17
|
+
* 6. Only low signals → none
|
|
18
|
+
*
|
|
19
|
+
* Compound escalation: when drift + duplication + governance all have
|
|
20
|
+
* signals simultaneously, bump the level up by one.
|
|
21
|
+
*/
|
|
22
|
+
export declare function determineEscalation(signals: AggregatedSignal[]): EscalationResult;
|
|
23
|
+
//# sourceMappingURL=escalation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"escalation.d.ts","sourceRoot":"","sources":["../../src/intervention/escalation.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,KAAK,EAAE,gBAAgB,EAAE,gBAAgB,EAAwB,MAAM,mBAAmB,CAAC;AAyElG;;;;;;;;;;;;;GAaG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,gBAAgB,EAAE,GAAG,gBAAgB,CAgFjF"}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
/** All intervention categories for summary initialization. */
|
|
2
|
+
const ALL_CATEGORIES = [
|
|
3
|
+
'drift_spike',
|
|
4
|
+
'duplication_pressure',
|
|
5
|
+
'governance_breakdown',
|
|
6
|
+
'architectural_violation',
|
|
7
|
+
'test_gap',
|
|
8
|
+
'scope_creep',
|
|
9
|
+
];
|
|
10
|
+
/** Categories that trigger compound escalation when all present. */
|
|
11
|
+
const COMPOUND_TRIGGER_CATEGORIES = [
|
|
12
|
+
'drift_spike',
|
|
13
|
+
'duplication_pressure',
|
|
14
|
+
'governance_breakdown',
|
|
15
|
+
];
|
|
16
|
+
/**
|
|
17
|
+
* Build a signal count summary grouped by category.
|
|
18
|
+
*/
|
|
19
|
+
function buildSignalSummary(signals) {
|
|
20
|
+
const summary = {};
|
|
21
|
+
for (const cat of ALL_CATEGORIES) {
|
|
22
|
+
summary[cat] = 0;
|
|
23
|
+
}
|
|
24
|
+
for (const signal of signals) {
|
|
25
|
+
summary[signal.category] = (summary[signal.category] ?? 0) + 1;
|
|
26
|
+
}
|
|
27
|
+
return summary;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Count signals at a given severity level.
|
|
31
|
+
*/
|
|
32
|
+
function countBySeverity(signals, severity) {
|
|
33
|
+
return signals.filter((s) => s.severity === severity).length;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Count high-severity signals grouped by category, returning category counts.
|
|
37
|
+
*/
|
|
38
|
+
function highSignalsByCategory(signals) {
|
|
39
|
+
const map = new Map();
|
|
40
|
+
for (const signal of signals) {
|
|
41
|
+
if (signal.severity === 'high') {
|
|
42
|
+
map.set(signal.category, (map.get(signal.category) ?? 0) + 1);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return map;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Check whether compound escalation applies.
|
|
49
|
+
* Compound escalation triggers when drift + duplication + governance all have signals.
|
|
50
|
+
*/
|
|
51
|
+
function isCompoundEscalation(signals) {
|
|
52
|
+
const categoriesPresent = new Set(signals.map((s) => s.category));
|
|
53
|
+
return COMPOUND_TRIGGER_CATEGORIES.every((cat) => categoriesPresent.has(cat));
|
|
54
|
+
}
|
|
55
|
+
/** Escalation level ordering for bump operations. */
|
|
56
|
+
const ESCALATION_ORDER = ['none', 'advisory', 'warning', 'blocking'];
|
|
57
|
+
function bumpEscalation(level) {
|
|
58
|
+
const idx = ESCALATION_ORDER.indexOf(level);
|
|
59
|
+
if (idx < ESCALATION_ORDER.length - 1) {
|
|
60
|
+
return ESCALATION_ORDER[idx + 1];
|
|
61
|
+
}
|
|
62
|
+
return level;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Determine the escalation level from aggregated signals.
|
|
66
|
+
*
|
|
67
|
+
* Rules (evaluated top to bottom, first match wins):
|
|
68
|
+
* 1. Any critical signal → blocking
|
|
69
|
+
* 2. 3+ high signals in the same category → blocking
|
|
70
|
+
* 3. 2+ high signals across different categories → warning
|
|
71
|
+
* 4. Any high signal → advisory
|
|
72
|
+
* 5. Any medium signal → advisory
|
|
73
|
+
* 6. Only low signals → none
|
|
74
|
+
*
|
|
75
|
+
* Compound escalation: when drift + duplication + governance all have
|
|
76
|
+
* signals simultaneously, bump the level up by one.
|
|
77
|
+
*/
|
|
78
|
+
export function determineEscalation(signals) {
|
|
79
|
+
const summary = buildSignalSummary(signals);
|
|
80
|
+
const compound = isCompoundEscalation(signals);
|
|
81
|
+
if (signals.length === 0) {
|
|
82
|
+
return {
|
|
83
|
+
level: 'none',
|
|
84
|
+
reason: 'No signals detected',
|
|
85
|
+
compound_escalation: false,
|
|
86
|
+
signal_summary: summary,
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
let level = 'none';
|
|
90
|
+
let reason = '';
|
|
91
|
+
// Rule 1: Any critical signal → blocking
|
|
92
|
+
const criticalCount = countBySeverity(signals, 'critical');
|
|
93
|
+
if (criticalCount > 0) {
|
|
94
|
+
level = 'blocking';
|
|
95
|
+
reason = `${criticalCount} critical signal(s) detected`;
|
|
96
|
+
}
|
|
97
|
+
// Rule 2: 3+ high signals in same category → blocking
|
|
98
|
+
if (level !== 'blocking') {
|
|
99
|
+
const highByCategory = highSignalsByCategory(signals);
|
|
100
|
+
for (const [category, count] of highByCategory) {
|
|
101
|
+
if (count >= 3) {
|
|
102
|
+
level = 'blocking';
|
|
103
|
+
reason = `${count} high-severity signals in category '${category}'`;
|
|
104
|
+
break;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
// Rule 3: 2+ high signals across different categories → warning
|
|
109
|
+
if (level !== 'blocking') {
|
|
110
|
+
const highByCategory = highSignalsByCategory(signals);
|
|
111
|
+
const categoriesWithHigh = highByCategory.size;
|
|
112
|
+
if (categoriesWithHigh >= 2) {
|
|
113
|
+
level = 'warning';
|
|
114
|
+
reason = `High-severity signals across ${categoriesWithHigh} categories`;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
// Rule 4: Any high signal → advisory
|
|
118
|
+
if (level === 'none') {
|
|
119
|
+
const highCount = countBySeverity(signals, 'high');
|
|
120
|
+
if (highCount > 0) {
|
|
121
|
+
level = 'advisory';
|
|
122
|
+
reason = `${highCount} high-severity signal(s)`;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
// Rule 5: Medium signals → advisory
|
|
126
|
+
if (level === 'none') {
|
|
127
|
+
const mediumCount = countBySeverity(signals, 'medium');
|
|
128
|
+
if (mediumCount > 0) {
|
|
129
|
+
level = 'advisory';
|
|
130
|
+
reason = `${mediumCount} medium-severity signal(s)`;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
// Rule 6: Only low → none
|
|
134
|
+
if (level === 'none') {
|
|
135
|
+
reason = 'Only low-severity signals — tracked but no escalation';
|
|
136
|
+
}
|
|
137
|
+
// Compound escalation: bump one level if compound trigger applies
|
|
138
|
+
if (compound && level !== 'blocking') {
|
|
139
|
+
level = bumpEscalation(level);
|
|
140
|
+
reason = `${reason} [compound escalation: drift + duplication + governance converge]`;
|
|
141
|
+
}
|
|
142
|
+
return {
|
|
143
|
+
level,
|
|
144
|
+
reason,
|
|
145
|
+
compound_escalation: compound,
|
|
146
|
+
signal_summary: summary,
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
//# sourceMappingURL=escalation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"escalation.js","sourceRoot":"","sources":["../../src/intervention/escalation.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { AggregatedSignal, EscalationResult, Intervention } from '@codeledger/types';
|
|
2
|
+
/**
|
|
3
|
+
* Generate prioritized interventions from escalation result and aggregated signals.
|
|
4
|
+
*
|
|
5
|
+
* Each intervention is actionable: it includes a title, description, affected files,
|
|
6
|
+
* a suggested fix, and optionally an agent-ready execution template.
|
|
7
|
+
*
|
|
8
|
+
* Interventions are sorted by priority (1 = highest), then by affected file count
|
|
9
|
+
* (more impacted first).
|
|
10
|
+
*/
|
|
11
|
+
export declare function generateInterventions(escalation: EscalationResult, signals: AggregatedSignal[]): Intervention[];
|
|
12
|
+
//# sourceMappingURL=generator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generator.d.ts","sourceRoot":"","sources":["../../src/intervention/generator.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EACV,gBAAgB,EAChB,gBAAgB,EAChB,YAAY,EAGb,MAAM,mBAAmB,CAAC;AAuI3B;;;;;;;;GAQG;AACH,wBAAgB,qBAAqB,CACnC,UAAU,EAAE,gBAAgB,EAC5B,OAAO,EAAE,gBAAgB,EAAE,GAC1B,YAAY,EAAE,CAmDhB"}
|