hzl-core 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (177) hide show
  1. package/dist/__tests__/backup/backup-restore.test.d.ts +2 -0
  2. package/dist/__tests__/backup/backup-restore.test.d.ts.map +1 -0
  3. package/dist/__tests__/backup/backup-restore.test.js +200 -0
  4. package/dist/__tests__/backup/backup-restore.test.js.map +1 -0
  5. package/dist/__tests__/backup/import-export.test.d.ts +2 -0
  6. package/dist/__tests__/backup/import-export.test.d.ts.map +1 -0
  7. package/dist/__tests__/backup/import-export.test.js +341 -0
  8. package/dist/__tests__/backup/import-export.test.js.map +1 -0
  9. package/dist/__tests__/concurrency/stress.test.d.ts +2 -0
  10. package/dist/__tests__/concurrency/stress.test.d.ts.map +1 -0
  11. package/dist/__tests__/concurrency/stress.test.js +274 -0
  12. package/dist/__tests__/concurrency/stress.test.js.map +1 -0
  13. package/dist/__tests__/concurrency/worker.d.ts +2 -0
  14. package/dist/__tests__/concurrency/worker.d.ts.map +1 -0
  15. package/dist/__tests__/concurrency/worker.js +84 -0
  16. package/dist/__tests__/concurrency/worker.js.map +1 -0
  17. package/dist/__tests__/migrations/upgrade.test.d.ts +2 -0
  18. package/dist/__tests__/migrations/upgrade.test.d.ts.map +1 -0
  19. package/dist/__tests__/migrations/upgrade.test.js +203 -0
  20. package/dist/__tests__/migrations/upgrade.test.js.map +1 -0
  21. package/dist/__tests__/projections/rebuild-equivalence.test.d.ts +2 -0
  22. package/dist/__tests__/projections/rebuild-equivalence.test.d.ts.map +1 -0
  23. package/dist/__tests__/projections/rebuild-equivalence.test.js +276 -0
  24. package/dist/__tests__/projections/rebuild-equivalence.test.js.map +1 -0
  25. package/dist/__tests__/properties/invariants.test.d.ts +2 -0
  26. package/dist/__tests__/properties/invariants.test.d.ts.map +1 -0
  27. package/dist/__tests__/properties/invariants.test.js +314 -0
  28. package/dist/__tests__/properties/invariants.test.js.map +1 -0
  29. package/dist/db/connection.d.ts +13 -0
  30. package/dist/db/connection.d.ts.map +1 -0
  31. package/dist/db/connection.js +52 -0
  32. package/dist/db/connection.js.map +1 -0
  33. package/dist/db/connection.test.d.ts +2 -0
  34. package/dist/db/connection.test.d.ts.map +1 -0
  35. package/dist/db/connection.test.js +63 -0
  36. package/dist/db/connection.test.js.map +1 -0
  37. package/dist/db/migrations/v2.d.ts +2 -0
  38. package/dist/db/migrations/v2.d.ts.map +1 -0
  39. package/dist/db/migrations/v2.js +4 -0
  40. package/dist/db/migrations/v2.js.map +1 -0
  41. package/dist/db/migrations.d.ts +4 -0
  42. package/dist/db/migrations.d.ts.map +1 -0
  43. package/dist/db/migrations.js +45 -0
  44. package/dist/db/migrations.js.map +1 -0
  45. package/dist/db/migrations.test.d.ts +2 -0
  46. package/dist/db/migrations.test.d.ts.map +1 -0
  47. package/dist/db/migrations.test.js +75 -0
  48. package/dist/db/migrations.test.js.map +1 -0
  49. package/dist/db/schema.d.ts +3 -0
  50. package/dist/db/schema.d.ts.map +1 -0
  51. package/dist/db/schema.js +114 -0
  52. package/dist/db/schema.js.map +1 -0
  53. package/dist/events/store.d.ts +33 -0
  54. package/dist/events/store.d.ts.map +1 -0
  55. package/dist/events/store.js +81 -0
  56. package/dist/events/store.js.map +1 -0
  57. package/dist/events/store.test.d.ts +2 -0
  58. package/dist/events/store.test.d.ts.map +1 -0
  59. package/dist/events/store.test.js +138 -0
  60. package/dist/events/store.test.js.map +1 -0
  61. package/dist/events/types.d.ts +106 -0
  62. package/dist/events/types.d.ts.map +1 -0
  63. package/dist/events/types.js +87 -0
  64. package/dist/events/types.js.map +1 -0
  65. package/dist/events/validation.test.d.ts +2 -0
  66. package/dist/events/validation.test.d.ts.map +1 -0
  67. package/dist/events/validation.test.js +83 -0
  68. package/dist/events/validation.test.js.map +1 -0
  69. package/dist/fixtures/sample-data.d.ts +16 -0
  70. package/dist/fixtures/sample-data.d.ts.map +1 -0
  71. package/dist/fixtures/sample-data.js +148 -0
  72. package/dist/fixtures/sample-data.js.map +1 -0
  73. package/dist/index.d.ts +27 -0
  74. package/dist/index.d.ts.map +1 -0
  75. package/dist/index.js +44 -0
  76. package/dist/index.js.map +1 -0
  77. package/dist/index.test.d.ts +2 -0
  78. package/dist/index.test.d.ts.map +1 -0
  79. package/dist/index.test.js +102 -0
  80. package/dist/index.test.js.map +1 -0
  81. package/dist/projections/comments-checkpoints.d.ts +11 -0
  82. package/dist/projections/comments-checkpoints.d.ts.map +1 -0
  83. package/dist/projections/comments-checkpoints.js +33 -0
  84. package/dist/projections/comments-checkpoints.js.map +1 -0
  85. package/dist/projections/comments-checkpoints.test.d.ts +2 -0
  86. package/dist/projections/comments-checkpoints.test.d.ts.map +1 -0
  87. package/dist/projections/comments-checkpoints.test.js +72 -0
  88. package/dist/projections/comments-checkpoints.test.js.map +1 -0
  89. package/dist/projections/dependencies.d.ts +12 -0
  90. package/dist/projections/dependencies.d.ts.map +1 -0
  91. package/dist/projections/dependencies.js +39 -0
  92. package/dist/projections/dependencies.js.map +1 -0
  93. package/dist/projections/dependencies.test.d.ts +2 -0
  94. package/dist/projections/dependencies.test.d.ts.map +1 -0
  95. package/dist/projections/dependencies.test.js +97 -0
  96. package/dist/projections/dependencies.test.js.map +1 -0
  97. package/dist/projections/engine.d.ts +18 -0
  98. package/dist/projections/engine.d.ts.map +1 -0
  99. package/dist/projections/engine.js +56 -0
  100. package/dist/projections/engine.js.map +1 -0
  101. package/dist/projections/engine.test.d.ts +2 -0
  102. package/dist/projections/engine.test.d.ts.map +1 -0
  103. package/dist/projections/engine.test.js +92 -0
  104. package/dist/projections/engine.test.js.map +1 -0
  105. package/dist/projections/rebuild.d.ts +4 -0
  106. package/dist/projections/rebuild.d.ts.map +1 -0
  107. package/dist/projections/rebuild.js +26 -0
  108. package/dist/projections/rebuild.js.map +1 -0
  109. package/dist/projections/rebuild.test.d.ts +2 -0
  110. package/dist/projections/rebuild.test.d.ts.map +1 -0
  111. package/dist/projections/rebuild.test.js +59 -0
  112. package/dist/projections/rebuild.test.js.map +1 -0
  113. package/dist/projections/search.d.ts +11 -0
  114. package/dist/projections/search.d.ts.map +1 -0
  115. package/dist/projections/search.js +39 -0
  116. package/dist/projections/search.js.map +1 -0
  117. package/dist/projections/search.test.d.ts +2 -0
  118. package/dist/projections/search.test.d.ts.map +1 -0
  119. package/dist/projections/search.test.js +78 -0
  120. package/dist/projections/search.test.js.map +1 -0
  121. package/dist/projections/tags.d.ts +12 -0
  122. package/dist/projections/tags.d.ts.map +1 -0
  123. package/dist/projections/tags.js +41 -0
  124. package/dist/projections/tags.js.map +1 -0
  125. package/dist/projections/tags.test.d.ts +2 -0
  126. package/dist/projections/tags.test.d.ts.map +1 -0
  127. package/dist/projections/tags.test.js +69 -0
  128. package/dist/projections/tags.test.js.map +1 -0
  129. package/dist/projections/tasks-current.d.ts +14 -0
  130. package/dist/projections/tasks-current.d.ts.map +1 -0
  131. package/dist/projections/tasks-current.js +110 -0
  132. package/dist/projections/tasks-current.js.map +1 -0
  133. package/dist/projections/tasks-current.test.d.ts +2 -0
  134. package/dist/projections/tasks-current.test.d.ts.map +1 -0
  135. package/dist/projections/tasks-current.test.js +215 -0
  136. package/dist/projections/tasks-current.test.js.map +1 -0
  137. package/dist/projections/types.d.ts +13 -0
  138. package/dist/projections/types.d.ts.map +1 -0
  139. package/dist/projections/types.js +2 -0
  140. package/dist/projections/types.js.map +1 -0
  141. package/dist/services/backup-service.d.ts +16 -0
  142. package/dist/services/backup-service.d.ts.map +1 -0
  143. package/dist/services/backup-service.js +114 -0
  144. package/dist/services/backup-service.js.map +1 -0
  145. package/dist/services/search-service.d.ts +27 -0
  146. package/dist/services/search-service.d.ts.map +1 -0
  147. package/dist/services/search-service.js +33 -0
  148. package/dist/services/search-service.js.map +1 -0
  149. package/dist/services/search-service.test.d.ts +2 -0
  150. package/dist/services/search-service.test.d.ts.map +1 -0
  151. package/dist/services/search-service.test.js +66 -0
  152. package/dist/services/search-service.test.js.map +1 -0
  153. package/dist/services/task-service.d.ts +147 -0
  154. package/dist/services/task-service.d.ts.map +1 -0
  155. package/dist/services/task-service.js +442 -0
  156. package/dist/services/task-service.js.map +1 -0
  157. package/dist/services/task-service.test.d.ts +2 -0
  158. package/dist/services/task-service.test.d.ts.map +1 -0
  159. package/dist/services/task-service.test.js +399 -0
  160. package/dist/services/task-service.test.js.map +1 -0
  161. package/dist/services/validation-service.d.ts +29 -0
  162. package/dist/services/validation-service.d.ts.map +1 -0
  163. package/dist/services/validation-service.js +74 -0
  164. package/dist/services/validation-service.js.map +1 -0
  165. package/dist/services/validation-service.test.d.ts +2 -0
  166. package/dist/services/validation-service.test.d.ts.map +1 -0
  167. package/dist/services/validation-service.test.js +67 -0
  168. package/dist/services/validation-service.test.js.map +1 -0
  169. package/dist/utils/id.d.ts +3 -0
  170. package/dist/utils/id.d.ts.map +1 -0
  171. package/dist/utils/id.js +12 -0
  172. package/dist/utils/id.js.map +1 -0
  173. package/dist/utils/id.test.d.ts +2 -0
  174. package/dist/utils/id.test.d.ts.map +1 -0
  175. package/dist/utils/id.test.js +24 -0
  176. package/dist/utils/id.test.js.map +1 -0
  177. package/package.json +83 -0
