task-loop-store-performance.test.mjs
102 lines 3.4 KB
Raw
sha256:baa800aedf841dbf32081aa7b2befa288ac33dfc7175ac55014c55c4d8c742f9 docs: move durable-auth freeze/evidence to local developmen… Human 10 days ago
1 /**
2 * Tier 6 — PERFORMANCE: list/get p95 budget on loop fixtures.
3 *
4 * @see docs/TASK-LOOP-STORE-CONTRACT-2G-c.md §6
5 */
6 import { describe, it, beforeEach, afterEach } from 'node:test';
7 import assert from 'node:assert/strict';
8 import fs from 'node:fs';
9 import path from 'node:path';
10 import { fileURLToPath } from 'node:url';
11 import { getRepoRoot } from '../lib/repo-root.mjs';
12 import { listTaskLoops, getTaskLoop } from '../lib/task/task-loop-store.mjs';
13 import { listTasks } from '../lib/task/task-store.mjs';
14
15 const __dirname = path.dirname(fileURLToPath(import.meta.url));
16 const tmpRoot = path.join(__dirname, 'fixtures', 'tmp-task-loop-perf');
17 const loopStarterDir = path.join(getRepoRoot(), 'task-loops/starter');
18 const graphStarterDir = path.join(getRepoRoot(), 'orchestrator-graphs/starter');
19 const instancesDir = path.join(getRepoRoot(), 'task-loops/starter/instances');
20 const vaultId = 'vault-loop-perf';
21
22 /** p95 budget ms for loop list/get on fixture graph. */
23 const P95_BUDGET_MS = 50;
24
25 function p95(samples) {
26 const sorted = [...samples].sort((a, b) => a - b);
27 const idx = Math.ceil(sorted.length * 0.95) - 1;
28 return sorted[Math.max(0, idx)];
29 }
30
31 describe('Task loop store — performance', () => {
32 beforeEach(() => {
33 fs.rmSync(tmpRoot, { recursive: true, force: true });
34 fs.mkdirSync(tmpRoot, { recursive: true });
35 });
36
37 afterEach(() => {
38 fs.rmSync(tmpRoot, { recursive: true, force: true });
39 });
40
41 it('listTaskLoops and getTaskLoop stay within p95 budget on school-trip fixtures', () => {
42 const dataDir = path.join(tmpRoot, 'data');
43 fs.mkdirSync(dataDir, { recursive: true });
44
45 const listSamples = [];
46 const getSamples = [];
47
48 for (let i = 0; i < 100; i += 1) {
49 const t0 = performance.now();
50 listTaskLoops(dataDir, vaultId, {
51 visibleScopes: new Set(['personal']),
52 filterScopes: new Set(['personal']),
53 effectiveScope: 'personal',
54 starterDir: loopStarterDir,
55 graphsDir: graphStarterDir,
56 instancesDir,
57 });
58 listSamples.push(performance.now() - t0);
59
60 const t1 = performance.now();
61 getTaskLoop(dataDir, vaultId, 'loop_school_trip', {
62 visibleScopes: new Set(['personal']),
63 starterDir: loopStarterDir,
64 graphsDir: graphStarterDir,
65 instancesDir,
66 });
67 getSamples.push(performance.now() - t1);
68 }
69
70 assert.ok(p95(listSamples) < P95_BUDGET_MS, `list p95 ${p95(listSamples)}ms`);
71 assert.ok(p95(getSamples) < P95_BUDGET_MS, `get p95 ${p95(getSamples)}ms`);
72 });
73
74 it('listTasks with loop_ref filter stays within p95 on seeded instance', () => {
75 const dataDir = path.join(tmpRoot, 'data-filter');
76 fs.mkdirSync(dataDir, { recursive: true });
77
78 listTaskLoops(dataDir, vaultId, {
79 visibleScopes: new Set(['personal']),
80 filterScopes: new Set(['personal']),
81 effectiveScope: 'personal',
82 starterDir: loopStarterDir,
83 graphsDir: graphStarterDir,
84 instancesDir,
85 });
86
87 const samples = [];
88 for (let i = 0; i < 100; i += 1) {
89 const t0 = performance.now();
90 listTasks(dataDir, vaultId, {
91 visibleScopes: new Set(['personal']),
92 filterScopes: new Set(['personal']),
93 effectiveScope: 'personal',
94 loopRef: 'loop_school_trip',
95 starterDir: instancesDir,
96 });
97 samples.push(performance.now() - t0);
98 }
99
100 assert.ok(p95(samples) < P95_BUDGET_MS, `filter p95 ${p95(samples)}ms`);
101 });
102 });
File History 1 commit
sha256:baa800aedf841dbf32081aa7b2befa288ac33dfc7175ac55014c55c4d8c742f9 docs: move durable-auth freeze/evidence to local developmen… Human 10 days ago