task-write-data-integrity.test.mjs
143 lines 4.7 KB
Raw
sha256:b5f647cb9c409f563d4671fe3fc05ddea01fabfed9b41fc11cb923588e1c1baf mirror: GitHub Phase A durable MCP OAuth (#270) Human minor ⚠ breaking 10 days ago
1 /**
2 * Tier 5 — DATA-INTEGRITY: approve round-trip, uniqueness, SD-2 run_ref null at spawn.
3 */
4 import { describe, it, beforeEach, afterEach } from 'node:test';
5 import assert from 'node:assert/strict';
6 import fs from 'node:fs';
7 import path from 'node:path';
8 import { fileURLToPath } from 'node:url';
9
10 import {
11 handleTaskProposeRequest,
12 handleTaskInstanceMaterializeRequest,
13 loopStateId,
14 handleTaskLoopProposeRequest,
15 } from '../lib/task/task-write.mjs';
16 import { getTask } from '../lib/task/task-store.mjs';
17 import { assertLoopOccurrenceUniqueness, getTaskLoop, taskLoopForClient } from '../lib/task/task-loop-store.mjs';
18 import { createProposal } from '../hub/proposals-store.mjs';
19 import {
20 approveTaskProposal,
21 emptyTaskStarterDir,
22 sampleLoopCreatePayload,
23 sampleTaskCreatePayload,
24 visibleAll,
25 } from './fixtures/task/write-helpers.mjs';
26
27 const __dirname = path.dirname(fileURLToPath(import.meta.url));
28 const tmpRoot = path.join(__dirname, 'fixtures', 'tmp-task-write-di');
29
30 describe('task write — data integrity', () => {
31 const dataDir = path.join(tmpRoot, 'data');
32 const vaultId = 'default';
33 let starterDir;
34
35 beforeEach(() => {
36 fs.rmSync(tmpRoot, { recursive: true, force: true });
37 fs.mkdirSync(dataDir, { recursive: true });
38 starterDir = emptyTaskStarterDir(dataDir);
39 process.env.TASK_WRITES_ENABLED = '1';
40 });
41 afterEach(() => {
42 delete process.env.TASK_WRITES_ENABLED;
43 });
44
45 it('approve round-trip preserves task fields byte-stable', async () => {
46 const body = sampleTaskCreatePayload();
47 body.task.task_id = 'task_di_roundtrip';
48 const proposed = await handleTaskProposeRequest({
49 dataDir,
50 vaultId,
51 visibleScopes: visibleAll,
52 proposalKind: 'task_create',
53 body,
54 intent: 'create',
55 createProposal,
56 });
57 approveTaskProposal(dataDir, proposed.payload.proposal_id);
58 const task = getTask(dataDir, vaultId, 'task_di_roundtrip', { visibleScopes: visibleAll, starterDir });
59 assert.equal(task.title, body.task.title);
60 assert.equal(task.run_ref, null);
61 });
62
63 it('materialized instance has run_ref null (SD-2)', async () => {
64 const payload = sampleLoopCreatePayload();
65 payload.loop.loop_id = 'loop_di_sd2';
66 approveTaskProposal(
67 dataDir,
68 (await handleTaskLoopProposeRequest({
69 dataDir,
70 vaultId,
71 visibleScopes: visibleAll,
72 proposalKind: 'task_loop_create',
73 body: payload,
74 intent: 'create',
75 starterDir,
76 createProposal,
77 })).payload.proposal_id,
78 );
79 const loop = getTaskLoop(dataDir, vaultId, 'loop_di_sd2', { visibleScopes: visibleAll, starterDir });
80 const mat = await handleTaskInstanceMaterializeRequest({
81 dataDir,
82 vaultId,
83 visibleScopes: visibleAll,
84 loopId: 'loop_di_sd2',
85 body: {
86 loop_id: 'loop_di_sd2',
87 occurrence_key: '2026-W25',
88 base_state_id: loopStateId(taskLoopForClient(loop)),
89 },
90 intent: 'spawn',
91 starterDir,
92 createProposal,
93 });
94 approveTaskProposal(dataDir, mat.payload.proposal_id);
95 const task = getTask(dataDir, vaultId, mat.payload.task_id, { visibleScopes: visibleAll, starterDir });
96 assert.equal(task.run_ref, null);
97 assert.equal(assertLoopOccurrenceUniqueness(dataDir, vaultId).ok, true);
98 });
99
100 it('duplicate materialize occurrence_key refused at propose', async () => {
101 const payload = sampleLoopCreatePayload();
102 payload.loop.loop_id = 'loop_di_dup';
103 approveTaskProposal(
104 dataDir,
105 (await handleTaskLoopProposeRequest({
106 dataDir,
107 vaultId,
108 visibleScopes: visibleAll,
109 proposalKind: 'task_loop_create',
110 body: payload,
111 intent: 'create',
112 starterDir,
113 createProposal,
114 })).payload.proposal_id,
115 );
116 const loop = getTaskLoop(dataDir, vaultId, 'loop_di_dup', { visibleScopes: visibleAll, starterDir });
117 const baseStateId = loopStateId(taskLoopForClient(loop));
118 const mat = await handleTaskInstanceMaterializeRequest({
119 dataDir,
120 vaultId,
121 visibleScopes: visibleAll,
122 loopId: 'loop_di_dup',
123 body: { loop_id: 'loop_di_dup', occurrence_key: '2026-W25', base_state_id: baseStateId },
124 intent: 'spawn',
125 starterDir,
126 createProposal,
127 });
128 approveTaskProposal(dataDir, mat.payload.proposal_id);
129
130 const dup = await handleTaskInstanceMaterializeRequest({
131 dataDir,
132 vaultId,
133 visibleScopes: visibleAll,
134 loopId: 'loop_di_dup',
135 body: { loop_id: 'loop_di_dup', occurrence_key: '2026-W25', base_state_id: baseStateId },
136 intent: 'dup',
137 starterDir,
138 createProposal,
139 });
140 assert.equal(dup.ok, false);
141 assert.equal(dup.code, 'TASK_OCCURRENCE_EXISTS');
142 });
143 });
File History 1 commit
sha256:b5f647cb9c409f563d4671fe3fc05ddea01fabfed9b41fc11cb923588e1c1baf mirror: GitHub Phase A durable MCP OAuth (#270) Human minor 10 days ago