@@ -0,0 +1,274 @@
1
+ import { describe, it, expect, beforeAll, beforeEach, afterEach } from 'vitest';
2
+ import { Worker } from 'worker_threads';
3
+ import fs from 'fs';
4
+ import path from 'path';
5
+ import os from 'os';
6
+ import { execSync } from 'child_process';
7
+ import { fileURLToPath } from 'url';
8
+ import { createConnection } from '../../db/connection.js';
9
+ import { EventStore } from '../../events/store.js';
10
+ import { ProjectionEngine } from '../../projections/engine.js';
11
+ import { TasksCurrentProjector } from '../../projections/tasks-current.js';
12
+ import { DependenciesProjector } from '../../projections/dependencies.js';
13
+ import { TagsProjector } from '../../projections/tags.js';
14
+ import { TaskService } from '../../services/task-service.js';
15
+ import { TaskStatus } from '../../events/types.js';
16
+ const __filename = fileURLToPath(import.meta.url);
17
+ const __dirname = path.dirname(__filename);
18
+ const packageRoot = path.resolve(__dirname, '../../..');
19
+ const distWorkerPath = path.join(packageRoot, 'dist/__tests__/concurrency/worker.js');
20
+ function runWorker(dbPath, command) {
21
+ return new Promise((resolve, reject) => {
22
+ let settled = false;
23
+ const worker = new Worker(distWorkerPath, {
24
+ workerData: { dbPath, command },
25
+ });
26
+ worker.on('message', (message) => {
27
+ if (settled)
28
+ return;
29
+ settled = true;
30
+ resolve(message);
31
+ });
32
+ worker.on('error', (error) => {
33
+ if (settled)
34
+ return;
35
+ settled = true;
36
+ reject(error);
37
+ });
38
+ worker.on('exit', (code) => {
39
+ if (settled || code === 0)
40
+ return;
41
+ settled = true;
42
+ reject(new Error(`Worker exited with code ${code}`));
43
+ });
44
+ });
45
+ }
46
+ function setupServices(database) {
47
+ const eventStore = new EventStore(database);
48
+ const engine = new ProjectionEngine(database);
49
+ engine.register(new TasksCurrentProjector());
50
+ engine.register(new DependenciesProjector());
51
+ engine.register(new TagsProjector());
52
+ return {
53
+ eventStore,
54
+ engine,
55
+ taskService: new TaskService(database, eventStore, engine),
56
+ };
57
+ }
58
+ describe('Concurrency Stress Tests', () => {
59
+ let tempDir;
60
+ let dbPath;
61
+ let db;
62
+ let taskService;
63
+ beforeAll(() => {
64
+ execSync('npm run build', { cwd: packageRoot, stdio: 'inherit' });
65
+ });
66
+ beforeEach(() => {
67
+ tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'hzl-stress-'));
68
+ dbPath = path.join(tempDir, 'test.db');
69
+ db = createConnection(dbPath);
70
+ db.pragma('journal_mode = WAL');
71
+ db.pragma('busy_timeout = 5000');
72
+ const services = setupServices(db);
73
+ taskService = services.taskService;
74
+ });
75
+ afterEach(() => {
76
+ db.close();
77
+ fs.rmSync(tempDir, { recursive: true, force: true });
78
+ });
79
+ describe('claim-next contention (cross-process)', () => {
80
+ it('ensures exactly one agent claims each task under high contention', async () => {
81
+ const taskIds = [];
82
+ for (let i = 0; i < 10; i++) {
83
+ const task = taskService.createTask({ title: `Task ${i}`, project: 'stress-test' });
84
+ taskService.setStatus(task.task_id, TaskStatus.Ready);
85
+ taskIds.push(task.task_id);
86
+ }
87
+ const claims = Array.from({ length: 20 }, (_, i) => runWorker(dbPath, {
88
+ type: 'claim-next',
89
+ project: 'stress-test',
90
+ author: `agent-${i}`,
91
+ }));
92
+ const results = await Promise.all(claims);
93
+ const successes = results.filter((result) => result.success);
94
+ expect(successes).toHaveLength(10);
95
+ const claimedTaskIds = successes.map((result) => result.taskId);
96
+ const uniqueClaimedIds = new Set(claimedTaskIds);
97
+ expect(uniqueClaimedIds.size).toBe(10);
98
+ for (const taskId of taskIds) {
99
+ expect(claimedTaskIds).toContain(taskId);
100
+ }
101
+ const failedClaims = results.filter((result) => !result.success);
102
+ expect(failedClaims).toHaveLength(10);
103
+ });
104
+ it('prevents double-claiming a single task across workers', async () => {
105
+ const task = taskService.createTask({ title: 'Contested task', project: 'stress-test' });
106
+ taskService.setStatus(task.task_id, TaskStatus.Ready);
107
+ const attempts = Array.from({ length: 20 }, (_, i) => runWorker(dbPath, {
108
+ type: 'claim-specific',
109
+ taskId: task.task_id,
110
+ author: `agent-${i}`,
111
+ }));
112
+ const results = await Promise.all(attempts);
113
+ const successes = results.filter((result) => result.success);
114
+ expect(successes).toHaveLength(1);
115
+ expect(successes[0].taskId).toBe(task.task_id);
116
+ const taskRow = db
117
+ .prepare('SELECT status, claimed_by_author FROM tasks_current WHERE task_id = ?')
118
+ .get(task.task_id);
119
+ expect(taskRow.status).toBe('in_progress');
120
+ expect(taskRow.claimed_by_author).toBeDefined();
121
+ });
122
+ });
123
+ describe('steal contention (cross-process)', () => {
124
+ it('allows only one agent to steal an expired lease', async () => {
125
+ const task = taskService.createTask({ title: 'Expired task', project: 'stress-test' });
126
+ taskService.setStatus(task.task_id, TaskStatus.Ready);
127
+ taskService.claimTask(task.task_id, {
128
+ author: 'original-agent',
129
+ lease_until: new Date(Date.now() - 60000).toISOString(),
130
+ });
131
+ const steals = Array.from({ length: 10 }, (_, i) => runWorker(dbPath, {
132
+ type: 'steal',
133
+ taskId: task.task_id,
134
+ author: `stealer-${i}`,
135
+ ifExpired: true,
136
+ leaseMinutes: 5,
137
+ }));
138
+ const results = await Promise.all(steals);
139
+ const successes = results.filter((result) => result.success);
140
+ expect(successes).toHaveLength(1);
141
+ const updatedTask = taskService.getTaskById(task.task_id);
142
+ expect(updatedTask?.claimed_by_author).toBeTruthy();
143
+ });
144
+ it('rejects steal when lease is not expired', () => {
145
+ const task = taskService.createTask({ title: 'Active task', project: 'stress-test' });
146
+ taskService.setStatus(task.task_id, TaskStatus.Ready);
147
+ taskService.claimTask(task.task_id, {
148
+ author: 'original-agent',
149
+ lease_until: new Date(Date.now() + 3600000).toISOString(),
150
+ });
151
+ const result = taskService.stealTask(task.task_id, {
152
+ author: 'stealer',
153
+ ifExpired: true,
154
+ });
155
+ expect(result.success).toBe(false);
156
+ expect(result.error).toContain('not expired');
157
+ });
158
+ });
159
+ describe('mixed operations stress test (cross-process)', () => {
160
+ it('handles concurrent claim, complete, and release operations', async () => {
161
+ for (let i = 0; i < 12; i++) {
162
+ const task = taskService.createTask({ title: `Task ${i}`, project: 'stress-test' });
163
+ taskService.setStatus(task.task_id, TaskStatus.Ready);
164
+ }
165
+ const claims = Array.from({ length: 6 }, (_, i) => runWorker(dbPath, {
166
+ type: 'claim-next',
167
+ project: 'stress-test',
168
+ author: `agent-${i}`,
169
+ }));
170
+ const claimResults = await Promise.all(claims);
171
+ const claimed = claimResults.filter((result) => result.success && result.taskId);
172
+ expect(claimed).toHaveLength(6);
173
+ const completeOps = claimed.slice(0, 3).map((claim, index) => runWorker(dbPath, {
174
+ type: 'complete',
175
+ taskId: claim.taskId,
176
+ author: `finisher-${index}`,
177
+ }));
178
+ const releaseOps = claimed.slice(3, 5).map((claim, index) => runWorker(dbPath, {
179
+ type: 'release',
180
+ taskId: claim.taskId,
181
+ author: `releaser-${index}`,
182
+ }));
183
+ const followUpClaims = Array.from({ length: 2 }, (_, i) => runWorker(dbPath, {
184
+ type: 'claim-next',
185
+ project: 'stress-test',
186
+ author: `agent-${i + 10}`,
187
+ }));
188
+ const wave2Results = await Promise.all([...completeOps, ...releaseOps, ...followUpClaims]);
189
+ const errors = wave2Results.filter((result) => !result.success && result.operation !== 'claim-next');
190
+ expect(errors).toHaveLength(0);
191
+ const taskCounts = db
192
+ .prepare(`SELECT status, COUNT(*) as count FROM tasks_current
193
+ WHERE project = 'stress-test' GROUP BY status`)
194
+ .all();
195
+ const totalTasks = taskCounts.reduce((sum, row) => sum + row.count, 0);
196
+ expect(totalTasks).toBe(12);
197
+ });
198
+ });
199
+ describe('invariant preservation under concurrency', () => {
200
+ it('never allows double-claiming the same task via direct claim', async () => {
201
+ const task = taskService.createTask({ title: 'Single task', project: 'stress-test' });
202
+ taskService.setStatus(task.task_id, TaskStatus.Ready);
203
+ const claimPromises = [];
204
+ for (let i = 0; i < 20; i++) {
205
+ claimPromises.push(Promise.resolve().then(() => {
206
+ try {
207
+ taskService.claimTask(task.task_id, { author: `agent-${i}` });
208
+ return { success: true };
209
+ }
210
+ catch {
211
+ return { success: false };
212
+ }
213
+ }));
214
+ }
215
+ const results = await Promise.all(claimPromises);
216
+ const successCount = results.filter((result) => result.success).length;
217
+ expect(successCount).toBe(1);
218
+ const taskRow = db
219
+ .prepare('SELECT status, claimed_by_author FROM tasks_current WHERE task_id = ?')
220
+ .get(task.task_id);
221
+ expect(taskRow.status).toBe('in_progress');
222
+ expect(taskRow.claimed_by_author).toBeDefined();
223
+ });
224
+ it('maintains consistent event count under concurrent writes', async () => {
225
+ const taskIds = [];
226
+ for (let i = 0; i < 10; i++) {
227
+ const task = taskService.createTask({ title: `Task ${i}`, project: 'stress-test' });
228
+ taskService.setStatus(task.task_id, TaskStatus.Ready);
229
+ taskIds.push(task.task_id);
230
+ }
231
+ const initialEventCount = db
232
+ .prepare('SELECT COUNT(*) as count FROM events')
233
+ .get();
234
+ const claimPromises = taskIds.map((_, i) => Promise.resolve().then(() => {
235
+ const result = taskService.claimNext({ author: `agent-${i}`, project: 'stress-test' });
236
+ return { success: !!result };
237
+ }));
238
+ await Promise.all(claimPromises);
239
+ const finalEventCount = db
240
+ .prepare('SELECT COUNT(*) as count FROM events')
241
+ .get();
242
+ expect(finalEventCount.count).toBeGreaterThan(initialEventCount.count);
243
+ const statusChangedEvents = db
244
+ .prepare("SELECT COUNT(*) as count FROM events WHERE type = 'status_changed'")
245
+ .get();
246
+ expect(statusChangedEvents.count).toBe(20);
247
+ });
248
+ });
249
+ describe('transaction atomicity', () => {
250
+ it('rolls back on error during event write', () => {
251
+ const task = taskService.createTask({ title: 'Test', project: 'stress-test' });
252
+ taskService.setStatus(task.task_id, TaskStatus.Ready);
253
+ const eventCountBefore = db
254
+ .prepare('SELECT COUNT(*) as count FROM events')
255
+ .get();
256
+ try {
257
+ taskService.claimTask(task.task_id, { author: 'test' });
258
+ taskService.claimTask(task.task_id, { author: 'another' });
259
+ }
260
+ catch {
261
+ // Expected
262
+ }
263
+ const eventCountAfter = db
264
+ .prepare('SELECT COUNT(*) as count FROM events')
265
+ .get();
266
+ expect(eventCountAfter.count).toBe(eventCountBefore.count + 1);
267
+ const taskRow = db
268
+ .prepare('SELECT status FROM tasks_current WHERE task_id = ?')
269
+ .get(task.task_id);
270
+ expect(taskRow.status).toBe('in_progress');
271
+ });
272
+ });
273
+ });
274
+ //# sourceMappingURL=stress.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stress.test.js","sourceRoot":"","sources":["../../../src/__tests__/concurrency/stress.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=worker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"worker.d.ts","sourceRoot":"","sources":["../../../src/__tests__/concurrency/worker.ts"],"names":[],"mappings":""}
@@ -0,0 +1,84 @@
1
+ // packages/hzl-core/src/__tests__/concurrency/worker.ts
2
+ // Worker script for concurrency stress tests
3
+ import { parentPort, workerData } from 'worker_threads';
4
+ import { createConnection } from '../../db/connection.js';
5
+ import { EventStore } from '../../events/store.js';
6
+ import { ProjectionEngine } from '../../projections/engine.js';
7
+ import { TasksCurrentProjector } from '../../projections/tasks-current.js';
8
+ import { DependenciesProjector } from '../../projections/dependencies.js';
9
+ import { TagsProjector } from '../../projections/tags.js';
10
+ import { TaskService } from '../../services/task-service.js';
11
+ const { dbPath, command } = workerData;
12
+ function setupServices(database) {
13
+ const eventStore = new EventStore(database);
14
+ const engine = new ProjectionEngine(database);
15
+ engine.register(new TasksCurrentProjector());
16
+ engine.register(new DependenciesProjector());
17
+ engine.register(new TagsProjector());
18
+ return {
19
+ eventStore,
20
+ engine,
21
+ taskService: new TaskService(database, eventStore, engine),
22
+ };
23
+ }
24
+ async function run() {
25
+ const db = createConnection(dbPath);
26
+ db.pragma('journal_mode = WAL');
27
+ db.pragma('busy_timeout = 5000');
28
+ const { taskService } = setupServices(db);
29
+ try {
30
+ switch (command.type) {
31
+ case 'claim-next': {
32
+ const leaseUntil = command.leaseMinutes
33
+ ? new Date(Date.now() + command.leaseMinutes * 60000).toISOString()
34
+ : undefined;
35
+ const task = taskService.claimNext({
36
+ project: command.project,
37
+ author: command.author,
38
+ lease_until: leaseUntil,
39
+ });
40
+ return { success: !!task, taskId: task?.task_id, operation: 'claim-next' };
41
+ }
42
+ case 'claim-specific': {
43
+ const leaseUntil = command.leaseMinutes
44
+ ? new Date(Date.now() + command.leaseMinutes * 60000).toISOString()
45
+ : undefined;
46
+ const task = taskService.claimTask(command.taskId, {
47
+ author: command.author,
48
+ lease_until: leaseUntil,
49
+ });
50
+ return { success: true, taskId: task.task_id, operation: 'claim-specific' };
51
+ }
52
+ case 'steal': {
53
+ const leaseUntil = command.leaseMinutes
54
+ ? new Date(Date.now() + command.leaseMinutes * 60000).toISOString()
55
+ : undefined;
56
+ const result = taskService.stealTask(command.taskId, {
57
+ ifExpired: command.ifExpired,
58
+ force: command.force,
59
+ author: command.author,
60
+ lease_until: leaseUntil,
61
+ });
62
+ return { success: result.success, taskId: command.taskId, operation: 'steal', error: result.error };
63
+ }
64
+ case 'complete': {
65
+ const task = taskService.completeTask(command.taskId, { author: command.author });
66
+ return { success: true, taskId: task.task_id, operation: 'complete' };
67
+ }
68
+ case 'release': {
69
+ const task = taskService.releaseTask(command.taskId, { author: command.author });
70
+ return { success: true, taskId: task.task_id, operation: 'release' };
71
+ }
72
+ default:
73
+ return { success: false, error: 'Unknown command', operation: command.type };
74
+ }
75
+ }
76
+ catch (err) {
77
+ return { success: false, error: err.message, operation: command.type };
78
+ }
79
+ finally {
80
+ db.close();
81
+ }
82
+ }
83
+ run().then((result) => parentPort?.postMessage(result));
84
+ //# sourceMappingURL=worker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"worker.js","sourceRoot":"","sources":["../../../src/__tests__/concurrency/worker.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=upgrade.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"upgrade.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/migrations/upgrade.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,203 @@
1
+ import { describe, it, expect, beforeEach, afterEach } from 'vitest';
2
+ import Database from 'better-sqlite3';
3
+ import fs from 'fs';
4
+ import path from 'path';
5
+ import os from 'os';
6
+ import { fileURLToPath } from 'url';
7
+ import { runMigrations, getCurrentVersion } from '../../db/migrations.js';
8
+ import { createConnection } from '../../db/connection.js';
9
+ const __filename = fileURLToPath(import.meta.url);
10
+ const __dirname = path.dirname(__filename);
11
+ describe('Migration Upgrade Tests', () => {
12
+ let tempDir;
13
+ let dbPath;
14
+ beforeEach(() => {
15
+ tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'hzl-migration-'));
16
+ dbPath = path.join(tempDir, 'test.db');
17
+ });
18
+ afterEach(() => {
19
+ fs.rmSync(tempDir, { recursive: true, force: true });
20
+ });
21
+ describe('v1 schema creation', () => {
22
+ it('creates all required tables', () => {
23
+ const db = createConnection(dbPath);
24
+ const tables = db
25
+ .prepare("SELECT name FROM sqlite_master WHERE type='table' ORDER BY name")
26
+ .all();
27
+ const tableNames = tables.map((t) => t.name);
28
+ expect(tableNames).toContain('events');
29
+ expect(tableNames).toContain('tasks_current');
30
+ expect(tableNames).toContain('task_dependencies');
31
+ expect(tableNames).toContain('task_tags');
32
+ expect(tableNames).toContain('task_comments');
33
+ expect(tableNames).toContain('task_checkpoints');
34
+ expect(tableNames).toContain('projection_state');
35
+ expect(tableNames).toContain('schema_migrations');
36
+ db.close();
37
+ });
38
+ it('creates all required indexes', () => {
39
+ const db = createConnection(dbPath);
40
+ const indexes = db
41
+ .prepare("SELECT name FROM sqlite_master WHERE type='index' AND name LIKE 'idx_%'")
42
+ .all();
43
+ const indexNames = indexes.map((i) => i.name);
44
+ expect(indexNames).toContain('idx_events_task_id');
45
+ expect(indexNames).toContain('idx_events_type');
46
+ expect(indexNames).toContain('idx_tasks_current_project_status');
47
+ expect(indexNames).toContain('idx_tasks_current_claim_next');
48
+ expect(indexNames).toContain('idx_deps_depends_on');
49
+ expect(indexNames).toContain('idx_task_tags_tag');
50
+ db.close();
51
+ });
52
+ it('sets correct schema version', () => {
53
+ const db = createConnection(dbPath);
54
+ const version = getCurrentVersion(db);
55
+ expect(version).toBe(1);
56
+ db.close();
57
+ });
58
+ });
59
+ describe('v1 fixture loading', () => {
60
+ it('loads v1 fixture and verifies data integrity', () => {
61
+ const db = new Database(dbPath);
62
+ const fixturePath = path.join(__dirname, 'fixtures', 'v1-sample.sql');
63
+ const fixtureSql = fs.readFileSync(fixturePath, 'utf-8');
64
+ db.exec(fixtureSql);
65
+ db.close();
66
+ const migratedDb = createConnection(dbPath);
67
+ const eventCount = migratedDb
68
+ .prepare('SELECT COUNT(*) as count FROM events')
69
+ .get();
70
+ expect(eventCount.count).toBeGreaterThan(0);
71
+ const taskCount = migratedDb
72
+ .prepare('SELECT COUNT(*) as count FROM tasks_current')
73
+ .get();
74
+ expect(taskCount.count).toBeGreaterThan(0);
75
+ const taskWithDeps = migratedDb
76
+ .prepare(`
77
+ SELECT tc.task_id, COUNT(td.depends_on_id) as dep_count
78
+ FROM tasks_current tc
79
+ LEFT JOIN task_dependencies td ON tc.task_id = td.task_id
80
+ GROUP BY tc.task_id
81
+ HAVING dep_count > 0
82
+ `)
83
+ .all();
84
+ expect(taskWithDeps.length).toBeGreaterThan(0);
85
+ migratedDb.close();
86
+ });
87
+ });
88
+ describe('v1 → v2 migration (future)', () => {
89
+ it('preserves all existing data after upgrade', async () => {
90
+ const db = createConnection(dbPath);
91
+ db.exec(`
92
+ INSERT INTO events (event_id, task_id, type, data, timestamp)
93
+ VALUES
94
+ ('EVT001', 'TASK001', 'task_created', '{"title":"Test task","project":"inbox"}', '2026-01-01T00:00:00Z'),
95
+ ('EVT002', 'TASK001', 'status_changed', '{"from":"backlog","to":"ready"}', '2026-01-01T00:01:00Z');
96
+
97
+ INSERT INTO tasks_current (task_id, title, project, status, links, tags, metadata, created_at, updated_at, last_event_id)
98
+ VALUES ('TASK001', 'Test task', 'inbox', 'ready', '[]', '["important"]', '{}', '2026-01-01T00:00:00Z', '2026-01-01T00:01:00Z', 2);
99
+
100
+ INSERT INTO task_tags (task_id, tag) VALUES ('TASK001', 'important');
101
+ `);
102
+ const preEventCount = db
103
+ .prepare('SELECT COUNT(*) as count FROM events')
104
+ .get();
105
+ const preTaskCount = db
106
+ .prepare('SELECT COUNT(*) as count FROM tasks_current')
107
+ .get();
108
+ db.close();
109
+ const migratedDb = createConnection(dbPath);
110
+ const postEventCount = migratedDb
111
+ .prepare('SELECT COUNT(*) as count FROM events')
112
+ .get();
113
+ const postTaskCount = migratedDb
114
+ .prepare('SELECT COUNT(*) as count FROM tasks_current')
115
+ .get();
116
+ expect(postEventCount.count).toBe(preEventCount.count);
117
+ expect(postTaskCount.count).toBe(preTaskCount.count);
118
+ const task = migratedDb
119
+ .prepare('SELECT * FROM tasks_current WHERE task_id = ?')
120
+ .get('TASK001');
121
+ expect(task.title).toBe('Test task');
122
+ expect(task.status).toBe('ready');
123
+ migratedDb.close();
124
+ });
125
+ it('handles empty database upgrade', () => {
126
+ const db = new Database(dbPath);
127
+ db.exec(`
128
+ CREATE TABLE schema_migrations (version INTEGER PRIMARY KEY, applied_at TEXT NOT NULL);
129
+ INSERT INTO schema_migrations (version, applied_at) VALUES (1, '2026-01-01T00:00:00Z');
130
+ `);
131
+ db.close();
132
+ const migratedDb = createConnection(dbPath);
133
+ const version = getCurrentVersion(migratedDb);
134
+ expect(version).toBeGreaterThanOrEqual(1);
135
+ migratedDb.close();
136
+ });
137
+ it('migration is idempotent', () => {
138
+ const db = createConnection(dbPath);
139
+ const version1 = getCurrentVersion(db);
140
+ db.close();
141
+ const db2 = createConnection(dbPath);
142
+ const version2 = getCurrentVersion(db2);
143
+ db2.close();
144
+ const db3 = createConnection(dbPath);
145
+ const version3 = getCurrentVersion(db3);
146
+ db3.close();
147
+ expect(version1).toBe(version2);
148
+ expect(version2).toBe(version3);
149
+ });
150
+ });
151
+ describe('migration rollback scenarios', () => {
152
+ it('fails gracefully on corrupted schema_migrations table', () => {
153
+ const db = new Database(dbPath);
154
+ db.exec(`
155
+ CREATE TABLE schema_migrations (version TEXT, applied_at TEXT);
156
+ INSERT INTO schema_migrations (version, applied_at) VALUES ('not_a_number', '2026-01-01');
157
+ `);
158
+ db.close();
159
+ const migratedDb = createConnection(dbPath);
160
+ const version = getCurrentVersion(migratedDb);
161
+ expect(version).toBeGreaterThanOrEqual(1);
162
+ migratedDb.close();
163
+ });
164
+ it('handles partial migration failure', () => {
165
+ const db = new Database(dbPath);
166
+ runMigrations(db);
167
+ db.exec('DROP TABLE IF EXISTS task_search');
168
+ db.close();
169
+ const reconnectedDb = createConnection(dbPath);
170
+ const ftsTable = reconnectedDb
171
+ .prepare("SELECT name FROM sqlite_master WHERE type='table' AND name='task_search'")
172
+ .get();
173
+ expect(ftsTable).toBeDefined();
174
+ reconnectedDb.close();
175
+ });
176
+ });
177
+ describe('schema version tracking', () => {
178
+ it('records migration timestamps', () => {
179
+ const db = createConnection(dbPath);
180
+ const migrations = db
181
+ .prepare('SELECT version, applied_at FROM schema_migrations ORDER BY version')
182
+ .all();
183
+ expect(migrations.length).toBeGreaterThan(0);
184
+ for (const m of migrations) {
185
+ expect(m.version).toBeGreaterThan(0);
186
+ expect(new Date(m.applied_at).getTime()).not.toBeNaN();
187
+ }
188
+ db.close();
189
+ });
190
+ it('does not re-run already applied migrations', () => {
191
+ const db = createConnection(dbPath);
192
+ db.exec("INSERT INTO projection_state (name, last_event_id, updated_at) VALUES ('test_marker', 999, '2026-01-01')");
193
+ db.close();
194
+ const db2 = createConnection(dbPath);
195
+ const marker = db2
196
+ .prepare("SELECT * FROM projection_state WHERE name = 'test_marker'")
197
+ .get();
198
+ expect(marker).toBeDefined();
199
+ db2.close();
200
+ });
201
+ });
202
+ });
203
+ //# sourceMappingURL=upgrade.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"upgrade.test.js","sourceRoot":"","sources":["../../../src/__tests__/migrations/upgrade.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=rebuild-equivalence.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rebuild-equivalence.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/projections/rebuild-equivalence.test.ts"],"names":[],"mappings":""}