gridstamp 1.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/.cursorrules +74 -0
- package/CLAUDE.md +61 -0
- package/LICENSE +190 -0
- package/README.md +107 -0
- package/dist/index.js +194 -0
- package/package.json +84 -0
- package/src/antispoofing/detector.ts +509 -0
- package/src/antispoofing/index.ts +7 -0
- package/src/gamification/badges.ts +429 -0
- package/src/gamification/fleet-leaderboard.ts +293 -0
- package/src/gamification/index.ts +44 -0
- package/src/gamification/streaks.ts +243 -0
- package/src/gamification/trust-tiers.ts +393 -0
- package/src/gamification/zone-mastery.ts +256 -0
- package/src/index.ts +341 -0
- package/src/memory/index.ts +9 -0
- package/src/memory/place-cells.ts +279 -0
- package/src/memory/spatial-memory.ts +375 -0
- package/src/navigation/index.ts +1 -0
- package/src/navigation/pathfinding.ts +403 -0
- package/src/perception/camera.ts +249 -0
- package/src/perception/index.ts +2 -0
- package/src/types/index.ts +416 -0
- package/src/utils/crypto.ts +94 -0
- package/src/utils/index.ts +2 -0
- package/src/utils/math.ts +204 -0
- package/src/verification/index.ts +9 -0
- package/src/verification/spatial-proof.ts +442 -0
- package/tests/antispoofing/detector.test.ts +196 -0
- package/tests/gamification/badges.test.ts +163 -0
- package/tests/gamification/fleet-leaderboard.test.ts +181 -0
- package/tests/gamification/streaks.test.ts +158 -0
- package/tests/gamification/trust-tiers.test.ts +165 -0
- package/tests/gamification/zone-mastery.test.ts +143 -0
- package/tests/memory/place-cells.test.ts +128 -0
- package/tests/stress/load.test.ts +499 -0
- package/tests/stress/security.test.ts +378 -0
- package/tests/stress/simulation.test.ts +361 -0
- package/tests/utils/crypto.test.ts +115 -0
- package/tests/utils/math.test.ts +195 -0
- package/tests/verification/spatial-proof.test.ts +299 -0
- package/tsconfig.json +26 -0
|
@@ -0,0 +1,499 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Production Stress Tests — Load, concurrency, edge cases, overflow
|
|
3
|
+
*
|
|
4
|
+
* These simulate real fleet operations:
|
|
5
|
+
* - 1000 robots registering and operating simultaneously
|
|
6
|
+
* - Rapid-fire verification cycles
|
|
7
|
+
* - Memory pressure under sustained load
|
|
8
|
+
* - Boundary conditions that break naive implementations
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { describe, it, expect } from 'vitest';
|
|
12
|
+
import {
|
|
13
|
+
TrustTierSystem,
|
|
14
|
+
TrustTier,
|
|
15
|
+
TIER_CONFIGS,
|
|
16
|
+
BadgeSystem,
|
|
17
|
+
StreakSystem,
|
|
18
|
+
ZoneMasterySystem,
|
|
19
|
+
FleetLeaderboard,
|
|
20
|
+
LeaderboardMetric,
|
|
21
|
+
type RobotMetrics,
|
|
22
|
+
type RobotStats,
|
|
23
|
+
} from '../../src/gamification/index.js';
|
|
24
|
+
import {
|
|
25
|
+
computeSSIM,
|
|
26
|
+
rgbToGrayscale,
|
|
27
|
+
approximateLPIPS,
|
|
28
|
+
generateSpatialProof,
|
|
29
|
+
verifySpatialProofIntegrity,
|
|
30
|
+
createSettlement,
|
|
31
|
+
} from '../../src/verification/spatial-proof.js';
|
|
32
|
+
import {
|
|
33
|
+
ReplayDetector,
|
|
34
|
+
FrameIntegrityChecker,
|
|
35
|
+
CanarySystem,
|
|
36
|
+
} from '../../src/antispoofing/detector.js';
|
|
37
|
+
import { signFrame, generateNonce, hmacSign, deriveKey } from '../../src/utils/crypto.js';
|
|
38
|
+
import { PlaceCellPopulation, GridCellSystem, computeSpatialCode } from '../../src/memory/place-cells.js';
|
|
39
|
+
import { ShortTermMemory } from '../../src/memory/spatial-memory.js';
|
|
40
|
+
import type { CameraFrame, Pose, RenderedView } from '../../src/types/index.js';
|
|
41
|
+
|
|
42
|
+
const SECRET = 'a]9#kL2$mP7xQ4vB8nR1wF5yH3jT6dG0'.slice(0, 32);
|
|
43
|
+
|
|
44
|
+
function makeTestPose(x: number, y: number): Pose {
|
|
45
|
+
return {
|
|
46
|
+
position: { x, y, z: 0 },
|
|
47
|
+
orientation: { w: 1, x: 0, y: 0, z: 0 },
|
|
48
|
+
timestamp: Date.now(),
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function makeTestFrame(w: number, h: number, seed: number, seq: number): CameraFrame {
|
|
53
|
+
const rgb = new Uint8Array(w * h * 3);
|
|
54
|
+
for (let i = 0; i < rgb.length; i++) rgb[i] = (i * 17 + seed * 31) % 256;
|
|
55
|
+
const depth = new Float32Array(w * h);
|
|
56
|
+
for (let i = 0; i < depth.length; i++) depth[i] = 1 + (seed % 5);
|
|
57
|
+
const ts = Date.now();
|
|
58
|
+
return {
|
|
59
|
+
id: generateNonce(8),
|
|
60
|
+
timestamp: ts,
|
|
61
|
+
rgb, width: w, height: h, depth,
|
|
62
|
+
pose: makeTestPose(seed, seed),
|
|
63
|
+
hmac: signFrame(rgb, ts, seq, SECRET),
|
|
64
|
+
sequenceNumber: seq,
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function makeRender(w: number, h: number, seed: number): RenderedView {
|
|
69
|
+
const rgb = new Uint8Array(w * h * 3);
|
|
70
|
+
for (let i = 0; i < rgb.length; i++) rgb[i] = (i * 17 + seed * 31) % 256;
|
|
71
|
+
const depth = new Float32Array(w * h);
|
|
72
|
+
for (let i = 0; i < depth.length; i++) depth[i] = 1 + (seed % 5);
|
|
73
|
+
return { rgb, depth, width: w, height: h, pose: makeTestPose(seed, seed), renderTimeMs: 1 };
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// ============================================================
|
|
77
|
+
// LOAD TESTS
|
|
78
|
+
// ============================================================
|
|
79
|
+
|
|
80
|
+
describe('Load: Trust Tier System', () => {
|
|
81
|
+
it('handles 1000 robot registrations', () => {
|
|
82
|
+
const system = new TrustTierSystem(SECRET);
|
|
83
|
+
const start = performance.now();
|
|
84
|
+
for (let i = 0; i < 1000; i++) {
|
|
85
|
+
system.register(`robot-${i}`);
|
|
86
|
+
}
|
|
87
|
+
const elapsed = performance.now() - start;
|
|
88
|
+
expect(system.robotCount).toBe(1000);
|
|
89
|
+
expect(elapsed).toBeLessThan(1000); // under 1 second
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
it('handles 10,000 success recordings across 100 robots', () => {
|
|
93
|
+
const system = new TrustTierSystem(SECRET);
|
|
94
|
+
for (let i = 0; i < 100; i++) system.register(`r-${i}`);
|
|
95
|
+
const start = performance.now();
|
|
96
|
+
for (let round = 0; round < 100; round++) {
|
|
97
|
+
for (let i = 0; i < 100; i++) {
|
|
98
|
+
system.recordSuccess(`r-${i}`, 10);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
const elapsed = performance.now() - start;
|
|
102
|
+
expect(elapsed).toBeLessThan(5000); // under 5 seconds for 10K ops
|
|
103
|
+
// All robots should have progressed past Untrusted
|
|
104
|
+
for (let i = 0; i < 100; i++) {
|
|
105
|
+
const profile = system.getProfile(`r-${i}`)!;
|
|
106
|
+
expect(profile.points).toBe(1000);
|
|
107
|
+
expect(profile.currentTier).toBeGreaterThan(TrustTier.UNTRUSTED);
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
it('history chain integrity holds under volume', () => {
|
|
112
|
+
const system = new TrustTierSystem(SECRET);
|
|
113
|
+
system.register('heavy-robot');
|
|
114
|
+
// Generate enough activity to trigger multiple promotions
|
|
115
|
+
for (let i = 0; i < 500; i++) system.recordSuccess('heavy-robot', 20);
|
|
116
|
+
const result = system.verifyHistory('heavy-robot');
|
|
117
|
+
expect(result.valid).toBe(true);
|
|
118
|
+
const profile = system.getProfile('heavy-robot')!;
|
|
119
|
+
expect(profile.history.length).toBeGreaterThan(0);
|
|
120
|
+
// Every single event in history must be signed
|
|
121
|
+
for (const event of profile.history) {
|
|
122
|
+
expect(event.signature).toHaveLength(64);
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
it('tier progression is monotonically correct under load', () => {
|
|
127
|
+
const system = new TrustTierSystem(SECRET);
|
|
128
|
+
system.register('climber');
|
|
129
|
+
let lastTier = TrustTier.UNTRUSTED;
|
|
130
|
+
for (let i = 0; i < 1000; i++) {
|
|
131
|
+
system.recordSuccess('climber', 10);
|
|
132
|
+
const profile = system.getProfile('climber')!;
|
|
133
|
+
// Tier should never decrease during pure success run
|
|
134
|
+
expect(profile.currentTier).toBeGreaterThanOrEqual(lastTier);
|
|
135
|
+
lastTier = profile.currentTier;
|
|
136
|
+
}
|
|
137
|
+
expect(lastTier).toBeGreaterThanOrEqual(TrustTier.ELITE);
|
|
138
|
+
});
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
describe('Load: Badge System', () => {
|
|
142
|
+
it('evaluates badges for 500 robots efficiently', () => {
|
|
143
|
+
const system = new BadgeSystem(SECRET);
|
|
144
|
+
const start = performance.now();
|
|
145
|
+
for (let i = 0; i < 500; i++) {
|
|
146
|
+
const metrics: RobotMetrics = {
|
|
147
|
+
successful_verifications: 100 + i,
|
|
148
|
+
spoofing_incidents: 0,
|
|
149
|
+
threats_detected: i % 20,
|
|
150
|
+
zones_mapped: 5 + (i % 30),
|
|
151
|
+
max_zone_mastery: 0.3 + (i % 70) / 100,
|
|
152
|
+
unique_routes: 10 + i,
|
|
153
|
+
consecutive_days: 7 + (i % 60),
|
|
154
|
+
night_operations: i % 80,
|
|
155
|
+
total_verifications: 110 + i,
|
|
156
|
+
success_rate: 90 + (i % 10),
|
|
157
|
+
max_ssim: 0.85 + (i % 15) / 100,
|
|
158
|
+
max_zones_per_trip: 1 + (i % 5),
|
|
159
|
+
fast_operations: i % 20,
|
|
160
|
+
};
|
|
161
|
+
system.evaluate(`robot-${i}`, metrics);
|
|
162
|
+
}
|
|
163
|
+
const elapsed = performance.now() - start;
|
|
164
|
+
expect(elapsed).toBeLessThan(3000);
|
|
165
|
+
// Spot check: first robot should have multiple badges
|
|
166
|
+
expect(system.getBadgeCount('robot-0')).toBeGreaterThan(3);
|
|
167
|
+
// All badges should be signed
|
|
168
|
+
const badges = system.getBadges('robot-0');
|
|
169
|
+
for (const badge of badges) {
|
|
170
|
+
expect(badge.signature).toHaveLength(64);
|
|
171
|
+
}
|
|
172
|
+
});
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
describe('Load: Streak System', () => {
|
|
176
|
+
it('simulates 365-day streak for 100 robots', () => {
|
|
177
|
+
const system = new StreakSystem(SECRET);
|
|
178
|
+
for (let i = 0; i < 100; i++) system.register(`r-${i}`);
|
|
179
|
+
const baseDate = new Date('2025-01-01T12:00:00Z').getTime();
|
|
180
|
+
const start = performance.now();
|
|
181
|
+
for (let day = 0; day < 365; day++) {
|
|
182
|
+
const ts = baseDate + day * 86400000;
|
|
183
|
+
for (let i = 0; i < 100; i++) {
|
|
184
|
+
system.recordActivity(`r-${i}`, 100, ts);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
const elapsed = performance.now() - start;
|
|
188
|
+
expect(elapsed).toBeLessThan(5000); // 36,500 operations under 5s
|
|
189
|
+
// Every robot should have 365-day streak
|
|
190
|
+
for (let i = 0; i < 100; i++) {
|
|
191
|
+
const record = system.getRecord(`r-${i}`)!;
|
|
192
|
+
expect(record.currentStreak).toBe(365);
|
|
193
|
+
expect(record.longestStreak).toBe(365);
|
|
194
|
+
}
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
it('multiplier stays bounded even at extreme streaks', () => {
|
|
198
|
+
const system = new StreakSystem(SECRET);
|
|
199
|
+
expect(system.calculateMultiplier(0)).toBe(1.0);
|
|
200
|
+
expect(system.calculateMultiplier(10)).toBe(2.0); // capped
|
|
201
|
+
expect(system.calculateMultiplier(100)).toBe(2.0);
|
|
202
|
+
expect(system.calculateMultiplier(10000)).toBe(2.0);
|
|
203
|
+
expect(system.calculateMultiplier(Number.MAX_SAFE_INTEGER)).toBe(2.0);
|
|
204
|
+
});
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
describe('Load: Zone Mastery', () => {
|
|
208
|
+
it('handles 50 zones with 200 robots visiting', () => {
|
|
209
|
+
const system = new ZoneMasterySystem(SECRET, 2.0);
|
|
210
|
+
// Create 50 zones
|
|
211
|
+
const zoneIds: string[] = [];
|
|
212
|
+
for (let z = 0; z < 50; z++) {
|
|
213
|
+
const zone = system.defineZone(`Zone-${z}`, {
|
|
214
|
+
min: { x: z * 100, y: 0, z: 0 },
|
|
215
|
+
max: { x: z * 100 + 50, y: 50, z: 5 },
|
|
216
|
+
});
|
|
217
|
+
zoneIds.push(zone.id);
|
|
218
|
+
}
|
|
219
|
+
expect(system.totalZones).toBe(50);
|
|
220
|
+
|
|
221
|
+
// 200 robots each visit 5 random zones
|
|
222
|
+
const start = performance.now();
|
|
223
|
+
for (let r = 0; r < 200; r++) {
|
|
224
|
+
for (let v = 0; v < 5; v++) {
|
|
225
|
+
const z = (r + v) % 50;
|
|
226
|
+
system.recordVisit(
|
|
227
|
+
`robot-${r}`,
|
|
228
|
+
{ x: z * 100 + 25, y: 25, z: 2 },
|
|
229
|
+
Math.random() > 0.1, // 90% success
|
|
230
|
+
50,
|
|
231
|
+
);
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
const elapsed = performance.now() - start;
|
|
235
|
+
expect(elapsed).toBeLessThan(3000); // 1000 visits under 3s
|
|
236
|
+
|
|
237
|
+
// Spot check mastery
|
|
238
|
+
const scores = system.getAllMastery('robot-0');
|
|
239
|
+
expect(scores.length).toBeGreaterThan(0);
|
|
240
|
+
for (const score of scores) {
|
|
241
|
+
expect(score.composite).toBeGreaterThanOrEqual(0);
|
|
242
|
+
expect(score.composite).toBeLessThanOrEqual(1);
|
|
243
|
+
expect(score.coverage).toBeGreaterThanOrEqual(0);
|
|
244
|
+
expect(score.successRate).toBeGreaterThanOrEqual(0);
|
|
245
|
+
}
|
|
246
|
+
});
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
describe('Load: Fleet Leaderboard', () => {
|
|
250
|
+
it('ranks 500 robots across 10 fleets', () => {
|
|
251
|
+
const lb = new FleetLeaderboard(SECRET);
|
|
252
|
+
for (let i = 0; i < 500; i++) {
|
|
253
|
+
lb.updateStats({
|
|
254
|
+
robotId: `robot-${i}`,
|
|
255
|
+
fleetId: `fleet-${i % 10}`,
|
|
256
|
+
trustTier: (i % 6) as TrustTier,
|
|
257
|
+
points: Math.floor(Math.random() * 10000),
|
|
258
|
+
totalVerifications: 50 + Math.floor(Math.random() * 500),
|
|
259
|
+
successfulVerifications: 45 + Math.floor(Math.random() * 450),
|
|
260
|
+
zonesExplored: Math.floor(Math.random() * 50),
|
|
261
|
+
badgeCount: Math.floor(Math.random() * 20),
|
|
262
|
+
streakDays: Math.floor(Math.random() * 100),
|
|
263
|
+
maxZoneMastery: Math.random(),
|
|
264
|
+
spoofingIncidents: Math.floor(Math.random() * 3),
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
expect(lb.totalRobots).toBe(500);
|
|
268
|
+
|
|
269
|
+
const start = performance.now();
|
|
270
|
+
// Generate leaderboards for all 10 fleets
|
|
271
|
+
for (let f = 0; f < 10; f++) {
|
|
272
|
+
const board = lb.getFleetLeaderboard(`fleet-${f}`, LeaderboardMetric.COMPOSITE, 50);
|
|
273
|
+
expect(board.length).toBeLessThanOrEqual(50);
|
|
274
|
+
// Verify descending order
|
|
275
|
+
for (let j = 1; j < board.length; j++) {
|
|
276
|
+
expect(board[j]!.score).toBeLessThanOrEqual(board[j - 1]!.score);
|
|
277
|
+
}
|
|
278
|
+
// Verify ranks are sequential
|
|
279
|
+
for (let j = 0; j < board.length; j++) {
|
|
280
|
+
expect(board[j]!.rank).toBe(j + 1);
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
// Global leaderboard
|
|
284
|
+
const global = lb.getGlobalLeaderboard(LeaderboardMetric.COMPOSITE, 100);
|
|
285
|
+
expect(global.length).toBe(100);
|
|
286
|
+
const elapsed = performance.now() - start;
|
|
287
|
+
expect(elapsed).toBeLessThan(2000);
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
it('fleet summary aggregates correctly under load', () => {
|
|
291
|
+
const lb = new FleetLeaderboard(SECRET);
|
|
292
|
+
let totalSuccess = 0;
|
|
293
|
+
let totalVerify = 0;
|
|
294
|
+
for (let i = 0; i < 100; i++) {
|
|
295
|
+
const sv = 80 + (i % 20);
|
|
296
|
+
const tv = 100;
|
|
297
|
+
totalSuccess += sv;
|
|
298
|
+
totalVerify += tv;
|
|
299
|
+
lb.updateStats({
|
|
300
|
+
robotId: `r-${i}`,
|
|
301
|
+
fleetId: 'mega-fleet',
|
|
302
|
+
trustTier: TrustTier.VERIFIED,
|
|
303
|
+
points: 500,
|
|
304
|
+
totalVerifications: tv,
|
|
305
|
+
successfulVerifications: sv,
|
|
306
|
+
zonesExplored: 5,
|
|
307
|
+
badgeCount: 3,
|
|
308
|
+
streakDays: 10,
|
|
309
|
+
maxZoneMastery: 0.5,
|
|
310
|
+
spoofingIncidents: 0,
|
|
311
|
+
});
|
|
312
|
+
}
|
|
313
|
+
const summary = lb.getFleetSummary('mega-fleet');
|
|
314
|
+
expect(summary.robotCount).toBe(100);
|
|
315
|
+
expect(summary.totalDeliveries).toBe(totalSuccess);
|
|
316
|
+
expect(summary.averageSuccessRate).toBeCloseTo(totalSuccess / totalVerify, 2);
|
|
317
|
+
});
|
|
318
|
+
});
|
|
319
|
+
|
|
320
|
+
// ============================================================
|
|
321
|
+
// VERIFICATION STRESS
|
|
322
|
+
// ============================================================
|
|
323
|
+
|
|
324
|
+
describe('Load: Spatial Verification', () => {
|
|
325
|
+
it('100 rapid spatial proofs maintain integrity', () => {
|
|
326
|
+
const proofs = [];
|
|
327
|
+
for (let i = 0; i < 100; i++) {
|
|
328
|
+
const frame = makeTestFrame(32, 32, i, i + 1);
|
|
329
|
+
const render = makeRender(32, 32, i);
|
|
330
|
+
const proof = generateSpatialProof(
|
|
331
|
+
`robot-${i}`, makeTestPose(i, i), frame, render,
|
|
332
|
+
`merkle-${i}`, [], SECRET,
|
|
333
|
+
);
|
|
334
|
+
proofs.push(proof);
|
|
335
|
+
}
|
|
336
|
+
// Every proof should have valid signature
|
|
337
|
+
for (const proof of proofs) {
|
|
338
|
+
const result = verifySpatialProofIntegrity(proof, SECRET);
|
|
339
|
+
expect(result.valid).toBe(true);
|
|
340
|
+
}
|
|
341
|
+
// Every proof with wrong secret should fail
|
|
342
|
+
for (const proof of proofs) {
|
|
343
|
+
const result = verifySpatialProofIntegrity(proof, 'b'.repeat(32));
|
|
344
|
+
expect(result.valid).toBe(false);
|
|
345
|
+
}
|
|
346
|
+
});
|
|
347
|
+
|
|
348
|
+
it('SSIM computation handles large images', () => {
|
|
349
|
+
const size = 256;
|
|
350
|
+
const img = new Uint8Array(size * size);
|
|
351
|
+
for (let i = 0; i < img.length; i++) img[i] = (i * 7) % 256;
|
|
352
|
+
const start = performance.now();
|
|
353
|
+
const ssim = computeSSIM(img, img, size, size);
|
|
354
|
+
const elapsed = performance.now() - start;
|
|
355
|
+
expect(ssim).toBeCloseTo(1.0, 2);
|
|
356
|
+
expect(elapsed).toBeLessThan(1000); // 256x256 SSIM under 1s
|
|
357
|
+
});
|
|
358
|
+
|
|
359
|
+
it('settlement atomic verify-then-pay under rapid fire', () => {
|
|
360
|
+
const settlements = [];
|
|
361
|
+
for (let i = 0; i < 50; i++) {
|
|
362
|
+
const frame = makeTestFrame(32, 32, 42, i + 1);
|
|
363
|
+
const identicalRender: RenderedView = {
|
|
364
|
+
rgb: frame.rgb, depth: frame.depth!, width: 32, height: 32,
|
|
365
|
+
pose: makeTestPose(42, 42), renderTimeMs: 1,
|
|
366
|
+
};
|
|
367
|
+
const proof = generateSpatialProof(
|
|
368
|
+
'robot-1', makeTestPose(42, 42), frame, identicalRender,
|
|
369
|
+
'merkle-root', [], SECRET,
|
|
370
|
+
);
|
|
371
|
+
if (proof.passed) {
|
|
372
|
+
const settlement = createSettlement(proof, 10.00, 'USD', `merchant-${i}`, SECRET);
|
|
373
|
+
settlements.push(settlement);
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
expect(settlements.length).toBeGreaterThan(0);
|
|
377
|
+
for (const s of settlements) {
|
|
378
|
+
expect(s.status).toBe('verified');
|
|
379
|
+
expect(s.amount).toBe(10.00);
|
|
380
|
+
}
|
|
381
|
+
});
|
|
382
|
+
});
|
|
383
|
+
|
|
384
|
+
// ============================================================
|
|
385
|
+
// ANTI-SPOOFING STRESS
|
|
386
|
+
// ============================================================
|
|
387
|
+
|
|
388
|
+
describe('Load: Anti-Spoofing', () => {
|
|
389
|
+
it('replay detector handles 1000 sequential frames', () => {
|
|
390
|
+
const detector = new ReplayDetector(30);
|
|
391
|
+
const now = Date.now();
|
|
392
|
+
let criticalCount = 0;
|
|
393
|
+
for (let i = 0; i < 1000; i++) {
|
|
394
|
+
// Embed frame index as raw bytes to guarantee unique content hashes
|
|
395
|
+
const rgb = new Uint8Array(32 * 32 * 3);
|
|
396
|
+
rgb[0] = (i >> 24) & 0xFF;
|
|
397
|
+
rgb[1] = (i >> 16) & 0xFF;
|
|
398
|
+
rgb[2] = (i >> 8) & 0xFF;
|
|
399
|
+
rgb[3] = i & 0xFF;
|
|
400
|
+
for (let j = 4; j < rgb.length; j++) rgb[j] = (j + i) & 0xFF;
|
|
401
|
+
const ts = now + i * 33;
|
|
402
|
+
const frame: CameraFrame = {
|
|
403
|
+
id: `frame-${i}`,
|
|
404
|
+
timestamp: ts,
|
|
405
|
+
rgb, width: 32, height: 32,
|
|
406
|
+
sequenceNumber: i + 1,
|
|
407
|
+
hmac: signFrame(rgb, ts, i + 1, SECRET),
|
|
408
|
+
};
|
|
409
|
+
const threats = detector.check(frame);
|
|
410
|
+
const critical = threats.filter(t => t.severity === 'critical');
|
|
411
|
+
criticalCount += critical.length;
|
|
412
|
+
}
|
|
413
|
+
// Across 1000 sequential frames, no critical replay threats
|
|
414
|
+
expect(criticalCount).toBe(0);
|
|
415
|
+
});
|
|
416
|
+
|
|
417
|
+
it('canary system scales to 100 canaries', () => {
|
|
418
|
+
const canaries = new CanarySystem(SECRET);
|
|
419
|
+
for (let i = 0; i < 100; i++) {
|
|
420
|
+
canaries.plant(`canary-${i}`, { x: i * 100, y: i * 100, z: 0 });
|
|
421
|
+
}
|
|
422
|
+
expect(canaries.count).toBe(100);
|
|
423
|
+
|
|
424
|
+
// Check activation at a canary position (within 0.5m tolerance)
|
|
425
|
+
const threats = canaries.checkForCanaryActivation([
|
|
426
|
+
{ x: 0.3, y: 0.3, z: 0 }, // within 0.5m of canary-0 at (0,0,0)
|
|
427
|
+
]);
|
|
428
|
+
expect(threats.length).toBe(1);
|
|
429
|
+
|
|
430
|
+
// Check at a position far from all canaries (canaries are at i*100, i*100)
|
|
431
|
+
// Use a position that doesn't match any canary: x=50.5 * 100 = midpoint
|
|
432
|
+
const safe = canaries.checkForCanaryActivation([
|
|
433
|
+
{ x: 99999, y: 99999, z: 0 },
|
|
434
|
+
]);
|
|
435
|
+
expect(safe).toHaveLength(0);
|
|
436
|
+
});
|
|
437
|
+
});
|
|
438
|
+
|
|
439
|
+
// ============================================================
|
|
440
|
+
// SPATIAL MEMORY STRESS
|
|
441
|
+
// ============================================================
|
|
442
|
+
|
|
443
|
+
describe('Load: Place Cell Population', () => {
|
|
444
|
+
it('covers large region with place cells', () => {
|
|
445
|
+
const pop = new PlaceCellPopulation(2.0);
|
|
446
|
+
const count = pop.coverRegion(
|
|
447
|
+
{ x: 0, y: 0, z: 0 },
|
|
448
|
+
{ x: 100, y: 100, z: 0 },
|
|
449
|
+
3.0,
|
|
450
|
+
);
|
|
451
|
+
expect(count).toBeGreaterThan(100);
|
|
452
|
+
|
|
453
|
+
// Activations should work at any point
|
|
454
|
+
const start = performance.now();
|
|
455
|
+
for (let i = 0; i < 1000; i++) {
|
|
456
|
+
const activations = pop.getActivations({
|
|
457
|
+
x: Math.random() * 100,
|
|
458
|
+
y: Math.random() * 100,
|
|
459
|
+
z: 0,
|
|
460
|
+
});
|
|
461
|
+
expect(activations.size).toBeGreaterThan(0);
|
|
462
|
+
}
|
|
463
|
+
const elapsed = performance.now() - start;
|
|
464
|
+
expect(elapsed).toBeLessThan(5000); // 1000 queries under 5s
|
|
465
|
+
});
|
|
466
|
+
|
|
467
|
+
it('grid cell system handles multi-scale queries', () => {
|
|
468
|
+
const system = new GridCellSystem(0.5, Math.SQRT2, 6, 32);
|
|
469
|
+
expect(system.totalCells).toBe(192); // 6 * 32
|
|
470
|
+
const start = performance.now();
|
|
471
|
+
for (let i = 0; i < 500; i++) {
|
|
472
|
+
const activations = system.getActivations({
|
|
473
|
+
x: Math.random() * 50,
|
|
474
|
+
y: Math.random() * 50,
|
|
475
|
+
z: 0,
|
|
476
|
+
});
|
|
477
|
+
expect(activations.size).toBe(192);
|
|
478
|
+
}
|
|
479
|
+
const elapsed = performance.now() - start;
|
|
480
|
+
expect(elapsed).toBeLessThan(3000);
|
|
481
|
+
});
|
|
482
|
+
});
|
|
483
|
+
|
|
484
|
+
describe('Load: Short-Term Memory', () => {
|
|
485
|
+
it('handles rapid frame insertion at 30fps', () => {
|
|
486
|
+
const stm = new ShortTermMemory(900, 30000); // 30s buffer
|
|
487
|
+
const start = performance.now();
|
|
488
|
+
for (let i = 0; i < 900; i++) {
|
|
489
|
+
const frame = makeTestFrame(32, 32, i, i + 1);
|
|
490
|
+
stm.add(frame, []);
|
|
491
|
+
}
|
|
492
|
+
const elapsed = performance.now() - start;
|
|
493
|
+
expect(stm.count).toBe(900);
|
|
494
|
+
expect(elapsed).toBeLessThan(2000);
|
|
495
|
+
// Verify FIFO eviction
|
|
496
|
+
stm.add(makeTestFrame(32, 32, 901, 901), []);
|
|
497
|
+
expect(stm.count).toBe(900); // oldest evicted
|
|
498
|
+
});
|
|
499
|
+
});
|