File size: 2,992 Bytes
d197cf3
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
import type {
  AdmittedRunContext,
  PreparedAgentRunAdmission,
} from "../agents/admitted-run-context.js";
import { parseExecutionIdentityAdmissionToken } from "./execution-identity-admission.js";

export type ExecutionOwnerBindingResult =
  | "disabled"
  | "bound"
  | "already-bound"
  | "mismatch"
  | "missing";

export function isRetainedExecutionOwnerBinding(
  result: ExecutionOwnerBindingResult | undefined,
): result is "bound" | "already-bound" {
  return result === "bound" || result === "already-bound";
}

type ExecutionOwnerBinding = Readonly<{
  contextId: string;
  executionId: string;
}>;

/** Extracts only an admitted exact identity; operational run correlation cannot bind owner rows. */
export function executionOwnerBindingFromAdmission(
  admitted: AdmittedRunContext,
): ExecutionOwnerBinding | undefined {
  if (!admitted.executionIdentityToken) {
    return undefined;
  }
  const token = parseExecutionIdentityAdmissionToken(admitted.executionIdentityToken);
  if (token.runId !== admitted.operationalRunInstance.runId) {
    throw new Error("owner execution binding disagrees with the admitted run");
  }
  return { contextId: token.contextId, executionId: token.executionId };
}

export function classifyExecutionOwnerBinding(
  current: { contextId: string | null; executionId: string | null },
  binding: ExecutionOwnerBinding,
): Exclude<ExecutionOwnerBindingResult, "disabled" | "bound" | "missing"> | "unbound" {
  if (current.contextId === null && current.executionId === null) {
    return "unbound";
  }
  return current.contextId === binding.contextId && current.executionId === binding.executionId
    ? "already-bound"
    : "mismatch";
}

/** Adds one exact owner write after admission resolves, never inside the admission callback. */
export function withPostAdmissionExecutionOwnerBinding(
  prepared: PreparedAgentRunAdmission,
  bind: (context: AdmittedRunContext) => void,
): PreparedAgentRunAdmission {
  let bound = false;
  return Object.freeze({
    ...prepared,
    admit: async (runtimeKind, runtimeInstanceId) => {
      const admitted = await prepared.admit(runtimeKind, runtimeInstanceId);
      if (!bound) {
        bound = true;
        bind(admitted);
      }
      return admitted;
    },
  });
}

/** Requires both exact admission and actual execution start, in either runtime order. */
export function createExecutionStartedOwnerBinding(bind: (context: AdmittedRunContext) => void): {
  onPostAdmission: (context: AdmittedRunContext) => void;
  onExecutionStarted: () => void;
} {
  let admitted: AdmittedRunContext | undefined;
  let executionStarted = false;
  let bound = false;
  const bindIfReady = () => {
    if (bound || !admitted || !executionStarted) {
      return;
    }
    bound = true;
    bind(admitted);
  };
  return {
    onPostAdmission: (context) => {
      admitted = context;
      bindIfReady();
    },
    onExecutionStarted: () => {
      executionStarted = true;
      bindIfReady();
    },
  };
}