@tomflow/proflow-task-orchestration 0.1.9 → 0.1.11

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 CHANGED
@@ -1,5 +1,17 @@
1
1
  # @tomflow/proflow-task-orchestration
2
2
 
3
+ ## 0.1.11
4
+
5
+ ### Patch Changes
6
+
7
+ - Release the verified Real-3 B1 task recovery, exact execution identity, durable observer resume, bounded gateway error, and matching Agent Action contract fixes.
8
+
9
+ ## 0.1.10
10
+
11
+ ### Patch Changes
12
+
13
+ - Close the Real-3 source candidate and real-workspace loop: fail-closed Browser submit verification, worker-bound Task mutation and WAKE confirmation, detached platform start ownership with shell return, discoverable docs, and targeted single-package Workspace update.
14
+
3
15
  ## 0.1.9
4
16
 
5
17
  ### Patch Changes
@@ -4,7 +4,7 @@ declare const success: () => {
4
4
  readonly ok: true;
5
5
  readonly status: "SUCCEEDED";
6
6
  readonly moduleRef: "task-orchestration";
7
- readonly moduleVersion: "0.1.9";
7
+ readonly moduleVersion: "0.1.11";
8
8
  };
9
9
  observedEffects: string[];
10
10
  };
@@ -17,7 +17,7 @@ export declare const behaviorAdapter: {
17
17
  ok: true;
18
18
  status: "SUCCEEDED";
19
19
  moduleRef: "task-orchestration";
20
- moduleVersion: "0.1.9";
20
+ moduleVersion: "0.1.11";
21
21
  data: {
22
22
  setupStatus: "READY";
23
23
  runtimeStatus: "NOT_APPLICABLE";
@@ -32,7 +32,7 @@ export declare const behaviorAdapter: {
32
32
  ok: true;
33
33
  status: "SUCCEEDED";
34
34
  moduleRef: "task-orchestration";
35
- moduleVersion: "0.1.9";
35
+ moduleVersion: "0.1.11";
36
36
  data: {
37
37
  docs: string;
38
38
  };
@@ -3,7 +3,7 @@ export declare const descriptor: {
3
3
  readonly contractVersion: "1.0.0";
4
4
  readonly moduleRef: "task-orchestration";
5
5
  readonly packageName: "@tomflow/proflow-task-orchestration";
6
- readonly moduleVersion: "0.1.9";
6
+ readonly moduleVersion: "0.1.11";
7
7
  readonly kind: "library";
8
8
  readonly templateVersion: "1.0.0";
9
9
  readonly platformCompatibility: ">=1.0.0 <2.0.0";
@@ -3,7 +3,7 @@ export const descriptor = {
3
3
  contractVersion: "1.0.0",
4
4
  moduleRef: "task-orchestration",
5
5
  packageName: "@tomflow/proflow-task-orchestration",
6
- moduleVersion: "0.1.9",
6
+ moduleVersion: "0.1.11",
7
7
  kind: "library",
8
8
  templateVersion: "1.0.0",
9
9
  platformCompatibility: ">=1.0.0 <2.0.0",
@@ -1,5 +1,5 @@
1
1
  import { z } from "zod";
2
- import { requiredTaskAgentPackageRefs } from "./model.js";
2
+ import { requiredTaskAgentPackageRefs, taskWaitTypes } from "./model.js";
3
3
  export const publicOperationNames = [
4
4
  "createTaskGroup",
5
5
  "getTaskGroup",
@@ -136,7 +136,7 @@ const schemas = {
136
136
  waitNode: z
137
137
  .object({
138
138
  ...nodeVersion,
139
- waitType: id,
139
+ waitType: z.enum(taskWaitTypes),
140
140
  reasonCode: id,
141
141
  message: id,
142
142
  relatedRef: id.optional(),
@@ -1,4 +1,6 @@
1
1
  export declare const requiredTaskAgentPackageRefs: readonly ["@tomflow/proflow-agent-product", "@tomflow/proflow-agent-controller-dev", "@tomflow/proflow-agent-test-ops"];
2
+ export declare const taskWaitTypes: readonly ["BUSINESS_CONFIRMATION", "REQUIREMENT_BLOCKED", "EXTERNAL_BUSINESS_DEPENDENCY"];
3
+ export type TaskWaitType = (typeof taskWaitTypes)[number];
2
4
  export type TaskGroupStatus = "READY" | "ACTIVE" | "SUCCEEDED";
3
5
  export type TaskStatus = "PENDING" | "READY" | "ACTIVE" | "WAITING" | "FAILED" | "PAUSED" | "SUCCEEDED" | "TERMINATED";
4
6
  export type NodeStatus = "PENDING" | "READY" | "IN_PROGRESS" | "WAITING" | "FAILED" | "SUCCEEDED" | "TERMINATED";
package/dist/src/model.js CHANGED
@@ -3,3 +3,8 @@ export const requiredTaskAgentPackageRefs = [
3
3
  "@tomflow/proflow-agent-controller-dev",
4
4
  "@tomflow/proflow-agent-test-ops",
5
5
  ];
6
+ export const taskWaitTypes = [
7
+ "BUSINESS_CONFIRMATION",
8
+ "REQUIREMENT_BLOCKED",
9
+ "EXTERNAL_BUSINESS_DEPENDENCY",
10
+ ];
@@ -144,6 +144,7 @@ export declare function createTaskServices(options: {
144
144
  } | null;
145
145
  canDrive: boolean;
146
146
  blockedReason: string | null;
147
+ resumeSignalRef: string | null;
147
148
  }>;
148
149
  getNodeContext: (raw: unknown) => TaskResult<{
149
150
  task: Pick<Task, "taskId" | "title" | "objective" | "status" | "version">;
@@ -726,15 +726,24 @@ export function createTaskServices(options) {
726
726
  const current = task.currentNodeId
727
727
  ? tx.nodes.get(task.currentNodeId)
728
728
  : undefined;
729
+ if (task.status === "WAITING" && current?.status !== "WAITING")
730
+ throw new DomainError("TASK_INVALID_STATE", "A WAITING Task must have a current WAITING Node.");
729
731
  if (current?.status === "FAILED")
730
732
  throw new DomainError("TASK_INVALID_STATE", "A failed Node must be explicitly reopened before resume.");
731
- if (current?.status === "WAITING")
733
+ if (current?.status === "WAITING") {
734
+ const unresolved = tx.messages
735
+ .listPending()
736
+ .some((message) => message.taskId === task.taskId &&
737
+ message.nodeId === current.nodeId);
738
+ if (unresolved)
739
+ throw new DomainError("TASK_BLOCKER_UNRESOLVED", "The current Node still has an unresolved business blocker.");
732
740
  tx.nodes.update({
733
741
  ...current,
734
742
  status: "IN_PROGRESS",
735
743
  version: current.version + 1,
736
744
  updatedAt: timestamp,
737
745
  });
746
+ }
738
747
  const updated = {
739
748
  ...task,
740
749
  status: "ACTIVE",
@@ -782,6 +791,8 @@ export function createTaskServices(options) {
782
791
  const binding = tx.roleBindings.get(task.taskId, node.requiredAgentPackageRef);
783
792
  if (!binding?.workerRef || !binding.conversationLocator)
784
793
  throw new DomainError("TASK_ROLE_BINDING_REQUIRED", "Node role is not bound.");
794
+ if (!matchesWorker(input.actorRef, binding.workerRef))
795
+ throw new DomainError("WORKER_MISMATCH", "Only the Task-bound Worker may start the Node.");
785
796
  const updatedNode = {
786
797
  ...node,
787
798
  status: "IN_PROGRESS",
@@ -908,6 +919,8 @@ export function createTaskServices(options) {
908
919
  checkVersion(node.version, input.expectedNodeVersion, "NODE_VERSION_CONFLICT");
909
920
  if (task.status !== "ACTIVE")
910
921
  throw new DomainError("TASK_INVALID_STATE", "Task must be ACTIVE before a Node can wait.");
922
+ if (task.currentNodeId !== node.nodeId)
923
+ throw new DomainError("NODE_NOT_CURRENT", "Only the current Node can enter WAITING.");
911
924
  if (node.status !== "IN_PROGRESS" ||
912
925
  !matchesWorker(input.actorRef, node.workerRef))
913
926
  throw new DomainError(!matchesWorker(input.actorRef, node.workerRef)
@@ -948,10 +961,14 @@ export function createTaskServices(options) {
948
961
  const node = requireNode(tx, input.taskId, input.nodeId);
949
962
  checkVersion(task.version, input.expectedTaskVersion, "TASK_VERSION_CONFLICT");
950
963
  checkVersion(node.version, input.expectedNodeVersion, "NODE_VERSION_CONFLICT");
951
- if (!["ACTIVE", "WAITING"].includes(task.status))
952
- throw new DomainError("TASK_INVALID_STATE", "Task cannot accept a Node failure in its current state.");
953
- if (!["IN_PROGRESS", "WAITING"].includes(node.status))
954
- throw new DomainError("NODE_INVALID_STATE", "Node cannot fail.");
964
+ if (task.status !== "ACTIVE")
965
+ throw new DomainError("TASK_INVALID_STATE", "Task must be ACTIVE before the current run can fail.");
966
+ if (task.currentNodeId !== node.nodeId)
967
+ throw new DomainError("NODE_NOT_CURRENT", "Only the current Node can record a run failure.");
968
+ if (!matchesWorker(input.actorRef, node.workerRef))
969
+ throw new DomainError("WORKER_MISMATCH", "Only the bound running Worker may fail the current Node.");
970
+ if (node.status !== "IN_PROGRESS")
971
+ throw new DomainError("NODE_INVALID_STATE", "Only the current IN_PROGRESS run can fail.");
955
972
  const failedNode = {
956
973
  ...node,
957
974
  status: "FAILED",
@@ -1114,6 +1131,13 @@ export function createTaskServices(options) {
1114
1131
  else if (!terminal && !roleBinding?.workerRef)
1115
1132
  blockedReason = "TASK_ROLE_BINDING_REQUIRED";
1116
1133
  const canDrive = !terminal && blockedReason === null;
1134
+ let durableResumeEventId;
1135
+ if (task.status === "ACTIVE" && currentNode?.status === "IN_PROGRESS")
1136
+ for (const taskEvent of tx.events.listByTask(task.taskId))
1137
+ if (taskEvent.eventType === "TASK_RESUMED" &&
1138
+ taskEvent.taskVersion === task.version &&
1139
+ taskEvent.eventId !== undefined)
1140
+ durableResumeEventId = taskEvent.eventId;
1117
1141
  return {
1118
1142
  taskId: task.taskId,
1119
1143
  taskStatus: task.status,
@@ -1138,6 +1162,9 @@ export function createTaskServices(options) {
1138
1162
  : null,
1139
1163
  canDrive,
1140
1164
  blockedReason,
1165
+ resumeSignalRef: durableResumeEventId === undefined
1166
+ ? null
1167
+ : `task-event:${durableResumeEventId}`,
1141
1168
  };
1142
1169
  }),
1143
1170
  getNodeContext: (raw) => queryWithDocumentRecovery("getNodeContext", raw, (tx, input) => {
@@ -7,7 +7,7 @@ const taskTransitions = {
7
7
  READY: ["ACTIVE", "TERMINATED"],
8
8
  ACTIVE: ["WAITING", "PAUSED", "FAILED", "SUCCEEDED", "TERMINATED"],
9
9
  WAITING: ["ACTIVE", "PAUSED", "TERMINATED"],
10
- FAILED: ["PAUSED", "TERMINATED"],
10
+ FAILED: ["TERMINATED"],
11
11
  PAUSED: ["ACTIVE", "TERMINATED"],
12
12
  SUCCEEDED: [],
13
13
  TERMINATED: [],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tomflow/proflow-task-orchestration",
3
- "version": "0.1.9",
3
+ "version": "0.1.11",
4
4
  "type": "module",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -23,9 +23,9 @@
23
23
  "@tomflow/proflow-module-contract": "^0.1.13"
24
24
  },
25
25
  "devDependencies": {
26
- "@tomflow/proflow-task-store-sqlite": "^0.1.11",
27
- "@tomflow/proflow-deployment-conformance": "^0.1.11",
28
- "@tomflow/proflow-task-migration-runner": "^0.1.11"
26
+ "@tomflow/proflow-task-migration-runner": "^0.1.11",
27
+ "@tomflow/proflow-deployment-conformance": "^0.1.13",
28
+ "@tomflow/proflow-task-store-sqlite": "^0.1.11"
29
29
  },
30
30
  "description": "Owns the Task & Orchestration public contract, domain rules and application services.",
31
31
  "keywords": [
@@ -3,7 +3,7 @@
3
3
  "contractVersion": "1.0.0",
4
4
  "moduleRef": "task-orchestration",
5
5
  "packageName": "@tomflow/proflow-task-orchestration",
6
- "moduleVersion": "0.1.9",
6
+ "moduleVersion": "0.1.11",
7
7
  "kind": "library",
8
8
  "templateVersion": "1.0.0",
9
9
  "platformCompatibility": ">=1.0.0 <2.0.0",