| @@ -1693,6 +1693,104 @@ it.layer(TestLayer)("OrchestrationV2LayerLive lifecycle", (it) => { · 1692 unmodified lines |
| 1693 | assert.equal(cancelAgainError._tag, "OrchestratorDispatchError"); | 1693 | assert.equal(cancelAgainError._tag, "OrchestratorDispatchError"); |
| 1694 | }), | 1694 | }), |
| 1695 | ); | 1695 | ); |
| | 1696 | |
| | 1697 | it.effect("rejects queued prompt mutations from an archived caller", () => |
| | 1698 | Effect.gen(function* () { |
| | 1699 | const orchestrator = yield* OrchestratorV2; |
| | 1700 | const projectId = ProjectId.make("runtime-layer-queued-archived-caller-project"); |
| | 1701 | const callerThreadId = ThreadId.make("runtime-layer-queued-archived-caller"); |
| | 1702 | const targetThreadId = ThreadId.make("runtime-layer-queued-archived-target"); |
| | 1703 | |
| | 1704 | for (const [threadId, title] of [ |
| | 1705 | [callerThreadId, "Archived queue caller"], |
| | 1706 | [targetThreadId, "Archived queue target"], |
| | 1707 | ] as const) { |
| | 1708 | yield* orchestrator.dispatch({ |
| | 1709 | type: "thread.create", |
| | 1710 | createdBy: "user", |
| | 1711 | creationSource: "web", |
| | 1712 | commandId: CommandId.make(`command:${threadId}:create`), |
| | 1713 | threadId, |
| | 1714 | projectId, |
| | 1715 | title, |
| | 1716 | modelSelection, |
| | 1717 | runtimeMode: "full-access", |
| | 1718 | interactionMode: "default", |
| | 1719 | branch: null, |
| | 1720 | worktreePath: `/tmp/${threadId}`, |
| | 1721 | }); |
| | 1722 | } |
| | 1723 | yield* orchestrator.dispatch({ |
| | 1724 | type: "message.dispatch", |
| | 1725 | createdBy: "user", |
| | 1726 | creationSource: "web", |
| | 1727 | commandId: CommandId.make("runtime-layer-queued-archived-target-active"), |
| | 1728 | threadId: targetThreadId, |
| | 1729 | messageId: MessageId.make("runtime-layer-queued-archived-target-active"), |
| | 1730 | text: "Keep the target active.", |
| | 1731 | attachments: [], |
| | 1732 | modelSelection, |
| | 1733 | dispatchMode: { type: "start_immediately" }, |
| | 1734 | }); |
| | 1735 | const queuedMessageId = MessageId.make("runtime-layer-queued-archived-target-queued"); |
| | 1736 | yield* orchestrator.dispatch({ |
| | 1737 | type: "message.dispatch", |
| | 1738 | createdBy: "user", |
| | 1739 | creationSource: "web", |
| | 1740 | commandId: CommandId.make("runtime-layer-queued-archived-target-queued"), |
| | 1741 | threadId: targetThreadId, |
| | 1742 | messageId: queuedMessageId, |
| | 1743 | text: "Do not mutate this queued prompt.", |
| | 1744 | attachments: [], |
| | 1745 | modelSelection, |
| | 1746 | dispatchMode: { type: "queue_after_active" }, |
| | 1747 | }); |
| | 1748 | const queuedRun = (yield* orchestrator.getThreadProjection(targetThreadId)).runs.find( |
| | 1749 | (run) => run.userMessageId === queuedMessageId, |
| | 1750 | ); |
| | 1751 | assert.isDefined(queuedRun); |
| | 1752 | yield* orchestrator.dispatch({ |
| | 1753 | type: "thread.archive", |
| | 1754 | commandId: CommandId.make("runtime-layer-queued-archived-caller-archive"), |
| | 1755 | threadId: callerThreadId, |
| | 1756 | }); |
| | 1757 | |
| | 1758 | const policyCeiling = { |
| | 1759 | callerThreadId, |
| | 1760 | runtimeMode: "full-access" as const, |
| | 1761 | interactionMode: "default" as const, |
| | 1762 | }; |
| | 1763 | const editError = yield* orchestrator |
| | 1764 | .dispatch({ |
| | 1765 | type: "queued-run.edit", |
| | 1766 | commandId: CommandId.make("runtime-layer-queued-archived-caller-edit"), |
| | 1767 | threadId: targetThreadId, |
| | 1768 | runId: queuedRun.id, |
| | 1769 | text: "This edit must be rejected.", |
| | 1770 | policyCeiling, |
| | 1771 | }) |
| | 1772 | .pipe(Effect.flip); |
| | 1773 | assert.equal(editError._tag, "OrchestratorDispatchError"); |
| | 1774 | const promoteError = yield* orchestrator |
| | 1775 | .dispatch({ |
| | 1776 | type: "queued-message.promote-to-steer", |
| | 1777 | commandId: CommandId.make("runtime-layer-queued-archived-caller-promote"), |
| | 1778 | threadId: targetThreadId, |
| | 1779 | queuedRunId: queuedRun.id, |
| | 1780 | targetRunId: RunId.make("runtime-layer-queued-archived-target-active-run"), |
| | 1781 | policyCeiling, |
| | 1782 | }) |
| | 1783 | .pipe(Effect.flip); |
| | 1784 | assert.equal(promoteError._tag, "OrchestratorDispatchError"); |
| | 1785 | |
| | 1786 | const projection = yield* orchestrator.getThreadProjection(targetThreadId); |
| | 1787 | assert.equal( |
| | 1788 | projection.messages.find((message) => message.id === queuedMessageId)?.text, |
| | 1789 | "Do not mutate this queued prompt.", |
| | 1790 | ); |
| | 1791 | assert.equal(projection.runs.find((run) => run.id === queuedRun.id)?.status, "queued"); |
| | 1792 | }), |
| | 1793 | ); |
| 1696 | }); | 1794 | }); |
| 1697 | | 1795 | |
| 1698 | it.layer(SharedApplicationDataPlaneTestLayer)("pending provider interruption", (it) => { | 1796 | it.layer(SharedApplicationDataPlaneTestLayer)("pending provider interruption", (it) => { |