task-store-performance.test.mjs
90 lines 3.0 KB
Raw
sha256:b5f647cb9c409f563d4671fe3fc05ddea01fabfed9b41fc11cb923588e1c1baf mirror: GitHub Phase A durable MCP OAuth (#270) Human minor ⚠ breaking 10 days ago
1 /**
2 * Tier 6 — PERFORMANCE: list/get p95 budget on 500-task fixture.
3 *
4 * @see docs/TASK-STORE-CONTRACT-2G.md §9
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 { listTasks, getTask, MAX_TASK_SUMMARIES } from '../lib/task/task-store.mjs';
12 import { saveFlowStore } from '../lib/flow/flow-store.mjs';
13
14 const __dirname = path.dirname(fileURLToPath(import.meta.url));
15 const tmpRoot = path.join(__dirname, 'fixtures', 'tmp-task-performance');
16
17 function percentile(values, p) {
18 const sorted = [...values].sort((a, b) => a - b);
19 const idx = Math.ceil((p / 100) * sorted.length) - 1;
20 return sorted[Math.max(0, idx)];
21 }
22
23 describe('Task store — performance', () => {
24 const dataDir = path.join(tmpRoot, 'data');
25 const vaultId = 'default';
26
27 beforeEach(() => {
28 fs.rmSync(tmpRoot, { recursive: true, force: true });
29 fs.mkdirSync(dataDir, { recursive: true });
30 const tasks = [];
31 for (let i = 0; i < MAX_TASK_SUMMARIES; i += 1) {
32 const id = `task_perf_${String(i).padStart(6, '0')}`;
33 tasks.push({
34 schema: 'knowtation.task/v0',
35 task_id: id,
36 kind: 'personal',
37 scope: i % 3 === 0 ? 'org' : i % 2 === 0 ? 'project' : 'personal',
38 status: 'pending',
39 title: id,
40 workspace_id: 'ws-personal',
41 due_at: i % 7 === 0 ? null : `2026-06-${String((i % 28) + 1).padStart(2, '0')}T00:00:00Z`,
42 assignee_ref: null,
43 assigner_ref: null,
44 run_ref: null,
45 artifact_links: [],
46 created: '2026-06-01T00:00:00Z',
47 updated: '2026-06-01T00:00:00Z',
48 truncated: false,
49 });
50 }
51 saveFlowStore(dataDir, {
52 vaults: {
53 [vaultId]: { flows: [], steps: [], runs: [], candidates: [], projections: [], tasks },
54 },
55 });
56 });
57
58 afterEach(() => {
59 fs.rmSync(tmpRoot, { recursive: true, force: true });
60 });
61
62 it('listTasks and getTask stay within p95 budget', () => {
63 const listTimes = [];
64 for (let i = 0; i < 40; i += 1) {
65 const t0 = performance.now();
66 listTasks(dataDir, vaultId, {
67 filterScopes: new Set(['personal', 'project', 'org']),
68 effectiveScope: 'org',
69 workspaceId: i % 2 === 0 ? 'ws-personal' : undefined,
70 limit: MAX_TASK_SUMMARIES,
71 });
72 listTimes.push(performance.now() - t0);
73 }
74
75 const getTimes = [];
76 for (let i = 0; i < 40; i += 1) {
77 const id = `task_perf_${String(i * 12).padStart(6, '0')}`;
78 const t0 = performance.now();
79 getTask(dataDir, vaultId, id, {
80 visibleScopes: new Set(['personal', 'project', 'org']),
81 });
82 getTimes.push(performance.now() - t0);
83 }
84
85 const listP95 = percentile(listTimes, 95);
86 const getP95 = percentile(getTimes, 95);
87 assert.ok(listP95 < 200, `listTasks p95 ${listP95}ms exceeds budget`);
88 assert.ok(getP95 < 50, `getTask p95 ${getP95}ms exceeds budget`);
89 });
90 });
File History 1 commit
sha256:b5f647cb9c409f563d4671fe3fc05ddea01fabfed9b41fc11cb923588e1c1baf mirror: GitHub Phase A durable MCP OAuth (#270) Human minor 10 days ago