flow-capture-performance.test.mjs
sha256:8915fe406161f95c1681f9469375e7bae5b28c884f00bedbdef65e4b0cd0738d
docs(flow): commit FLOW-V0-SPEC.md hygiene for 7A-INT merge
Human
17 hours ago
| 1 | /** |
| 2 | * Tier 6 — PERFORMANCE: observe + dedup scan + list bounded. |
| 3 | * |
| 4 | * @see lib/flow/flow-capture.mjs |
| 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 | handleFlowCaptureObserveRequest, |
| 13 | handleFlowCaptureListRequest, |
| 14 | handleFlowCaptureProposeRequest, |
| 15 | computeStructuralOverlap, |
| 16 | } from '../lib/flow/flow-capture.mjs'; |
| 17 | import { applyFlowProposalToIndex } from '../lib/flow/flow-authoring.mjs'; |
| 18 | import { upsertCandidate } from '../lib/flow/flow-store.mjs'; |
| 19 | import { createProposal } from '../hub/proposals-store.mjs'; |
| 20 | import { makeFlowBundle, emptyStarterDir } from './fixtures/flow/authoring-helpers.mjs'; |
| 21 | import { validSessionMeta, makeCandidateRecord } from './fixtures/flow/capture-helpers.mjs'; |
| 22 | |
| 23 | const __dirname = path.dirname(fileURLToPath(import.meta.url)); |
| 24 | const tmpRoot = path.join(__dirname, 'fixtures', 'tmp-flow-capture-perf'); |
| 25 | const visible = new Set(['personal', 'project', 'org']); |
| 26 | const P95_BUDGET_MS = 500; |
| 27 | |
| 28 | function p95(samples) { |
| 29 | const sorted = [...samples].sort((a, b) => a - b); |
| 30 | const idx = Math.ceil(sorted.length * 0.95) - 1; |
| 31 | return sorted[Math.max(0, idx)]; |
| 32 | } |
| 33 | |
| 34 | describe('Flow capture — performance', () => { |
| 35 | const dataDir = path.join(tmpRoot, 'data'); |
| 36 | const vaultId = 'default'; |
| 37 | |
| 38 | beforeEach(() => { |
| 39 | fs.rmSync(tmpRoot, { recursive: true, force: true }); |
| 40 | fs.mkdirSync(dataDir, { recursive: true }); |
| 41 | process.env.FLOW_CAPTURE_DETECTION_ENABLED = '1'; |
| 42 | process.env.FLOW_CAPTURE_WRITES_ENABLED = '1'; |
| 43 | }); |
| 44 | afterEach(() => { |
| 45 | fs.rmSync(tmpRoot, { recursive: true, force: true }); |
| 46 | delete process.env.FLOW_CAPTURE_DETECTION_ENABLED; |
| 47 | delete process.env.FLOW_CAPTURE_WRITES_ENABLED; |
| 48 | }); |
| 49 | |
| 50 | it('observe + dedup overlap scan within p95 budget on large index', () => { |
| 51 | const starterDir = emptyStarterDir(dataDir); |
| 52 | for (let i = 0; i < 40; i += 1) { |
| 53 | const bundle = makeFlowBundle({ flowId: `flow_perf_${i}`, steps: 3 }); |
| 54 | applyFlowProposalToIndex(dataDir, vaultId, bundle.flow, bundle.steps); |
| 55 | } |
| 56 | upsertCandidate(dataDir, vaultId, makeCandidateRecord({ candidate_id: 'cand_perf1' })); |
| 57 | |
| 58 | const samples = []; |
| 59 | for (let i = 0; i < 20; i += 1) { |
| 60 | const t0 = performance.now(); |
| 61 | handleFlowCaptureProposeRequest({ |
| 62 | dataDir, vaultId, visibleScopes: visible, candidateId: 'cand_perf1', confirmedScope: 'personal', intent: 'x', createProposal, starterDir, |
| 63 | }); |
| 64 | samples.push(performance.now() - t0); |
| 65 | } |
| 66 | assert.ok(p95(samples) < P95_BUDGET_MS, `p95 ${p95(samples)}ms exceeds ${P95_BUDGET_MS}ms`); |
| 67 | }); |
| 68 | |
| 69 | it('list candidates bounded', () => { |
| 70 | for (let i = 0; i < 60; i += 1) { |
| 71 | upsertCandidate(dataDir, vaultId, makeCandidateRecord({ candidate_id: `cand_p${String(i).padStart(3, '0')}` })); |
| 72 | } |
| 73 | const t0 = performance.now(); |
| 74 | const r = handleFlowCaptureListRequest({ dataDir, vaultId, visibleScopes: visible, limit: 50 }); |
| 75 | const elapsed = performance.now() - t0; |
| 76 | assert.equal(r.payload.candidates.length, 50); |
| 77 | assert.ok(elapsed < P95_BUDGET_MS); |
| 78 | }); |
| 79 | |
| 80 | it('overlap helper is linear in token sets', () => { |
| 81 | const draft = Array.from({ length: 32 }, (_, i) => `step token${i} action verify`); |
| 82 | const steps = Array.from({ length: 32 }, (_, i) => ({ |
| 83 | owned_job: `token${i}`, |
| 84 | instruction: `action verify step ${i}`, |
| 85 | skill_refs: [], |
| 86 | })); |
| 87 | const t0 = performance.now(); |
| 88 | for (let i = 0; i < 200; i += 1) computeStructuralOverlap(draft, steps); |
| 89 | assert.ok(performance.now() - t0 < P95_BUDGET_MS); |
| 90 | }); |
| 91 | |
| 92 | it('observe path bounded for valid meta', () => { |
| 93 | const samples = []; |
| 94 | for (let i = 0; i < 30; i += 1) { |
| 95 | const t0 = performance.now(); |
| 96 | handleFlowCaptureObserveRequest({ |
| 97 | dataDir, vaultId, visibleScopes: visible, sessionMeta: validSessionMeta({ session_id: 'a'.repeat(64) }), |
| 98 | }); |
| 99 | samples.push(performance.now() - t0); |
| 100 | } |
| 101 | assert.ok(p95(samples) < P95_BUDGET_MS); |
| 102 | }); |
| 103 | }); |
File History
1 commit
sha256:8915fe406161f95c1681f9469375e7bae5b28c884f00bedbdef65e4b0cd0738d
docs(flow): commit FLOW-V0-SPEC.md hygiene for 7A-INT merge
Human
17 hours ago