flow-store-stress.test.mjs
149 lines 4.0 KB
Raw
sha256:8915fe406161f95c1681f9469375e7bae5b28c884f00bedbdef65e4b0cd0738d docs(flow): commit FLOW-V0-SPEC.md hygiene for 7A-INT merge Human 14 hours ago
1 /**
2 * Tier 4 — STRESS: capped list/get with large vault fixtures.
3 *
4 * @see docs/FLOW-STORE-CONTRACT-7A-10.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 {
12 saveFlowStore,
13 listFlows,
14 getFlow,
15 MAX_FLOW_SUMMARIES,
16 MAX_STEPS_PER_FLOW,
17 buildFlowStepId,
18 } from '../lib/flow/flow-store.mjs';
19
20 const __dirname = path.dirname(fileURLToPath(import.meta.url));
21 const tmpRoot = path.join(__dirname, 'fixtures', 'tmp-flow-stress');
22
23 function makeFlow(id, scope, version, updated) {
24 return {
25 schema: 'knowtation.flow/v0',
26 flow_id: id,
27 title: `Flow ${id}`,
28 version,
29 scope,
30 summary: 'stress fixture',
31 tags: ['stress'],
32 steps: [buildFlowStepId(id, 1)],
33 inputs: [],
34 updated,
35 truncated: false,
36 };
37 }
38
39 function makeStep(flowId) {
40 return {
41 schema: 'knowtation.flow_step/v0',
42 step_id: buildFlowStepId(flowId, 1),
43 flow_id: flowId,
44 ordinal: 1,
45 owned_job: 'job',
46 instruction: 'do',
47 trigger: 'when',
48 when_not_to_run: 'never',
49 boundaries: ['b'],
50 output_shape: 'shape',
51 verification: { kind: 'human_review', evidence_required: true, description: 'd' },
52 automatable: 'manual',
53 };
54 }
55
56 describe('Flow store — stress caps', () => {
57 const dataDir = path.join(tmpRoot, 'data');
58 const vaultId = 'default';
59
60 beforeEach(() => {
61 fs.rmSync(tmpRoot, { recursive: true, force: true });
62 fs.mkdirSync(dataDir, { recursive: true });
63
64 const flows = [];
65 const steps = [];
66 for (let i = 0; i < MAX_FLOW_SUMMARIES; i += 1) {
67 const id = `flow_stress_${String(i).padStart(3, '0')}`;
68 flows.push(makeFlow(id, 'personal', '1.0.0', `2026-06-${String((i % 28) + 1).padStart(2, '0')}T00:00:00Z`));
69 steps.push(makeStep(id));
70 }
71
72 const bigId = 'flow_many_steps';
73 const bigSteps = [];
74 const bigStepIds = [];
75 for (let n = 1; n <= MAX_STEPS_PER_FLOW + 5; n += 1) {
76 bigStepIds.push(buildFlowStepId(bigId, n));
77 bigSteps.push({
78 ...makeStep(bigId),
79 step_id: buildFlowStepId(bigId, n),
80 ordinal: n,
81 owned_job: `job ${n}`,
82 });
83 }
84 flows.push({
85 ...makeFlow(bigId, 'personal', '1.0.0', '2026-06-30T00:00:00Z'),
86 steps: bigStepIds,
87 });
88 steps.push(...bigSteps);
89
90 saveFlowStore(dataDir, {
91 vaults: {
92 [vaultId]: {
93 flows,
94 steps,
95 runs: [{
96 schema: 'knowtation.flow_run/v0',
97 run_id: 'run_stress_deep',
98 flow_id: bigId,
99 flow_version: '1.0.0',
100 scope: 'personal',
101 status: 'in_progress',
102 step_states: bigStepIds.map((sid) => ({
103 step_id: sid,
104 status: 'done',
105 verified: true,
106 })),
107 started: '2026-06-20T00:00:00Z',
108 provenance: { actor: 'hash', harness: 'test' },
109 }],
110 candidates: [],
111 projections: [],
112 },
113 },
114 });
115 });
116
117 afterEach(() => {
118 fs.rmSync(tmpRoot, { recursive: true, force: true });
119 });
120
121 it('list caps at limit and sets truncated', () => {
122 const list = listFlows(dataDir, vaultId, {
123 filterScopes: new Set(['personal']),
124 effectiveScope: 'personal',
125 limit: 50,
126 });
127 assert.equal(list.flows.length, 50);
128 assert.equal(list.truncated, true);
129 });
130
131 it('get caps steps at MAX_STEPS_PER_FLOW and marks flow truncated', () => {
132 const got = getFlow(dataDir, vaultId, 'flow_many_steps', {
133 filterScopes: new Set(['personal']),
134 });
135 assert.ok(got);
136 assert.equal(got.steps.length, MAX_STEPS_PER_FLOW);
137 assert.equal(got.flow.truncated, true);
138 });
139
140 it('deep run step_states do not block get', () => {
141 const t0 = performance.now();
142 const got = getFlow(dataDir, vaultId, 'flow_many_steps', {
143 filterScopes: new Set(['personal']),
144 });
145 const elapsed = performance.now() - t0;
146 assert.ok(got);
147 assert.ok(elapsed < 500, `getFlow took ${elapsed}ms`);
148 });
149 });
File History 1 commit
sha256:8915fe406161f95c1681f9469375e7bae5b28c884f00bedbdef65e4b0cd0738d docs(flow): commit FLOW-V0-SPEC.md hygiene for 7A-INT merge Human 14 hours ago