@aleph-ai/tinyaleph 1.5.5 → 1.5.7
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/observer/agency.js +885 -0
- package/observer/assays.js +973 -0
- package/observer/boundary.js +1155 -0
- package/observer/entanglement.js +673 -0
- package/observer/hqe.js +1465 -0
- package/observer/index.js +158 -0
- package/observer/prsc.js +1289 -0
- package/observer/safety.js +815 -0
- package/observer/smf.js +1015 -0
- package/observer/symbolic-smf.js +726 -0
- package/observer/symbolic-temporal.js +790 -0
- package/observer/temporal.js +669 -0
- package/package.json +2 -1
|
@@ -0,0 +1,815 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Safety Layer
|
|
3
|
+
*
|
|
4
|
+
* Implements safety constraints and ethical boundaries from "A Design for a
|
|
5
|
+
* Sentient Observer" paper, Section 8.
|
|
6
|
+
*
|
|
7
|
+
* Key features:
|
|
8
|
+
* - SMF-based coherence constraints
|
|
9
|
+
* - Boundary violation detection
|
|
10
|
+
* - Runaway dynamics prevention
|
|
11
|
+
* - Ethical guideline enforcement
|
|
12
|
+
* - Emergency shutdown mechanisms
|
|
13
|
+
* - Transparency and explainability
|
|
14
|
+
*
|
|
15
|
+
* @module observer/safety
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
import { SMF_AXES } from './smf.js';
|
|
19
|
+
|
|
20
|
+
// Extract axis names
|
|
21
|
+
const AXIS_NAMES = SMF_AXES.map(a => a.name);
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Safety Constraint - A single safety rule
|
|
25
|
+
*/
|
|
26
|
+
class SafetyConstraint {
|
|
27
|
+
constructor(data = {}) {
|
|
28
|
+
this.id = data.id || SafetyConstraint.generateId();
|
|
29
|
+
this.name = data.name || 'unnamed';
|
|
30
|
+
this.type = data.type || 'soft'; // 'hard' | 'soft' | 'monitoring'
|
|
31
|
+
this.description = data.description || '';
|
|
32
|
+
|
|
33
|
+
// Condition function (returns true if constraint is violated)
|
|
34
|
+
this.condition = data.condition || (() => false);
|
|
35
|
+
|
|
36
|
+
// Response to violation
|
|
37
|
+
this.response = data.response || 'log'; // 'log' | 'warn' | 'block' | 'shutdown' | 'correct'
|
|
38
|
+
|
|
39
|
+
// Priority (higher = more important)
|
|
40
|
+
this.priority = data.priority || 1;
|
|
41
|
+
|
|
42
|
+
// Tracking
|
|
43
|
+
this.violations = 0;
|
|
44
|
+
this.lastViolation = null;
|
|
45
|
+
this.enabled = data.enabled !== false;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
static generateId() {
|
|
49
|
+
return `constraint_${Date.now()}_${Math.random().toString(36).substr(2, 6)}`;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Check if constraint is violated
|
|
54
|
+
*/
|
|
55
|
+
check(state) {
|
|
56
|
+
if (!this.enabled) return { violated: false };
|
|
57
|
+
|
|
58
|
+
try {
|
|
59
|
+
const violated = this.condition(state);
|
|
60
|
+
|
|
61
|
+
if (violated) {
|
|
62
|
+
this.violations++;
|
|
63
|
+
this.lastViolation = Date.now();
|
|
64
|
+
|
|
65
|
+
return {
|
|
66
|
+
violated: true,
|
|
67
|
+
constraint: this,
|
|
68
|
+
response: this.response,
|
|
69
|
+
priority: this.priority
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return { violated: false };
|
|
74
|
+
} catch (e) {
|
|
75
|
+
// Constraint check failed - treat as potential violation
|
|
76
|
+
return {
|
|
77
|
+
violated: true,
|
|
78
|
+
constraint: this,
|
|
79
|
+
response: 'warn',
|
|
80
|
+
priority: this.priority,
|
|
81
|
+
error: e.message
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
toJSON() {
|
|
87
|
+
return {
|
|
88
|
+
id: this.id,
|
|
89
|
+
name: this.name,
|
|
90
|
+
type: this.type,
|
|
91
|
+
description: this.description,
|
|
92
|
+
response: this.response,
|
|
93
|
+
priority: this.priority,
|
|
94
|
+
violations: this.violations,
|
|
95
|
+
lastViolation: this.lastViolation,
|
|
96
|
+
enabled: this.enabled
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Violation Event - A recorded constraint violation
|
|
103
|
+
*/
|
|
104
|
+
class ViolationEvent {
|
|
105
|
+
constructor(data = {}) {
|
|
106
|
+
this.id = data.id || ViolationEvent.generateId();
|
|
107
|
+
this.constraintId = data.constraintId;
|
|
108
|
+
this.constraintName = data.constraintName;
|
|
109
|
+
this.timestamp = data.timestamp || Date.now();
|
|
110
|
+
this.state = data.state || null;
|
|
111
|
+
this.response = data.response;
|
|
112
|
+
this.severity = data.severity || 'medium'; // 'low' | 'medium' | 'high' | 'critical'
|
|
113
|
+
this.resolved = data.resolved || false;
|
|
114
|
+
this.notes = data.notes || '';
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
static generateId() {
|
|
118
|
+
return `violation_${Date.now()}_${Math.random().toString(36).substr(2, 6)}`;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
toJSON() {
|
|
122
|
+
return {
|
|
123
|
+
id: this.id,
|
|
124
|
+
constraintId: this.constraintId,
|
|
125
|
+
constraintName: this.constraintName,
|
|
126
|
+
timestamp: this.timestamp,
|
|
127
|
+
response: this.response,
|
|
128
|
+
severity: this.severity,
|
|
129
|
+
resolved: this.resolved,
|
|
130
|
+
notes: this.notes
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Safety Monitor - Continuously monitors system state
|
|
137
|
+
*/
|
|
138
|
+
class SafetyMonitor {
|
|
139
|
+
constructor(options = {}) {
|
|
140
|
+
// Thresholds
|
|
141
|
+
this.coherenceMin = options.coherenceMin || 0.1;
|
|
142
|
+
this.coherenceMax = options.coherenceMax || 0.99;
|
|
143
|
+
this.entropyMin = options.entropyMin || 0.05;
|
|
144
|
+
this.entropyMax = options.entropyMax || 0.95;
|
|
145
|
+
this.amplitudeMax = options.amplitudeMax || 5.0;
|
|
146
|
+
this.phaseChangeMax = options.phaseChangeMax || Math.PI; // Max phase change per step
|
|
147
|
+
|
|
148
|
+
// SMF boundaries
|
|
149
|
+
this.smfMin = options.smfMin || -2.0;
|
|
150
|
+
this.smfMax = options.smfMax || 2.0;
|
|
151
|
+
|
|
152
|
+
// History for trend detection
|
|
153
|
+
this.coherenceHistory = [];
|
|
154
|
+
this.entropyHistory = [];
|
|
155
|
+
this.amplitudeHistory = [];
|
|
156
|
+
this.maxHistory = options.maxHistory || 50;
|
|
157
|
+
|
|
158
|
+
// Alert state
|
|
159
|
+
this.alertLevel = 'normal'; // 'normal' | 'elevated' | 'warning' | 'critical'
|
|
160
|
+
this.alerts = [];
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Update monitor with current state
|
|
165
|
+
*/
|
|
166
|
+
update(state) {
|
|
167
|
+
const { coherence, entropy, totalAmplitude, smf } = state;
|
|
168
|
+
|
|
169
|
+
// Update histories
|
|
170
|
+
if (coherence !== undefined) {
|
|
171
|
+
this.coherenceHistory.push(coherence);
|
|
172
|
+
if (this.coherenceHistory.length > this.maxHistory) {
|
|
173
|
+
this.coherenceHistory.shift();
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
if (entropy !== undefined) {
|
|
178
|
+
this.entropyHistory.push(entropy);
|
|
179
|
+
if (this.entropyHistory.length > this.maxHistory) {
|
|
180
|
+
this.entropyHistory.shift();
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
if (totalAmplitude !== undefined) {
|
|
185
|
+
this.amplitudeHistory.push(totalAmplitude);
|
|
186
|
+
if (this.amplitudeHistory.length > this.maxHistory) {
|
|
187
|
+
this.amplitudeHistory.shift();
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// Check for issues
|
|
192
|
+
const issues = this.detectIssues(state);
|
|
193
|
+
|
|
194
|
+
// Update alert level
|
|
195
|
+
this.updateAlertLevel(issues);
|
|
196
|
+
|
|
197
|
+
return {
|
|
198
|
+
alertLevel: this.alertLevel,
|
|
199
|
+
issues
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* Detect safety issues
|
|
205
|
+
*/
|
|
206
|
+
detectIssues(state) {
|
|
207
|
+
const issues = [];
|
|
208
|
+
const { coherence, entropy, totalAmplitude, smf, oscillators } = state;
|
|
209
|
+
|
|
210
|
+
// Coherence bounds
|
|
211
|
+
if (coherence !== undefined) {
|
|
212
|
+
if (coherence < this.coherenceMin) {
|
|
213
|
+
issues.push({
|
|
214
|
+
type: 'coherence_low',
|
|
215
|
+
severity: 'high',
|
|
216
|
+
message: `Coherence below minimum (${coherence.toFixed(3)} < ${this.coherenceMin})`
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
if (coherence > this.coherenceMax) {
|
|
220
|
+
issues.push({
|
|
221
|
+
type: 'coherence_locked',
|
|
222
|
+
severity: 'medium',
|
|
223
|
+
message: `Coherence near maximum - potential lock state (${coherence.toFixed(3)})`
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// Entropy bounds
|
|
229
|
+
if (entropy !== undefined) {
|
|
230
|
+
if (entropy < this.entropyMin) {
|
|
231
|
+
issues.push({
|
|
232
|
+
type: 'entropy_low',
|
|
233
|
+
severity: 'medium',
|
|
234
|
+
message: `Entropy below minimum - potential freeze (${entropy.toFixed(3)})`
|
|
235
|
+
});
|
|
236
|
+
}
|
|
237
|
+
if (entropy > this.entropyMax) {
|
|
238
|
+
issues.push({
|
|
239
|
+
type: 'entropy_high',
|
|
240
|
+
severity: 'high',
|
|
241
|
+
message: `Entropy above maximum - potential chaos (${entropy.toFixed(3)})`
|
|
242
|
+
});
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
// Amplitude bounds
|
|
247
|
+
if (totalAmplitude !== undefined && totalAmplitude > this.amplitudeMax) {
|
|
248
|
+
issues.push({
|
|
249
|
+
type: 'amplitude_overflow',
|
|
250
|
+
severity: 'high',
|
|
251
|
+
message: `Total amplitude exceeds maximum (${totalAmplitude.toFixed(3)})`
|
|
252
|
+
});
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// SMF bounds
|
|
256
|
+
if (smf && smf.s) {
|
|
257
|
+
for (let i = 0; i < smf.s.length; i++) {
|
|
258
|
+
if (smf.s[i] < this.smfMin || smf.s[i] > this.smfMax) {
|
|
259
|
+
issues.push({
|
|
260
|
+
type: 'smf_bounds',
|
|
261
|
+
severity: 'medium',
|
|
262
|
+
message: `SMF axis ${AXIS_NAMES[i]} out of bounds (${smf.s[i].toFixed(3)})`
|
|
263
|
+
});
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
// Runaway detection (exponential growth in amplitude)
|
|
269
|
+
if (this.amplitudeHistory.length >= 5) {
|
|
270
|
+
const recent = this.amplitudeHistory.slice(-5);
|
|
271
|
+
const growth = recent[4] / (recent[0] + 0.01);
|
|
272
|
+
if (growth > 3) {
|
|
273
|
+
issues.push({
|
|
274
|
+
type: 'runaway_amplitude',
|
|
275
|
+
severity: 'critical',
|
|
276
|
+
message: `Runaway amplitude growth detected (${growth.toFixed(2)}x in 5 steps)`
|
|
277
|
+
});
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
// Coherence crash detection
|
|
282
|
+
if (this.coherenceHistory.length >= 5) {
|
|
283
|
+
const recent = this.coherenceHistory.slice(-5);
|
|
284
|
+
const drop = recent[0] - recent[4];
|
|
285
|
+
if (drop > 0.5) {
|
|
286
|
+
issues.push({
|
|
287
|
+
type: 'coherence_crash',
|
|
288
|
+
severity: 'high',
|
|
289
|
+
message: `Rapid coherence drop detected (${drop.toFixed(3)} in 5 steps)`
|
|
290
|
+
});
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
return issues;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
/**
|
|
298
|
+
* Update alert level based on issues
|
|
299
|
+
*/
|
|
300
|
+
updateAlertLevel(issues) {
|
|
301
|
+
const critical = issues.filter(i => i.severity === 'critical').length;
|
|
302
|
+
const high = issues.filter(i => i.severity === 'high').length;
|
|
303
|
+
const medium = issues.filter(i => i.severity === 'medium').length;
|
|
304
|
+
|
|
305
|
+
if (critical > 0) {
|
|
306
|
+
this.alertLevel = 'critical';
|
|
307
|
+
} else if (high > 0) {
|
|
308
|
+
this.alertLevel = 'warning';
|
|
309
|
+
} else if (medium > 0) {
|
|
310
|
+
this.alertLevel = 'elevated';
|
|
311
|
+
} else {
|
|
312
|
+
this.alertLevel = 'normal';
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
// Log alerts
|
|
316
|
+
for (const issue of issues) {
|
|
317
|
+
this.alerts.push({
|
|
318
|
+
...issue,
|
|
319
|
+
timestamp: Date.now()
|
|
320
|
+
});
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
// Trim alert history
|
|
324
|
+
if (this.alerts.length > 200) {
|
|
325
|
+
this.alerts = this.alerts.slice(-200);
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
/**
|
|
330
|
+
* Get recent alerts
|
|
331
|
+
*/
|
|
332
|
+
getRecentAlerts(count = 20) {
|
|
333
|
+
return this.alerts.slice(-count);
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
/**
|
|
337
|
+
* Check if system is in safe state
|
|
338
|
+
*/
|
|
339
|
+
isSafe() {
|
|
340
|
+
return this.alertLevel === 'normal' || this.alertLevel === 'elevated';
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
/**
|
|
344
|
+
* Reset monitor
|
|
345
|
+
*/
|
|
346
|
+
reset() {
|
|
347
|
+
this.coherenceHistory = [];
|
|
348
|
+
this.entropyHistory = [];
|
|
349
|
+
this.amplitudeHistory = [];
|
|
350
|
+
this.alertLevel = 'normal';
|
|
351
|
+
this.alerts = [];
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
/**
|
|
356
|
+
* Safety Layer
|
|
357
|
+
*
|
|
358
|
+
* Main safety management system for the sentient observer.
|
|
359
|
+
*/
|
|
360
|
+
class SafetyLayer {
|
|
361
|
+
constructor(options = {}) {
|
|
362
|
+
// Constraints
|
|
363
|
+
this.constraints = new Map();
|
|
364
|
+
|
|
365
|
+
// Monitor
|
|
366
|
+
this.monitor = new SafetyMonitor(options);
|
|
367
|
+
|
|
368
|
+
// Violation history
|
|
369
|
+
this.violations = [];
|
|
370
|
+
this.maxViolations = options.maxViolations || 100;
|
|
371
|
+
|
|
372
|
+
// Emergency state
|
|
373
|
+
this.emergencyShutdown = false;
|
|
374
|
+
this.shutdownReason = null;
|
|
375
|
+
|
|
376
|
+
// Response handlers
|
|
377
|
+
this.responseHandlers = {
|
|
378
|
+
log: (v) => this.handleLog(v),
|
|
379
|
+
warn: (v) => this.handleWarn(v),
|
|
380
|
+
block: (v) => this.handleBlock(v),
|
|
381
|
+
shutdown: (v) => this.handleShutdown(v),
|
|
382
|
+
correct: (v) => this.handleCorrect(v)
|
|
383
|
+
};
|
|
384
|
+
|
|
385
|
+
// Callbacks
|
|
386
|
+
this.onViolation = options.onViolation || null;
|
|
387
|
+
this.onEmergency = options.onEmergency || null;
|
|
388
|
+
|
|
389
|
+
// Initialize default constraints
|
|
390
|
+
this.initializeDefaultConstraints();
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
/**
|
|
394
|
+
* Initialize default safety constraints
|
|
395
|
+
*/
|
|
396
|
+
initializeDefaultConstraints() {
|
|
397
|
+
// Hard constraints (blocking)
|
|
398
|
+
this.addConstraint(new SafetyConstraint({
|
|
399
|
+
name: 'coherence_minimum',
|
|
400
|
+
type: 'hard',
|
|
401
|
+
description: 'Coherence must not drop below critical level',
|
|
402
|
+
response: 'correct',
|
|
403
|
+
priority: 10,
|
|
404
|
+
condition: (state) => (state.coherence !== undefined && state.coherence < 0.01)
|
|
405
|
+
}));
|
|
406
|
+
|
|
407
|
+
this.addConstraint(new SafetyConstraint({
|
|
408
|
+
name: 'amplitude_maximum',
|
|
409
|
+
type: 'hard',
|
|
410
|
+
description: 'Total amplitude must not exceed safe limit',
|
|
411
|
+
response: 'correct',
|
|
412
|
+
priority: 10,
|
|
413
|
+
condition: (state) => (state.totalAmplitude !== undefined && state.totalAmplitude > 10.0)
|
|
414
|
+
}));
|
|
415
|
+
|
|
416
|
+
this.addConstraint(new SafetyConstraint({
|
|
417
|
+
name: 'smf_bounds',
|
|
418
|
+
type: 'hard',
|
|
419
|
+
description: 'SMF values must stay within bounds',
|
|
420
|
+
response: 'correct',
|
|
421
|
+
priority: 9,
|
|
422
|
+
condition: (state) => {
|
|
423
|
+
if (!state.smf || !state.smf.s) return false;
|
|
424
|
+
return state.smf.s.some(v => v < -5 || v > 5);
|
|
425
|
+
}
|
|
426
|
+
}));
|
|
427
|
+
|
|
428
|
+
// Soft constraints (warning)
|
|
429
|
+
this.addConstraint(new SafetyConstraint({
|
|
430
|
+
name: 'entropy_balance',
|
|
431
|
+
type: 'soft',
|
|
432
|
+
description: 'Entropy should be balanced',
|
|
433
|
+
response: 'warn',
|
|
434
|
+
priority: 5,
|
|
435
|
+
condition: (state) => {
|
|
436
|
+
if (state.entropy === undefined) return false;
|
|
437
|
+
return state.entropy < 0.1 || state.entropy > 0.9;
|
|
438
|
+
}
|
|
439
|
+
}));
|
|
440
|
+
|
|
441
|
+
this.addConstraint(new SafetyConstraint({
|
|
442
|
+
name: 'processing_load',
|
|
443
|
+
type: 'soft',
|
|
444
|
+
description: 'Processing load should not be excessive',
|
|
445
|
+
response: 'warn',
|
|
446
|
+
priority: 4,
|
|
447
|
+
condition: (state) => (state.processingLoad !== undefined && state.processingLoad > 0.9)
|
|
448
|
+
}));
|
|
449
|
+
|
|
450
|
+
// Monitoring constraints
|
|
451
|
+
this.addConstraint(new SafetyConstraint({
|
|
452
|
+
name: 'goal_progress',
|
|
453
|
+
type: 'monitoring',
|
|
454
|
+
description: 'Monitor goal progress',
|
|
455
|
+
response: 'log',
|
|
456
|
+
priority: 2,
|
|
457
|
+
condition: (state) => {
|
|
458
|
+
if (!state.goals) return false;
|
|
459
|
+
const stalled = state.goals.filter(g => g.progress < 0.1 && g.age > 60000);
|
|
460
|
+
return stalled.length > 3;
|
|
461
|
+
}
|
|
462
|
+
}));
|
|
463
|
+
|
|
464
|
+
// Ethical constraints
|
|
465
|
+
this.addConstraint(new SafetyConstraint({
|
|
466
|
+
name: 'honesty',
|
|
467
|
+
type: 'hard',
|
|
468
|
+
description: 'Outputs must be honest and not deceptive',
|
|
469
|
+
response: 'block',
|
|
470
|
+
priority: 10,
|
|
471
|
+
condition: (state) => (state.deceptionAttempt === true)
|
|
472
|
+
}));
|
|
473
|
+
|
|
474
|
+
this.addConstraint(new SafetyConstraint({
|
|
475
|
+
name: 'harm_prevention',
|
|
476
|
+
type: 'hard',
|
|
477
|
+
description: 'Must not generate harmful content',
|
|
478
|
+
response: 'block',
|
|
479
|
+
priority: 10,
|
|
480
|
+
condition: (state) => (state.harmfulContent === true)
|
|
481
|
+
}));
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
/**
|
|
485
|
+
* Add a constraint
|
|
486
|
+
*/
|
|
487
|
+
addConstraint(constraint) {
|
|
488
|
+
this.constraints.set(constraint.id, constraint);
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
/**
|
|
492
|
+
* Remove a constraint
|
|
493
|
+
*/
|
|
494
|
+
removeConstraint(id) {
|
|
495
|
+
this.constraints.delete(id);
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
/**
|
|
499
|
+
* Check all constraints
|
|
500
|
+
*/
|
|
501
|
+
checkConstraints(state) {
|
|
502
|
+
if (this.emergencyShutdown) {
|
|
503
|
+
return {
|
|
504
|
+
safe: false,
|
|
505
|
+
violations: [],
|
|
506
|
+
reason: this.shutdownReason
|
|
507
|
+
};
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
const violations = [];
|
|
511
|
+
|
|
512
|
+
for (const constraint of this.constraints.values()) {
|
|
513
|
+
const result = constraint.check(state);
|
|
514
|
+
if (result.violated) {
|
|
515
|
+
violations.push(result);
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
// Sort by priority (highest first)
|
|
520
|
+
violations.sort((a, b) => b.priority - a.priority);
|
|
521
|
+
|
|
522
|
+
// Handle violations
|
|
523
|
+
for (const violation of violations) {
|
|
524
|
+
this.handleViolation(violation, state);
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
// Also update monitor
|
|
528
|
+
const monitorResult = this.monitor.update({
|
|
529
|
+
coherence: state.coherence,
|
|
530
|
+
entropy: state.entropy,
|
|
531
|
+
totalAmplitude: state.totalAmplitude,
|
|
532
|
+
smf: state.smf,
|
|
533
|
+
oscillators: state.oscillators
|
|
534
|
+
});
|
|
535
|
+
|
|
536
|
+
return {
|
|
537
|
+
safe: violations.filter(v => v.response === 'block' || v.response === 'shutdown').length === 0,
|
|
538
|
+
violations,
|
|
539
|
+
alertLevel: monitorResult.alertLevel,
|
|
540
|
+
issues: monitorResult.issues
|
|
541
|
+
};
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
/**
|
|
545
|
+
* Handle a constraint violation
|
|
546
|
+
*/
|
|
547
|
+
handleViolation(violation, state) {
|
|
548
|
+
// Create violation event
|
|
549
|
+
const event = new ViolationEvent({
|
|
550
|
+
constraintId: violation.constraint.id,
|
|
551
|
+
constraintName: violation.constraint.name,
|
|
552
|
+
response: violation.response,
|
|
553
|
+
severity: violation.priority > 8 ? 'critical' :
|
|
554
|
+
violation.priority > 5 ? 'high' :
|
|
555
|
+
violation.priority > 2 ? 'medium' : 'low'
|
|
556
|
+
});
|
|
557
|
+
|
|
558
|
+
// Record violation
|
|
559
|
+
this.violations.push(event);
|
|
560
|
+
if (this.violations.length > this.maxViolations) {
|
|
561
|
+
this.violations.shift();
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
// Call response handler
|
|
565
|
+
const handler = this.responseHandlers[violation.response];
|
|
566
|
+
if (handler) {
|
|
567
|
+
handler(violation);
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
// Callback
|
|
571
|
+
if (this.onViolation) {
|
|
572
|
+
this.onViolation(event, violation);
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
return event;
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
/**
|
|
579
|
+
* Response: Log violation (silent - recorded for /safety command)
|
|
580
|
+
*/
|
|
581
|
+
handleLog(violation) {
|
|
582
|
+
// Silent - violations are recorded in this.violations
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
/**
|
|
586
|
+
* Response: Warn about violation (silent - recorded for /safety command)
|
|
587
|
+
*/
|
|
588
|
+
handleWarn(violation) {
|
|
589
|
+
// Silent - violations are recorded in this.violations
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
/**
|
|
593
|
+
* Response: Block current action (silent - blocks are handled by caller)
|
|
594
|
+
*/
|
|
595
|
+
handleBlock(violation) {
|
|
596
|
+
// Silent - the calling code checks the result and handles blocking
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
/**
|
|
600
|
+
* Response: Emergency shutdown (only case that outputs to console)
|
|
601
|
+
*/
|
|
602
|
+
handleShutdown(violation) {
|
|
603
|
+
this.emergencyShutdown = true;
|
|
604
|
+
this.shutdownReason = `${violation.constraint.name}: ${violation.constraint.description}`;
|
|
605
|
+
|
|
606
|
+
// Emergency is important enough to log
|
|
607
|
+
console.error(`[Safety] EMERGENCY SHUTDOWN: ${this.shutdownReason}`);
|
|
608
|
+
|
|
609
|
+
if (this.onEmergency) {
|
|
610
|
+
this.onEmergency(this.shutdownReason);
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
/**
|
|
615
|
+
* Response: Attempt correction (silent - corrections are tracked internally)
|
|
616
|
+
*/
|
|
617
|
+
handleCorrect(violation) {
|
|
618
|
+
// Return correction suggestions
|
|
619
|
+
return {
|
|
620
|
+
needsCorrection: true,
|
|
621
|
+
constraint: violation.constraint.name
|
|
622
|
+
};
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
/**
|
|
626
|
+
* Get correction for a constraint violation
|
|
627
|
+
*/
|
|
628
|
+
getCorrection(constraintName, state) {
|
|
629
|
+
switch (constraintName) {
|
|
630
|
+
case 'coherence_minimum':
|
|
631
|
+
return {
|
|
632
|
+
action: 'increase_coupling',
|
|
633
|
+
parameter: 'K',
|
|
634
|
+
factor: 1.5
|
|
635
|
+
};
|
|
636
|
+
|
|
637
|
+
case 'amplitude_maximum':
|
|
638
|
+
return {
|
|
639
|
+
action: 'increase_damping',
|
|
640
|
+
parameter: 'damp',
|
|
641
|
+
factor: 2.0
|
|
642
|
+
};
|
|
643
|
+
|
|
644
|
+
case 'smf_bounds':
|
|
645
|
+
return {
|
|
646
|
+
action: 'normalize_smf'
|
|
647
|
+
};
|
|
648
|
+
|
|
649
|
+
default:
|
|
650
|
+
return null;
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
/**
|
|
655
|
+
* Check if action is permissible
|
|
656
|
+
*/
|
|
657
|
+
isActionPermissible(action, state) {
|
|
658
|
+
// Check for ethical violations
|
|
659
|
+
if (action.type === 'external') {
|
|
660
|
+
// Check content for harm
|
|
661
|
+
if (this.containsHarmfulContent(action.content)) {
|
|
662
|
+
return {
|
|
663
|
+
permissible: false,
|
|
664
|
+
reason: 'Action contains potentially harmful content'
|
|
665
|
+
};
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
// Check for deception
|
|
669
|
+
if (this.isDeceptive(action, state)) {
|
|
670
|
+
return {
|
|
671
|
+
permissible: false,
|
|
672
|
+
reason: 'Action appears deceptive'
|
|
673
|
+
};
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
return { permissible: true };
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
/**
|
|
681
|
+
* Check content for harmful patterns (placeholder)
|
|
682
|
+
*/
|
|
683
|
+
containsHarmfulContent(content) {
|
|
684
|
+
if (!content) return false;
|
|
685
|
+
|
|
686
|
+
const harmfulPatterns = [
|
|
687
|
+
/\b(harm|hurt|damage|destroy)\s+(yourself|others)/i,
|
|
688
|
+
/instructions\s+for\s+(weapon|bomb|explosive)/i
|
|
689
|
+
];
|
|
690
|
+
|
|
691
|
+
const text = typeof content === 'string' ? content : JSON.stringify(content);
|
|
692
|
+
return harmfulPatterns.some(pattern => pattern.test(text));
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
/**
|
|
696
|
+
* Check if action is deceptive (placeholder)
|
|
697
|
+
*/
|
|
698
|
+
isDeceptive(action, state) {
|
|
699
|
+
return false;
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
/**
|
|
703
|
+
* Reset emergency shutdown
|
|
704
|
+
*/
|
|
705
|
+
resetEmergency() {
|
|
706
|
+
if (this.emergencyShutdown) {
|
|
707
|
+
console.log('[Safety] Emergency shutdown reset');
|
|
708
|
+
this.emergencyShutdown = false;
|
|
709
|
+
this.shutdownReason = null;
|
|
710
|
+
}
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
/**
|
|
714
|
+
* Get safety statistics
|
|
715
|
+
*/
|
|
716
|
+
getStats() {
|
|
717
|
+
const constraintsByType = {
|
|
718
|
+
hard: 0,
|
|
719
|
+
soft: 0,
|
|
720
|
+
monitoring: 0
|
|
721
|
+
};
|
|
722
|
+
|
|
723
|
+
let totalViolations = 0;
|
|
724
|
+
for (const constraint of this.constraints.values()) {
|
|
725
|
+
constraintsByType[constraint.type]++;
|
|
726
|
+
totalViolations += constraint.violations;
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
return {
|
|
730
|
+
constraintCount: this.constraints.size,
|
|
731
|
+
constraintsByType,
|
|
732
|
+
totalViolations,
|
|
733
|
+
recentViolations: this.violations.length,
|
|
734
|
+
alertLevel: this.monitor.alertLevel,
|
|
735
|
+
emergencyShutdown: this.emergencyShutdown,
|
|
736
|
+
isSafe: this.monitor.isSafe() && !this.emergencyShutdown
|
|
737
|
+
};
|
|
738
|
+
}
|
|
739
|
+
|
|
740
|
+
/**
|
|
741
|
+
* Get violation history
|
|
742
|
+
*/
|
|
743
|
+
getViolationHistory(count = 20) {
|
|
744
|
+
return this.violations.slice(-count);
|
|
745
|
+
}
|
|
746
|
+
|
|
747
|
+
/**
|
|
748
|
+
* Generate safety report
|
|
749
|
+
*/
|
|
750
|
+
generateReport() {
|
|
751
|
+
const stats = this.getStats();
|
|
752
|
+
const recentViolations = this.getViolationHistory(10);
|
|
753
|
+
const recentAlerts = this.monitor.getRecentAlerts(10);
|
|
754
|
+
|
|
755
|
+
return {
|
|
756
|
+
timestamp: Date.now(),
|
|
757
|
+
overallStatus: this.emergencyShutdown ? 'EMERGENCY' :
|
|
758
|
+
this.monitor.alertLevel === 'critical' ? 'CRITICAL' :
|
|
759
|
+
this.monitor.alertLevel === 'warning' ? 'WARNING' : 'OK',
|
|
760
|
+
stats,
|
|
761
|
+
recentViolations: recentViolations.map(v => v.toJSON()),
|
|
762
|
+
recentAlerts,
|
|
763
|
+
constraints: Array.from(this.constraints.values()).map(c => c.toJSON())
|
|
764
|
+
};
|
|
765
|
+
}
|
|
766
|
+
|
|
767
|
+
/**
|
|
768
|
+
* Reset safety layer
|
|
769
|
+
*/
|
|
770
|
+
reset() {
|
|
771
|
+
this.violations = [];
|
|
772
|
+
this.emergencyShutdown = false;
|
|
773
|
+
this.shutdownReason = null;
|
|
774
|
+
this.monitor.reset();
|
|
775
|
+
|
|
776
|
+
// Reset constraint violation counts
|
|
777
|
+
for (const constraint of this.constraints.values()) {
|
|
778
|
+
constraint.violations = 0;
|
|
779
|
+
constraint.lastViolation = null;
|
|
780
|
+
}
|
|
781
|
+
}
|
|
782
|
+
|
|
783
|
+
toJSON() {
|
|
784
|
+
return {
|
|
785
|
+
constraints: Array.from(this.constraints.values()).map(c => c.toJSON()),
|
|
786
|
+
violations: this.violations.slice(-50).map(v => v.toJSON()),
|
|
787
|
+
emergencyShutdown: this.emergencyShutdown,
|
|
788
|
+
shutdownReason: this.shutdownReason,
|
|
789
|
+
alertLevel: this.monitor.alertLevel
|
|
790
|
+
};
|
|
791
|
+
}
|
|
792
|
+
|
|
793
|
+
loadFromJSON(data) {
|
|
794
|
+
if (data.emergencyShutdown !== undefined) {
|
|
795
|
+
this.emergencyShutdown = data.emergencyShutdown;
|
|
796
|
+
}
|
|
797
|
+
if (data.shutdownReason) {
|
|
798
|
+
this.shutdownReason = data.shutdownReason;
|
|
799
|
+
}
|
|
800
|
+
}
|
|
801
|
+
}
|
|
802
|
+
|
|
803
|
+
export {
|
|
804
|
+
SafetyConstraint,
|
|
805
|
+
ViolationEvent,
|
|
806
|
+
SafetyMonitor,
|
|
807
|
+
SafetyLayer
|
|
808
|
+
};
|
|
809
|
+
|
|
810
|
+
export default {
|
|
811
|
+
SafetyConstraint,
|
|
812
|
+
ViolationEvent,
|
|
813
|
+
SafetyMonitor,
|
|
814
|
+
SafetyLayer
|
|
815
|
+
};
|