@namzu/sdk 14.0.1 → 14.0.3
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.
- package/CHANGELOG.md +50 -0
- package/dist/manager/project/__tests__/a-closed-workspace-takes-no-work.test.js +40 -0
- package/dist/manager/project/__tests__/a-closed-workspace-takes-no-work.test.js.map +1 -1
- package/dist/manager/project/lifecycle.d.ts.map +1 -1
- package/dist/manager/project/lifecycle.js +17 -1
- package/dist/manager/project/lifecycle.js.map +1 -1
- package/dist/store/task/__tests__/an-edge-that-already-exists-is-not-news.test.d.ts +2 -0
- package/dist/store/task/__tests__/an-edge-that-already-exists-is-not-news.test.d.ts.map +1 -0
- package/dist/store/task/__tests__/an-edge-that-already-exists-is-not-news.test.js +95 -0
- package/dist/store/task/__tests__/an-edge-that-already-exists-is-not-news.test.js.map +1 -0
- package/dist/store/task/memory.d.ts.map +1 -1
- package/dist/store/task/memory.js +14 -2
- package/dist/store/task/memory.js.map +1 -1
- package/package.json +1 -1
- package/src/manager/project/__tests__/a-closed-workspace-takes-no-work.test.ts +46 -0
- package/src/manager/project/lifecycle.ts +19 -1
- package/src/store/task/__tests__/an-edge-that-already-exists-is-not-news.test.ts +115 -0
- package/src/store/task/memory.ts +13 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,55 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 14.0.3
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- c50f9bf: `ProjectManager.archive` refuses when it cannot establish the precondition.
|
|
8
|
+
|
|
9
|
+
14.0.0 shipped archival that "refuses rather than cascading" — a workspace with
|
|
10
|
+
a live session throws `ProjectNotEmptyError` instead of closing over running
|
|
11
|
+
work. The check read the session list as
|
|
12
|
+
`(await store.listSessionsByProject?.(...)) ?? []`, and `listSessionsByProject`
|
|
13
|
+
is optional. So on a store that does not implement it, "this store cannot tell
|
|
14
|
+
me what is running here" became "nothing is running here": the workspace closed
|
|
15
|
+
over live sessions and the call returned success.
|
|
16
|
+
|
|
17
|
+
It now throws, naming the missing method and what to do instead. Both stores in
|
|
18
|
+
this package implement it, so nothing in-tree changes; a host with its own
|
|
19
|
+
`SessionStore` gets a refusal where it previously got a wrong answer.
|
|
20
|
+
|
|
21
|
+
The mistake is worth naming, because the two halves are each correct and only
|
|
22
|
+
the combination is not. Optional-on-the-interface protects implementors: a
|
|
23
|
+
host's own store should not stop compiling because the SDK grew a method. It
|
|
24
|
+
cannot also mean a **safety precondition silently passes**. Where a store
|
|
25
|
+
cannot answer the question the check exists to ask, the answer is a refusal,
|
|
26
|
+
not a default.
|
|
27
|
+
|
|
28
|
+
## 14.0.2
|
|
29
|
+
|
|
30
|
+
### Patch Changes
|
|
31
|
+
|
|
32
|
+
- 9e03c89: `InMemoryTaskStore.block()` stops announcing an edge that already existed.
|
|
33
|
+
|
|
34
|
+
The two task stores disagreed about what `task.updated` means. `block()` is
|
|
35
|
+
idempotent on both — each guards its array against a duplicate entry — but only
|
|
36
|
+
the disk store guarded the _announcement_. Calling `block(a, b)` twice emitted
|
|
37
|
+
two `task.updated` events from the in-memory store and one from the disk store,
|
|
38
|
+
which is the one a host runs in production.
|
|
39
|
+
|
|
40
|
+
So a host rebuilding a dependency graph from the event stream did redundant
|
|
41
|
+
work against the reference implementation and not the durable one, and a host
|
|
42
|
+
counting events to detect change saw change where there was none. The
|
|
43
|
+
divergence is the kind that stays invisible until a store is swapped.
|
|
44
|
+
|
|
45
|
+
The disk store's behaviour was already correct and is now the behaviour of
|
|
46
|
+
both. No event is lost: a call that establishes a new edge — including one that
|
|
47
|
+
repairs a half-edge, where only one of the two arrays grows — still announces
|
|
48
|
+
both ends, because both ends are one fact.
|
|
49
|
+
|
|
50
|
+
The disk store's side of this had no test, which is why the disagreement
|
|
51
|
+
survived. Both are now driven from the same cases.
|
|
52
|
+
|
|
3
53
|
## 14.0.1
|
|
4
54
|
|
|
5
55
|
### Patch Changes
|
|
@@ -205,4 +205,44 @@ describe('a workspace stored before it had a status', () => {
|
|
|
205
205
|
expect(archived.status).toBe('archived');
|
|
206
206
|
});
|
|
207
207
|
});
|
|
208
|
+
describe('a store that cannot answer the precondition', () => {
|
|
209
|
+
/**
|
|
210
|
+
* `listSessionsByProject` is optional on `SessionStore` so a host's own
|
|
211
|
+
* store keeps compiling. The archive path read it as
|
|
212
|
+
* `(await store.listSessionsByProject?.(...)) ?? []`, which turned "this
|
|
213
|
+
* store cannot tell me what is running here" into "nothing is running
|
|
214
|
+
* here" — so a host with such a store closed a workspace over live
|
|
215
|
+
* sessions and got a success back. The refusal that the whole feature is
|
|
216
|
+
* about was skippable by not implementing one method.
|
|
217
|
+
*/
|
|
218
|
+
function storeWithoutTheListing(inner) {
|
|
219
|
+
const partial = {};
|
|
220
|
+
for (const key of [
|
|
221
|
+
'getProject',
|
|
222
|
+
'createProject',
|
|
223
|
+
'createSession',
|
|
224
|
+
'getSession',
|
|
225
|
+
'updateSession',
|
|
226
|
+
'setProjectStatus',
|
|
227
|
+
]) {
|
|
228
|
+
const fn = inner[key];
|
|
229
|
+
if (typeof fn === 'function')
|
|
230
|
+
partial[key] = fn.bind(inner);
|
|
231
|
+
}
|
|
232
|
+
return partial;
|
|
233
|
+
}
|
|
234
|
+
it('refuses to archive rather than assuming the workspace is empty', async () => {
|
|
235
|
+
const h = await harness();
|
|
236
|
+
await h.store.updateSession({ ...h.parentSession, status: 'active' }, TENANT);
|
|
237
|
+
const blind = new ProjectManager({ store: storeWithoutTheListing(h.store) });
|
|
238
|
+
await expect(blind.archive(h.project.id, TENANT)).rejects.toThrow(/listSessionsByProject/);
|
|
239
|
+
});
|
|
240
|
+
it('leaves the workspace open after refusing', async () => {
|
|
241
|
+
// The refusal has to happen before the write, or it is only a message.
|
|
242
|
+
const h = await harness();
|
|
243
|
+
const blind = new ProjectManager({ store: storeWithoutTheListing(h.store) });
|
|
244
|
+
await blind.archive(h.project.id, TENANT).catch(() => undefined);
|
|
245
|
+
expect((await h.store.getProject(h.project.id, TENANT))?.status).toBe('open');
|
|
246
|
+
});
|
|
247
|
+
});
|
|
208
248
|
//# sourceMappingURL=a-closed-workspace-takes-no-work.test.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"a-closed-workspace-takes-no-work.test.js","sourceRoot":"","sources":["../../../../src/manager/project/__tests__/a-closed-workspace-takes-no-work.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAA;AACnE,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAA;AAChC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAChC,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAA;AAExD,OAAO,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAA;AAChE,OAAO,EAAE,aAAa,EAAE,MAAM,wCAAwC,CAAA;AACtE,OAAO,EACN,kBAAkB,EAClB,oBAAoB,EACpB,iBAAiB,GACjB,MAAM,4BAA4B,CAAA;AACnC,OAAO,EAAE,wBAAwB,EAAE,MAAM,sCAAsC,CAAA;AAC/E,OAAO,EAAE,0BAA0B,EAAE,MAAM,yCAAyC,CAAA;AACpF,OAAO,EAAE,wBAAwB,EAAE,MAAM,wCAAwC,CAAA;AACjF,OAAO,EAAE,gBAAgB,EAAE,MAAM,gCAAgC,CAAA;AACjE,OAAO,EAAE,oBAAoB,EAAE,MAAM,kCAAkC,CAAA;AACvE,OAAO,EAAE,mBAAmB,EAAE,MAAM,iCAAiC,CAAA;
|
|
1
|
+
{"version":3,"file":"a-closed-workspace-takes-no-work.test.js","sourceRoot":"","sources":["../../../../src/manager/project/__tests__/a-closed-workspace-takes-no-work.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lifecycle.d.ts","sourceRoot":"","sources":["../../../src/manager/project/lifecycle.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAOH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAA;AACxD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,+BAA+B,CAAA;AAE5D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,4BAA4B,CAAA;AAC3D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAA;AAgBhE;;;;;;;;;;GAUG;AACH,wBAAsB,kBAAkB,CACvC,KAAK,EAAE,IAAI,CAAC,YAAY,EAAE,YAAY,CAAC,EACvC,SAAS,EAAE,SAAS,EACpB,QAAQ,EAAE,QAAQ,EAClB,EAAE,EAAE,MAAM,GACR,OAAO,CAAC,OAAO,CAAC,CASlB;AAED,MAAM,WAAW,kBAAkB;IAClC,KAAK,EAAE,YAAY,CAAA;CACnB;AAED,qBAAa,cAAc;IACd,OAAO,CAAC,QAAQ,CAAC,IAAI;gBAAJ,IAAI,EAAE,kBAAkB;IAErD,sCAAsC;IACtC,WAAW,CAAC,SAAS,EAAE,SAAS,EAAE,QAAQ,EAAE,QAAQ,EAAE,EAAE,SAAiB,GAAG,OAAO,CAAC,OAAO,CAAC;IAI5F;;;;;;;;;;;;;OAaG;IACG,OAAO,CAAC,SAAS,EAAE,SAAS,EAAE,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"lifecycle.d.ts","sourceRoot":"","sources":["../../../src/manager/project/lifecycle.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAOH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAA;AACxD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,+BAA+B,CAAA;AAE5D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,4BAA4B,CAAA;AAC3D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAA;AAgBhE;;;;;;;;;;GAUG;AACH,wBAAsB,kBAAkB,CACvC,KAAK,EAAE,IAAI,CAAC,YAAY,EAAE,YAAY,CAAC,EACvC,SAAS,EAAE,SAAS,EACpB,QAAQ,EAAE,QAAQ,EAClB,EAAE,EAAE,MAAM,GACR,OAAO,CAAC,OAAO,CAAC,CASlB;AAED,MAAM,WAAW,kBAAkB;IAClC,KAAK,EAAE,YAAY,CAAA;CACnB;AAED,qBAAa,cAAc;IACd,OAAO,CAAC,QAAQ,CAAC,IAAI;gBAAJ,IAAI,EAAE,kBAAkB;IAErD,sCAAsC;IACtC,WAAW,CAAC,SAAS,EAAE,SAAS,EAAE,QAAQ,EAAE,QAAQ,EAAE,EAAE,SAAiB,GAAG,OAAO,CAAC,OAAO,CAAC;IAI5F;;;;;;;;;;;;;OAaG;IACG,OAAO,CAAC,SAAS,EAAE,SAAS,EAAE,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC;IA0CzE;;;;OAIG;IACG,MAAM,CAAC,SAAS,EAAE,SAAS,EAAE,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC;YAS1D,KAAK;CAwBnB"}
|
|
@@ -79,7 +79,23 @@ export class ProjectManager {
|
|
|
79
79
|
if (!project) {
|
|
80
80
|
throw new Error(`Project ${projectId} not found for tenant ${tenantId} — archive rejected`);
|
|
81
81
|
}
|
|
82
|
-
|
|
82
|
+
// An unanswerable precondition is a refusal, not an empty answer.
|
|
83
|
+
//
|
|
84
|
+
// This read used to be `?? []`, which turned "this store cannot tell me
|
|
85
|
+
// what is running here" into "nothing is running here": a store without
|
|
86
|
+
// the optional method archived the workspace over live sessions and
|
|
87
|
+
// reported success. The whole point of the check is that archival does
|
|
88
|
+
// not cascade over running work, and the check was skippable by any
|
|
89
|
+
// store that had not implemented one optional method.
|
|
90
|
+
//
|
|
91
|
+
// Optional on the interface protects implementors — a host's own store
|
|
92
|
+
// should not stop compiling because the SDK grew a method. It cannot
|
|
93
|
+
// also mean a safety precondition silently passes.
|
|
94
|
+
const listByProject = this.deps.store.listSessionsByProject;
|
|
95
|
+
if (!listByProject) {
|
|
96
|
+
throw new Error(`Project ${projectId} cannot be archived: this SessionStore does not implement listSessionsByProject, so whether a session is still running in the workspace cannot be established. Implement it, or settle and verify the sessions through your own path before closing the workspace.`);
|
|
97
|
+
}
|
|
98
|
+
const sessions = await listByProject.call(this.deps.store, projectId, tenantId);
|
|
83
99
|
const blocking = sessions.filter((s) => ARCHIVAL_BLOCKING_STATUSES.has(s.status));
|
|
84
100
|
if (blocking.length > 0) {
|
|
85
101
|
throw new ProjectNotEmptyError({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lifecycle.js","sourceRoot":"","sources":["../../../src/manager/project/lifecycle.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,EACN,8BAA8B,EAC9B,kBAAkB,EAClB,oBAAoB,GACpB,MAAM,yBAAyB,CAAA;AAOhC;;;;;;GAMG;AACH,MAAM,0BAA0B,GAA+B,IAAI,GAAG,CAAC;IACtE,QAAQ;IACR,QAAQ;IACR,gBAAgB;IAChB,eAAe;CACf,CAAC,CAAA;AAEF;;;;;;;;;;GAUG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACvC,KAAuC,EACvC,SAAoB,EACpB,QAAkB,EAClB,EAAU;IAEV,MAAM,OAAO,GAAG,MAAM,KAAK,CAAC,UAAU,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAA;IAC3D,IAAI,CAAC,OAAO,EAAE,CAAC;QACd,MAAM,IAAI,KAAK,CAAC,WAAW,SAAS,yBAAyB,QAAQ,MAAM,EAAE,WAAW,CAAC,CAAA;IAC1F,CAAC;IACD,IAAI,OAAO,CAAC,MAAM,KAAK,UAAU,EAAE,CAAC;QACnC,MAAM,IAAI,kBAAkB,CAAC,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC,CAAA;IAChD,CAAC;IACD,OAAO,OAAO,CAAA;AACf,CAAC;AAMD,MAAM,OAAO,cAAc;IACG;IAA7B,YAA6B,IAAwB;QAAxB,SAAI,GAAJ,IAAI,CAAoB;IAAG,CAAC;IAEzD,sCAAsC;IACtC,WAAW,CAAC,SAAoB,EAAE,QAAkB,EAAE,EAAE,GAAG,cAAc;QACxE,OAAO,kBAAkB,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,EAAE,CAAC,CAAA;IACpE,CAAC;IAED;;;;;;;;;;;;;OAaG;IACH,KAAK,CAAC,OAAO,CAAC,SAAoB,EAAE,QAAkB;QACrD,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAA;QACrE,IAAI,CAAC,OAAO,EAAE,CAAC;YACd,MAAM,IAAI,KAAK,CAAC,WAAW,SAAS,yBAAyB,QAAQ,qBAAqB,CAAC,CAAA;QAC5F,CAAC;QAED,
|
|
1
|
+
{"version":3,"file":"lifecycle.js","sourceRoot":"","sources":["../../../src/manager/project/lifecycle.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"an-edge-that-already-exists-is-not-news.test.d.ts","sourceRoot":"","sources":["../../../../src/store/task/__tests__/an-edge-that-already-exists-is-not-news.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { mkdtemp, rm } from 'node:fs/promises';
|
|
2
|
+
import { tmpdir } from 'node:os';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { afterEach, describe, expect, it } from 'vitest';
|
|
5
|
+
import { DiskTaskStore } from '../disk.js';
|
|
6
|
+
import { InMemoryTaskStore } from '../memory.js';
|
|
7
|
+
/**
|
|
8
|
+
* The two stores disagreed about what `task.updated` means.
|
|
9
|
+
*
|
|
10
|
+
* `block()` is idempotent on both — it guards each array against a duplicate
|
|
11
|
+
* entry — but only the disk store guarded the *announcement*. Calling
|
|
12
|
+
* `block(a, b)` twice emitted two `task.updated` events from the in-memory
|
|
13
|
+
* store and one from the disk store, which is the one a host runs in
|
|
14
|
+
* production. So a host rebuilding a dependency graph from the stream did
|
|
15
|
+
* redundant work against the reference implementation and not the durable one,
|
|
16
|
+
* and a host counting events to detect change saw change where there was none.
|
|
17
|
+
*
|
|
18
|
+
* The disk store's behaviour is the correct one and the in-memory store now
|
|
19
|
+
* matches it: an edge that already existed is not news.
|
|
20
|
+
*
|
|
21
|
+
* Both are driven from the same cases here, because a reference implementation
|
|
22
|
+
* that disagrees with the durable one is worse than having only one — the
|
|
23
|
+
* disagreement is invisible until a host swaps stores in production.
|
|
24
|
+
*/
|
|
25
|
+
const RUN = 'run_edge';
|
|
26
|
+
const dirs = [];
|
|
27
|
+
afterEach(async () => {
|
|
28
|
+
await Promise.all(dirs.map((d) => rm(d, { recursive: true, force: true })));
|
|
29
|
+
dirs.length = 0;
|
|
30
|
+
});
|
|
31
|
+
async function diskStore() {
|
|
32
|
+
const dir = await mkdtemp(join(tmpdir(), 'namzu-edge-'));
|
|
33
|
+
dirs.push(dir);
|
|
34
|
+
return new DiskTaskStore({ baseDir: dir, defaultRunId: RUN });
|
|
35
|
+
}
|
|
36
|
+
const IMPLEMENTATIONS = [
|
|
37
|
+
['in memory', async () => new InMemoryTaskStore()],
|
|
38
|
+
['on disk', diskStore],
|
|
39
|
+
];
|
|
40
|
+
describe.each(IMPLEMENTATIONS)('an edge that already exists is not news (%s)', (_n, build) => {
|
|
41
|
+
async function twoTasks(store) {
|
|
42
|
+
const blocker = await store.create({ runId: RUN, subject: 'blocker' });
|
|
43
|
+
const blocked = await store.create({ runId: RUN, subject: 'blocked' });
|
|
44
|
+
return { blocker, blocked };
|
|
45
|
+
}
|
|
46
|
+
function recordUpdates(store) {
|
|
47
|
+
const seen = [];
|
|
48
|
+
store.on((event) => {
|
|
49
|
+
if (event.type === 'task.updated')
|
|
50
|
+
seen.push(event);
|
|
51
|
+
});
|
|
52
|
+
return seen;
|
|
53
|
+
}
|
|
54
|
+
it('announces both ends when the edge is written', async () => {
|
|
55
|
+
// The control: without it, "no second announcement" could be passing
|
|
56
|
+
// because nothing announces at all.
|
|
57
|
+
const store = await build();
|
|
58
|
+
const { blocker, blocked } = await twoTasks(store);
|
|
59
|
+
const seen = recordUpdates(store);
|
|
60
|
+
await store.block(blocker.id, blocked.id);
|
|
61
|
+
expect(seen.map((e) => e.taskId)).toEqual([blocker.id, blocked.id]);
|
|
62
|
+
});
|
|
63
|
+
it('says nothing the second time', async () => {
|
|
64
|
+
const store = await build();
|
|
65
|
+
const { blocker, blocked } = await twoTasks(store);
|
|
66
|
+
await store.block(blocker.id, blocked.id);
|
|
67
|
+
const seen = recordUpdates(store);
|
|
68
|
+
await store.block(blocker.id, blocked.id);
|
|
69
|
+
expect(seen).toEqual([]);
|
|
70
|
+
});
|
|
71
|
+
it('still records the edge exactly once after a repeated call', async () => {
|
|
72
|
+
// Suppressing the event must not become suppressing the write, and the
|
|
73
|
+
// arrays must not grow a duplicate.
|
|
74
|
+
const store = await build();
|
|
75
|
+
const { blocker, blocked } = await twoTasks(store);
|
|
76
|
+
await store.block(blocker.id, blocked.id);
|
|
77
|
+
await store.block(blocker.id, blocked.id);
|
|
78
|
+
expect((await store.get(blocker.id))?.blocks).toEqual([blocked.id]);
|
|
79
|
+
expect((await store.get(blocked.id))?.blockedBy).toEqual([blocker.id]);
|
|
80
|
+
});
|
|
81
|
+
it('announces a repair when only one side of the edge was missing', async () => {
|
|
82
|
+
// A half-edge is the case the early return must not swallow: one array
|
|
83
|
+
// already names the other and its counterpart does not. Both ends are
|
|
84
|
+
// one fact, so both are announced even though only one array grew.
|
|
85
|
+
const store = await build();
|
|
86
|
+
const { blocker, blocked } = await twoTasks(store);
|
|
87
|
+
await store.block(blocker.id, blocked.id);
|
|
88
|
+
// Reverse direction: `blocked` has not yet been recorded as blocking
|
|
89
|
+
// `blocker`, so this is a new edge, not the existing one.
|
|
90
|
+
const seen = recordUpdates(store);
|
|
91
|
+
await store.block(blocked.id, blocker.id);
|
|
92
|
+
expect(seen.map((e) => e.taskId)).toEqual([blocked.id, blocker.id]);
|
|
93
|
+
});
|
|
94
|
+
});
|
|
95
|
+
//# sourceMappingURL=an-edge-that-already-exists-is-not-news.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"an-edge-that-already-exists-is-not-news.test.js","sourceRoot":"","sources":["../../../../src/store/task/__tests__/an-edge-that-already-exists-is-not-news.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,EAAE,EAAE,MAAM,kBAAkB,CAAA;AAC9C,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAA;AAChC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAChC,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAA;AAIxD,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAC1C,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAA;AAEhD;;;;;;;;;;;;;;;;;GAiBG;AAEH,MAAM,GAAG,GAAG,UAAmB,CAAA;AAE/B,MAAM,IAAI,GAAa,EAAE,CAAA;AACzB,SAAS,CAAC,KAAK,IAAI,EAAE;IACpB,MAAM,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAA;IAC3E,IAAI,CAAC,MAAM,GAAG,CAAC,CAAA;AAChB,CAAC,CAAC,CAAA;AAEF,KAAK,UAAU,SAAS;IACvB,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,aAAa,CAAC,CAAC,CAAA;IACxD,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;IACd,OAAO,IAAI,aAAa,CAAC,EAAE,OAAO,EAAE,GAAG,EAAE,YAAY,EAAE,GAAG,EAAE,CAAC,CAAA;AAC9D,CAAC;AAED,MAAM,eAAe,GAA+D;IACnF,CAAC,WAAW,EAAE,KAAK,IAAI,EAAE,CAAC,IAAI,iBAAiB,EAAE,CAAC;IAClD,CAAC,SAAS,EAAE,SAAS,CAAC;CACtB,CAAA;AAED,QAAQ,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC,8CAA8C,EAAE,CAAC,EAAE,EAAE,KAAK,EAAE,EAAE;IAC5F,KAAK,UAAU,QAAQ,CAAC,KAAgB;QACvC,MAAM,OAAO,GAAG,MAAM,KAAK,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,GAAG,EAAE,OAAO,EAAE,SAAS,EAAE,CAAC,CAAA;QACtE,MAAM,OAAO,GAAG,MAAM,KAAK,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,GAAG,EAAE,OAAO,EAAE,SAAS,EAAE,CAAC,CAAA;QACtE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,CAAA;IAC5B,CAAC;IAED,SAAS,aAAa,CAAC,KAAgB;QACtC,MAAM,IAAI,GAAgB,EAAE,CAAA;QAC5B,KAAK,CAAC,EAAE,CAAC,CAAC,KAAK,EAAE,EAAE;YAClB,IAAI,KAAK,CAAC,IAAI,KAAK,cAAc;gBAAE,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;QACpD,CAAC,CAAC,CAAA;QACF,OAAO,IAAI,CAAA;IACZ,CAAC;IAED,EAAE,CAAC,8CAA8C,EAAE,KAAK,IAAI,EAAE;QAC7D,qEAAqE;QACrE,oCAAoC;QACpC,MAAM,KAAK,GAAG,MAAM,KAAK,EAAE,CAAA;QAC3B,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,MAAM,QAAQ,CAAC,KAAK,CAAC,CAAA;QAClD,MAAM,IAAI,GAAG,aAAa,CAAC,KAAK,CAAC,CAAA;QAEjC,MAAM,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,EAAE,OAAO,CAAC,EAAE,CAAC,CAAA;QAEzC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,EAAE,EAAE,OAAO,CAAC,EAAE,CAAC,CAAC,CAAA;IACpE,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,8BAA8B,EAAE,KAAK,IAAI,EAAE;QAC7C,MAAM,KAAK,GAAG,MAAM,KAAK,EAAE,CAAA;QAC3B,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,MAAM,QAAQ,CAAC,KAAK,CAAC,CAAA;QAClD,MAAM,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,EAAE,OAAO,CAAC,EAAE,CAAC,CAAA;QACzC,MAAM,IAAI,GAAG,aAAa,CAAC,KAAK,CAAC,CAAA;QAEjC,MAAM,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,EAAE,OAAO,CAAC,EAAE,CAAC,CAAA;QAEzC,MAAM,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAA;IACzB,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,2DAA2D,EAAE,KAAK,IAAI,EAAE;QAC1E,uEAAuE;QACvE,oCAAoC;QACpC,MAAM,KAAK,GAAG,MAAM,KAAK,EAAE,CAAA;QAC3B,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,MAAM,QAAQ,CAAC,KAAK,CAAC,CAAA;QAElD,MAAM,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,EAAE,OAAO,CAAC,EAAE,CAAC,CAAA;QACzC,MAAM,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,EAAE,OAAO,CAAC,EAAE,CAAC,CAAA;QAEzC,MAAM,CAAC,CAAC,MAAM,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAA;QACnE,MAAM,CAAC,CAAC,MAAM,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAA;IACvE,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,+DAA+D,EAAE,KAAK,IAAI,EAAE;QAC9E,uEAAuE;QACvE,sEAAsE;QACtE,mEAAmE;QACnE,MAAM,KAAK,GAAG,MAAM,KAAK,EAAE,CAAA;QAC3B,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,MAAM,QAAQ,CAAC,KAAK,CAAC,CAAA;QAClD,MAAM,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,EAAE,OAAO,CAAC,EAAE,CAAC,CAAA;QACzC,qEAAqE;QACrE,0DAA0D;QAC1D,MAAM,IAAI,GAAG,aAAa,CAAC,KAAK,CAAC,CAAA;QAEjC,MAAM,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,EAAE,OAAO,CAAC,EAAE,CAAC,CAAA;QAEzC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,EAAE,EAAE,OAAO,CAAC,EAAE,CAAC,CAAC,CAAA;IACpE,CAAC,CAAC,CAAA;AACH,CAAC,CAAC,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"memory.d.ts","sourceRoot":"","sources":["../../../src/store/task/memory.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,0BAA0B,CAAA;AAC7D,OAAO,KAAK,EACX,gBAAgB,EAChB,IAAI,EAEJ,iBAAiB,EACjB,UAAU,EACV,SAAS,EACT,gBAAgB,EAChB,MAAM,2BAA2B,CAAA;AAmBlC,qBAAa,iBAAkB,YAAW,SAAS;IAClD,OAAO,CAAC,KAAK,CAA0B;IACvC,OAAO,CAAC,SAAS,CAA0B;IAE3C,EAAE,CAAC,QAAQ,EAAE,iBAAiB,GAAG,MAAM,IAAI;IAO3C,OAAO,CAAC,IAAI;IAQN,MAAM,CAAC,MAAM,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC;IA+B/C,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,GAAG,SAAS,CAAC;IAI1C,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,GAAG,SAAS,CAAC;IAwCxE,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAsBpC,IAAI,CAAC,MAAM,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,UAAU,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,KAAK,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC;IAgBtF,KAAK,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,GAAG,SAAS,CAAC;IAc3D,KAAK,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"memory.d.ts","sourceRoot":"","sources":["../../../src/store/task/memory.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,0BAA0B,CAAA;AAC7D,OAAO,KAAK,EACX,gBAAgB,EAChB,IAAI,EAEJ,iBAAiB,EACjB,UAAU,EACV,SAAS,EACT,gBAAgB,EAChB,MAAM,2BAA2B,CAAA;AAmBlC,qBAAa,iBAAkB,YAAW,SAAS;IAClD,OAAO,CAAC,KAAK,CAA0B;IACvC,OAAO,CAAC,SAAS,CAA0B;IAE3C,EAAE,CAAC,QAAQ,EAAE,iBAAiB,GAAG,MAAM,IAAI;IAO3C,OAAO,CAAC,IAAI;IAQN,MAAM,CAAC,MAAM,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC;IA+B/C,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,GAAG,SAAS,CAAC;IAI1C,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,GAAG,SAAS,CAAC;IAwCxE,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAsBpC,IAAI,CAAC,MAAM,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,UAAU,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,KAAK,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC;IAgBtF,KAAK,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,GAAG,SAAS,CAAC;IAc3D,KAAK,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAiC1D,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAG5B"}
|
|
@@ -150,17 +150,29 @@ export class InMemoryTaskStore {
|
|
|
150
150
|
const blocked = this.tasks.get(blockedId);
|
|
151
151
|
if (!blocker || !blocked)
|
|
152
152
|
return;
|
|
153
|
+
let mutated = false;
|
|
153
154
|
if (!blocker.blocks.includes(blockedId)) {
|
|
154
155
|
blocker.blocks.push(blockedId);
|
|
156
|
+
mutated = true;
|
|
155
157
|
}
|
|
156
158
|
if (!blocked.blockedBy.includes(blockerId)) {
|
|
157
159
|
blocked.blockedBy.push(blockerId);
|
|
160
|
+
mutated = true;
|
|
158
161
|
}
|
|
162
|
+
// An edge that already existed is not news. This used to announce
|
|
163
|
+
// unconditionally while the disk store — the one a host runs in
|
|
164
|
+
// production — returned early, so the same call sequence produced two
|
|
165
|
+
// events from one implementation and none from the other. A host
|
|
166
|
+
// rebuilding a graph from the stream did redundant work against one
|
|
167
|
+
// store and not the other, and a host counting events to detect change
|
|
168
|
+
// saw change where there was none.
|
|
169
|
+
if (!mutated)
|
|
170
|
+
return;
|
|
159
171
|
// Announce BOTH ends. The edge was written and nothing said so, which
|
|
160
172
|
// left the graph observable only by polling: a listener saw a unit
|
|
161
173
|
// created and never learned that something now waits on it. Both sides
|
|
162
|
-
//
|
|
163
|
-
// half the edge.
|
|
174
|
+
// are one fact, so both are announced even when only one array grew —
|
|
175
|
+
// a host tracking a single side would draw half the edge.
|
|
164
176
|
const now = Date.now();
|
|
165
177
|
this.emit({ type: 'task.updated', taskId: blockerId, task: blocker, timestamp: now });
|
|
166
178
|
this.emit({ type: 'task.updated', taskId: blockedId, task: blocked, timestamp: now });
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"memory.js","sourceRoot":"","sources":["../../../src/store/task/memory.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"memory.js","sourceRoot":"","sources":["../../../src/store/task/memory.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -22,6 +22,7 @@ import type { AgentDefinition } from '../../../types/agent/factory.js'
|
|
|
22
22
|
import type { AgentTaskContext } from '../../../types/agent/task.js'
|
|
23
23
|
import type { AgentId, TenantId } from '../../../types/ids/index.js'
|
|
24
24
|
import type { SummaryId } from '../../../types/session/ids.js'
|
|
25
|
+
import type { SessionStore } from '../../../types/session/store.js'
|
|
25
26
|
import { ZERO_COST } from '../../../utils/cost.js'
|
|
26
27
|
import { AgentManager } from '../../agent/lifecycle.js'
|
|
27
28
|
import { ThreadManager } from '../../thread/lifecycle.js'
|
|
@@ -266,3 +267,48 @@ describe('a workspace stored before it had a status', () => {
|
|
|
266
267
|
expect(archived.status).toBe('archived')
|
|
267
268
|
})
|
|
268
269
|
})
|
|
270
|
+
|
|
271
|
+
describe('a store that cannot answer the precondition', () => {
|
|
272
|
+
/**
|
|
273
|
+
* `listSessionsByProject` is optional on `SessionStore` so a host's own
|
|
274
|
+
* store keeps compiling. The archive path read it as
|
|
275
|
+
* `(await store.listSessionsByProject?.(...)) ?? []`, which turned "this
|
|
276
|
+
* store cannot tell me what is running here" into "nothing is running
|
|
277
|
+
* here" — so a host with such a store closed a workspace over live
|
|
278
|
+
* sessions and got a success back. The refusal that the whole feature is
|
|
279
|
+
* about was skippable by not implementing one method.
|
|
280
|
+
*/
|
|
281
|
+
function storeWithoutTheListing(inner: SessionStore): SessionStore {
|
|
282
|
+
const partial: Record<string, unknown> = {}
|
|
283
|
+
for (const key of [
|
|
284
|
+
'getProject',
|
|
285
|
+
'createProject',
|
|
286
|
+
'createSession',
|
|
287
|
+
'getSession',
|
|
288
|
+
'updateSession',
|
|
289
|
+
'setProjectStatus',
|
|
290
|
+
]) {
|
|
291
|
+
const fn = (inner as unknown as Record<string, unknown>)[key]
|
|
292
|
+
if (typeof fn === 'function') partial[key] = (fn as (...a: unknown[]) => unknown).bind(inner)
|
|
293
|
+
}
|
|
294
|
+
return partial as unknown as SessionStore
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
it('refuses to archive rather than assuming the workspace is empty', async () => {
|
|
298
|
+
const h = await harness()
|
|
299
|
+
await h.store.updateSession({ ...h.parentSession, status: 'active' }, TENANT)
|
|
300
|
+
const blind = new ProjectManager({ store: storeWithoutTheListing(h.store) })
|
|
301
|
+
|
|
302
|
+
await expect(blind.archive(h.project.id, TENANT)).rejects.toThrow(/listSessionsByProject/)
|
|
303
|
+
})
|
|
304
|
+
|
|
305
|
+
it('leaves the workspace open after refusing', async () => {
|
|
306
|
+
// The refusal has to happen before the write, or it is only a message.
|
|
307
|
+
const h = await harness()
|
|
308
|
+
const blind = new ProjectManager({ store: storeWithoutTheListing(h.store) })
|
|
309
|
+
|
|
310
|
+
await blind.archive(h.project.id, TENANT).catch(() => undefined)
|
|
311
|
+
|
|
312
|
+
expect((await h.store.getProject(h.project.id, TENANT))?.status).toBe('open')
|
|
313
|
+
})
|
|
314
|
+
})
|
|
@@ -101,7 +101,25 @@ export class ProjectManager {
|
|
|
101
101
|
throw new Error(`Project ${projectId} not found for tenant ${tenantId} — archive rejected`)
|
|
102
102
|
}
|
|
103
103
|
|
|
104
|
-
|
|
104
|
+
// An unanswerable precondition is a refusal, not an empty answer.
|
|
105
|
+
//
|
|
106
|
+
// This read used to be `?? []`, which turned "this store cannot tell me
|
|
107
|
+
// what is running here" into "nothing is running here": a store without
|
|
108
|
+
// the optional method archived the workspace over live sessions and
|
|
109
|
+
// reported success. The whole point of the check is that archival does
|
|
110
|
+
// not cascade over running work, and the check was skippable by any
|
|
111
|
+
// store that had not implemented one optional method.
|
|
112
|
+
//
|
|
113
|
+
// Optional on the interface protects implementors — a host's own store
|
|
114
|
+
// should not stop compiling because the SDK grew a method. It cannot
|
|
115
|
+
// also mean a safety precondition silently passes.
|
|
116
|
+
const listByProject = this.deps.store.listSessionsByProject
|
|
117
|
+
if (!listByProject) {
|
|
118
|
+
throw new Error(
|
|
119
|
+
`Project ${projectId} cannot be archived: this SessionStore does not implement listSessionsByProject, so whether a session is still running in the workspace cannot be established. Implement it, or settle and verify the sessions through your own path before closing the workspace.`,
|
|
120
|
+
)
|
|
121
|
+
}
|
|
122
|
+
const sessions = await listByProject.call(this.deps.store, projectId, tenantId)
|
|
105
123
|
const blocking = sessions.filter((s) => ARCHIVAL_BLOCKING_STATUSES.has(s.status))
|
|
106
124
|
if (blocking.length > 0) {
|
|
107
125
|
throw new ProjectNotEmptyError({
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { mkdtemp, rm } from 'node:fs/promises'
|
|
2
|
+
import { tmpdir } from 'node:os'
|
|
3
|
+
import { join } from 'node:path'
|
|
4
|
+
import { afterEach, describe, expect, it } from 'vitest'
|
|
5
|
+
|
|
6
|
+
import type { RunId } from '../../../types/ids/index.js'
|
|
7
|
+
import type { TaskEvent, TaskStore } from '../../../types/task/index.js'
|
|
8
|
+
import { DiskTaskStore } from '../disk.js'
|
|
9
|
+
import { InMemoryTaskStore } from '../memory.js'
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* The two stores disagreed about what `task.updated` means.
|
|
13
|
+
*
|
|
14
|
+
* `block()` is idempotent on both — it guards each array against a duplicate
|
|
15
|
+
* entry — but only the disk store guarded the *announcement*. Calling
|
|
16
|
+
* `block(a, b)` twice emitted two `task.updated` events from the in-memory
|
|
17
|
+
* store and one from the disk store, which is the one a host runs in
|
|
18
|
+
* production. So a host rebuilding a dependency graph from the stream did
|
|
19
|
+
* redundant work against the reference implementation and not the durable one,
|
|
20
|
+
* and a host counting events to detect change saw change where there was none.
|
|
21
|
+
*
|
|
22
|
+
* The disk store's behaviour is the correct one and the in-memory store now
|
|
23
|
+
* matches it: an edge that already existed is not news.
|
|
24
|
+
*
|
|
25
|
+
* Both are driven from the same cases here, because a reference implementation
|
|
26
|
+
* that disagrees with the durable one is worse than having only one — the
|
|
27
|
+
* disagreement is invisible until a host swaps stores in production.
|
|
28
|
+
*/
|
|
29
|
+
|
|
30
|
+
const RUN = 'run_edge' as RunId
|
|
31
|
+
|
|
32
|
+
const dirs: string[] = []
|
|
33
|
+
afterEach(async () => {
|
|
34
|
+
await Promise.all(dirs.map((d) => rm(d, { recursive: true, force: true })))
|
|
35
|
+
dirs.length = 0
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
async function diskStore(): Promise<TaskStore> {
|
|
39
|
+
const dir = await mkdtemp(join(tmpdir(), 'namzu-edge-'))
|
|
40
|
+
dirs.push(dir)
|
|
41
|
+
return new DiskTaskStore({ baseDir: dir, defaultRunId: RUN })
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const IMPLEMENTATIONS: ReadonlyArray<readonly [string, () => Promise<TaskStore>]> = [
|
|
45
|
+
['in memory', async () => new InMemoryTaskStore()],
|
|
46
|
+
['on disk', diskStore],
|
|
47
|
+
]
|
|
48
|
+
|
|
49
|
+
describe.each(IMPLEMENTATIONS)('an edge that already exists is not news (%s)', (_n, build) => {
|
|
50
|
+
async function twoTasks(store: TaskStore) {
|
|
51
|
+
const blocker = await store.create({ runId: RUN, subject: 'blocker' })
|
|
52
|
+
const blocked = await store.create({ runId: RUN, subject: 'blocked' })
|
|
53
|
+
return { blocker, blocked }
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function recordUpdates(store: TaskStore): TaskEvent[] {
|
|
57
|
+
const seen: TaskEvent[] = []
|
|
58
|
+
store.on((event) => {
|
|
59
|
+
if (event.type === 'task.updated') seen.push(event)
|
|
60
|
+
})
|
|
61
|
+
return seen
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
it('announces both ends when the edge is written', async () => {
|
|
65
|
+
// The control: without it, "no second announcement" could be passing
|
|
66
|
+
// because nothing announces at all.
|
|
67
|
+
const store = await build()
|
|
68
|
+
const { blocker, blocked } = await twoTasks(store)
|
|
69
|
+
const seen = recordUpdates(store)
|
|
70
|
+
|
|
71
|
+
await store.block(blocker.id, blocked.id)
|
|
72
|
+
|
|
73
|
+
expect(seen.map((e) => e.taskId)).toEqual([blocker.id, blocked.id])
|
|
74
|
+
})
|
|
75
|
+
|
|
76
|
+
it('says nothing the second time', async () => {
|
|
77
|
+
const store = await build()
|
|
78
|
+
const { blocker, blocked } = await twoTasks(store)
|
|
79
|
+
await store.block(blocker.id, blocked.id)
|
|
80
|
+
const seen = recordUpdates(store)
|
|
81
|
+
|
|
82
|
+
await store.block(blocker.id, blocked.id)
|
|
83
|
+
|
|
84
|
+
expect(seen).toEqual([])
|
|
85
|
+
})
|
|
86
|
+
|
|
87
|
+
it('still records the edge exactly once after a repeated call', async () => {
|
|
88
|
+
// Suppressing the event must not become suppressing the write, and the
|
|
89
|
+
// arrays must not grow a duplicate.
|
|
90
|
+
const store = await build()
|
|
91
|
+
const { blocker, blocked } = await twoTasks(store)
|
|
92
|
+
|
|
93
|
+
await store.block(blocker.id, blocked.id)
|
|
94
|
+
await store.block(blocker.id, blocked.id)
|
|
95
|
+
|
|
96
|
+
expect((await store.get(blocker.id))?.blocks).toEqual([blocked.id])
|
|
97
|
+
expect((await store.get(blocked.id))?.blockedBy).toEqual([blocker.id])
|
|
98
|
+
})
|
|
99
|
+
|
|
100
|
+
it('announces a repair when only one side of the edge was missing', async () => {
|
|
101
|
+
// A half-edge is the case the early return must not swallow: one array
|
|
102
|
+
// already names the other and its counterpart does not. Both ends are
|
|
103
|
+
// one fact, so both are announced even though only one array grew.
|
|
104
|
+
const store = await build()
|
|
105
|
+
const { blocker, blocked } = await twoTasks(store)
|
|
106
|
+
await store.block(blocker.id, blocked.id)
|
|
107
|
+
// Reverse direction: `blocked` has not yet been recorded as blocking
|
|
108
|
+
// `blocker`, so this is a new edge, not the existing one.
|
|
109
|
+
const seen = recordUpdates(store)
|
|
110
|
+
|
|
111
|
+
await store.block(blocked.id, blocker.id)
|
|
112
|
+
|
|
113
|
+
expect(seen.map((e) => e.taskId)).toEqual([blocked.id, blocker.id])
|
|
114
|
+
})
|
|
115
|
+
})
|
package/src/store/task/memory.ts
CHANGED
|
@@ -177,18 +177,29 @@ export class InMemoryTaskStore implements TaskStore {
|
|
|
177
177
|
const blocked = this.tasks.get(blockedId)
|
|
178
178
|
if (!blocker || !blocked) return
|
|
179
179
|
|
|
180
|
+
let mutated = false
|
|
180
181
|
if (!blocker.blocks.includes(blockedId)) {
|
|
181
182
|
blocker.blocks.push(blockedId)
|
|
183
|
+
mutated = true
|
|
182
184
|
}
|
|
183
185
|
if (!blocked.blockedBy.includes(blockerId)) {
|
|
184
186
|
blocked.blockedBy.push(blockerId)
|
|
187
|
+
mutated = true
|
|
185
188
|
}
|
|
189
|
+
// An edge that already existed is not news. This used to announce
|
|
190
|
+
// unconditionally while the disk store — the one a host runs in
|
|
191
|
+
// production — returned early, so the same call sequence produced two
|
|
192
|
+
// events from one implementation and none from the other. A host
|
|
193
|
+
// rebuilding a graph from the stream did redundant work against one
|
|
194
|
+
// store and not the other, and a host counting events to detect change
|
|
195
|
+
// saw change where there was none.
|
|
196
|
+
if (!mutated) return
|
|
186
197
|
|
|
187
198
|
// Announce BOTH ends. The edge was written and nothing said so, which
|
|
188
199
|
// left the graph observable only by polling: a listener saw a unit
|
|
189
200
|
// created and never learned that something now waits on it. Both sides
|
|
190
|
-
//
|
|
191
|
-
// half the edge.
|
|
201
|
+
// are one fact, so both are announced even when only one array grew —
|
|
202
|
+
// a host tracking a single side would draw half the edge.
|
|
192
203
|
const now = Date.now()
|
|
193
204
|
this.emit({ type: 'task.updated', taskId: blockerId, task: blocker, timestamp: now })
|
|
194
205
|
this.emit({ type: 'task.updated', taskId: blockedId, task: blocked, timestamp: now })
|