History

fix(orchestration): preserve v2 thread deletion planning

Julius Marminge committed 2 months ago

Commit 04bbc331 parent 4b245473 files · +28 −26Browse files

Unified · Split

3 files
  1. apps/server/src/orchestration-v2/Orchestrator.ts +13 −21
  2. apps/server/src/orchestration-v2/runtimeLayer.test.ts +14 −5
  3. apps/server/src/orchestration-v2/testkit/ProviderReplayHarness.ts +1 −0
apps/server/src/orchestration-v2/Orchestrator.ts+13−21
@@ -1912,9 +1912,7 @@ const makeOrchestrator = Effect.fn("orchestrationV2.Orchestrator.layer")(functio · 1911 unmodified lines
19121912 // decided serially against the projection, so a turn start that
19131913 // re-engages the thread cannot race this detach.
19141914 const detachSessionIds = new Set(
1915− command.type === "thread.archive" ||
1916− command.type === "thread.delete" ||
1917− command.type === "thread.settle"
1915+ command.type === "thread.archive" || command.type === "thread.settle"
19181916 ? projection.providerSessions.map((session) => session.id)
19191917 : command.type === "thread.metadata.update" &&
19201918 command.worktreePath !== undefined &&
@@ -1956,13 +1954,11 @@ const makeOrchestrator = Effect.fn("orchestrationV2.Orchestrator.layer")(functio · 35 unmodified lines
19561954 ? "Thread archived."
19571955 : command.type === "thread.settle"
19581956 ? "Thread settled."
1959− : command.type === "thread.delete"
1960− ? "Thread deleted."
1961− : command.type === "thread.metadata.update"
1962− ? "Workspace changed."
1963− : command.type === "thread.runtime-mode.set"
1964− ? "Runtime mode changed."
1965− : "Provider or model selection changed.",
1957+ : command.type === "thread.metadata.update"
1958+ ? "Workspace changed."
1959+ : command.type === "thread.runtime-mode.set"
1960+ ? "Runtime mode changed."
1961+ : "Provider or model selection changed.",
19661962 },
19671963 });
19681964 const pendingEffect = {
@@ -1977,19 +1973,15 @@ const makeOrchestrator = Effect.fn("orchestrationV2.Orchestrator.layer")(functio · 8 unmodified lines
19771973 ? "Thread archived."
19781974 : command.type === "thread.settle"
19791975 ? "Thread settled."
1980− : command.type === "thread.delete"
1981− ? "Thread deleted."
1982− : command.type === "thread.metadata.update"
1983− ? "Workspace changed."
1984− : command.type === "thread.runtime-mode.set"
1985− ? "Runtime mode changed."
1986− : "Provider or model selection changed.",
1976+ : command.type === "thread.metadata.update"
1977+ ? "Workspace changed."
1978+ : command.type === "thread.runtime-mode.set"
1979+ ? "Runtime mode changed."
1980+ : "Provider or model selection changed.",
19871981 // Terminal detaches revoke the thread's MCP credentials; other
19881982 // detach reasons keep them so a re-attaching provider process
19891983 // stays authorized.
1990− ...(command.type === "thread.archive" || command.type === "thread.delete"
1991− ? { revokeMcpCredential: true }
1992− : {}),
1984+ ...(command.type === "thread.archive" ? { revokeMcpCredential: true } : {}),
19931985 },
19941986 } satisfies PendingOrchestrationEffectV2;
19951987 yield* Ref.update(effects, (existing) => [...existing, pendingEffect]);
@@ -1998,7 +1990,7 @@ const makeOrchestrator = Effect.fn("orchestrationV2.Orchestrator.layer")(functio · 2 unmodified lines
19981990 );
19991991 }
20001992
2001− if (command.type === "thread.archive" || command.type === "thread.delete") {
1993+ if (command.type === "thread.archive") {
20021994 yield* Ref.update(effects, (existing) => [
20031995 ...existing,
20041996 {
apps/server/src/orchestration-v2/runtimeLayer.test.ts+14−5
@@ -24,6 +24,7 @@ import * as Effect from "effect/Effect"; · 23 unmodified lines
2424 import * as DateTime from "effect/DateTime";
2525 import * as Deferred from "effect/Deferred";
2626 import * as Fiber from "effect/Fiber";
27+import * as FileSystem from "effect/FileSystem";
2728 import * as Layer from "effect/Layer";
2829 import * as Option from "effect/Option";
2930 import * as Queue from "effect/Queue";
@@ -908,7 +909,7 @@ it.layer(LegacyImportTestLayer)("OrchestrationV2 legacy import", (it) => { · 878 unmodified lines
908909 );
909910 });
910911
911−it.layer(TestLayer)("OrchestrationV2LayerLive lifecycle", (it) => {
912+it.layer(Layer.merge(TestLayer, NodeServices.layer))("OrchestrationV2LayerLive lifecycle", (it) => {
912913 it.effect("applies lifecycle commands idempotently and emits archive/removal shell deltas", () =>
913914 Effect.gen(function* () {
914915 const orchestrator = yield* OrchestratorV2;
@@ -1474,6 +1475,10 @@ it.layer(TestLayer)("OrchestrationV2LayerLive lifecycle", (it) => { · 559 unmodified lines
14741475
14751476 it.effect("applies deferred settlement after safe completion and replays its receipt", () =>
14761477 Effect.gen(function* () {
1478+ const fileSystem = yield* FileSystem.FileSystem;
1479+ const workspacePath = yield* fileSystem.makeTempDirectoryScoped({
1480+ prefix: "t3-runtime-layer-deferred-settle-",
1481+ });
14771482 const orchestrator = yield* OrchestratorV2;
14781483 const eventSink = yield* EventSinkV2;
14791484 const sql = yield* SqlClient.SqlClient;
@@ -1494,7 +1499,7 @@ it.layer(TestLayer)("OrchestrationV2LayerLive lifecycle", (it) => { · 14 unmodified lines
14941499 runtimeMode: "full-access",
14951500 interactionMode: "default",
14961501 branch: null,
1497− worktreePath: "/tmp/runtime-layer-deferred-settle",
1502+ worktreePath: workspacePath,
14981503 });
14991504 yield* orchestrator.dispatch({
15001505 type: "thread.pin",
@@ -1525,7 +1530,7 @@ it.layer(TestLayer)("OrchestrationV2LayerLive lifecycle", (it) => { · 24 unmodified lines
15251530 providerSessionId,
15261531 modelSelection,
15271532 runtimePolicy: {
1528− cwd: "/tmp/runtime-layer-deferred-settle",
1533+ cwd: workspacePath,
15291534 runtimeMode: "full-access",
15301535 interactionMode: "default",
15311536 },
@@ -1631,6 +1636,10 @@ it.layer(TestLayer)("OrchestrationV2LayerLive lifecycle", (it) => { · 99 unmodified lines
16311636
16321637 it.effect("archives after safe completion and discards stale or blocked deferred intents", () =>
16331638 Effect.gen(function* () {
1639+ const fileSystem = yield* FileSystem.FileSystem;
1640+ const workspacePath = yield* fileSystem.makeTempDirectoryScoped({
1641+ prefix: "t3-runtime-layer-deferred-organization-",
1642+ });
16341643 const orchestrator = yield* OrchestratorV2;
16351644 const eventSink = yield* EventSinkV2;
16361645 const sql = yield* SqlClient.SqlClient;
@@ -1652,7 +1661,7 @@ it.layer(TestLayer)("OrchestrationV2LayerLive lifecycle", (it) => { · 15 unmodified lines
16521661 runtimeMode: "full-access",
16531662 interactionMode: "default",
16541663 branch: null,
1655− worktreePath: `/tmp/runtime-layer-deferred-${suffix}`,
1664+ worktreePath: workspacePath,
16561665 });
16571666 yield* orchestrator.dispatch({
16581667 type: "message.dispatch",
@@ -1716,7 +1725,7 @@ it.layer(TestLayer)("OrchestrationV2LayerLive lifecycle", (it) => { · 57 unmodified lines
17161725 providerSessionId,
17171726 modelSelection,
17181727 runtimePolicy: {
1719− cwd: "/tmp/runtime-layer-deferred-archive",
1728+ cwd: workspacePath,
17201729 runtimeMode: "full-access",
17211730 interactionMode: "default",
17221731 },
apps/server/src/orchestration-v2/testkit/ProviderReplayHarness.ts+1−0
@@ -427,6 +427,7 @@ export function makeOrchestratorV2ReplayLayerWithRegistry<Error>( · 426 unmodified lines
427427 Layer.provide(
428428 Layer.mergeAll(effectWorkerProvided, storesLayer, eventSinkProvided, idAllocatorLayer),
429429 ),
430+ Layer.provide(serverSettingsLayer),
430431 );
431432 const replayRuntime = Layer.mergeAll(
432433 orchestratorProvided,