@makaio/framework 1.0.0-dev-1788258714339 → 1.0.0-dev-1788721567504

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.
Files changed (115) hide show
  1. package/dist/.makaio-build.json +2 -2
  2. package/dist/attempt-record-codec-BORASgzn.mjs +1 -0
  3. package/dist/authority-state-bootstrap-eitx6Ukn.mjs +1 -0
  4. package/dist/bus/index.d.mts +19 -19
  5. package/dist/bus/index.mjs +1 -1
  6. package/dist/capabilities-DEvmD9VJ.mjs +1 -0
  7. package/dist/{context-resolution-CW4OtPrS.d.mts → context-resolution-CoKFKIqz.d.mts} +5 -5
  8. package/dist/contracts/adapter/index.d.mts +1 -1
  9. package/dist/contracts/artifact/index.d.mts +2 -2
  10. package/dist/contracts/canonical-model/index.d.mts +1 -1
  11. package/dist/contracts/capabilities/index.d.mts +2 -2
  12. package/dist/contracts/capabilities/index.mjs +1 -1
  13. package/dist/contracts/client/index.d.mts +1 -1
  14. package/dist/contracts/extension/index.d.mts +3 -3
  15. package/dist/contracts/harness/index.d.mts +1 -1
  16. package/dist/contracts/index.d.mts +618 -124
  17. package/dist/contracts/index.mjs +1 -1
  18. package/dist/contracts/materialization/index.d.mts +3 -3
  19. package/dist/contracts/session/index.d.mts +2 -2
  20. package/dist/contracts/shared/index.d.mts +1 -1
  21. package/dist/contracts/variant/index.d.mts +1 -1
  22. package/dist/contracts/worker/index.d.mts +2 -0
  23. package/dist/contracts/worker/index.mjs +1 -0
  24. package/dist/contracts/workflow/index.d.mts +2 -2
  25. package/dist/contracts/workflow/index.mjs +1 -1
  26. package/dist/{execution-attempt-repository-BJ2W6wwx.d.mts → execution-attempt-repository-CRdrgou3.d.mts} +869 -58
  27. package/dist/{index-jxPncqWZ2.d.mts → index--Ws52sWV2.d.mts} +4 -4
  28. package/dist/{index-OG402CBI.d.mts → index-37_b--BH.d.mts} +85 -85
  29. package/dist/{index-B-3I98nw.d.mts → index-AdcDBUnc.d.mts} +95 -95
  30. package/dist/{index-CMekqu_D.d.mts → index-BJdkVFX9.d.mts} +327 -63
  31. package/dist/{index-4KJ6IDE7.d.mts → index-BKIxdzIw.d.mts} +5 -5
  32. package/dist/{index-CPi0UpRh.d.mts → index-B_8bA2JW.d.mts} +1 -1
  33. package/dist/{index-CmwAJ8-5.d.mts → index-CFI6FxC7.d.mts} +1 -1
  34. package/dist/{index-BqlCDBfc.d.mts → index-CVcG4Q3X.d.mts} +5 -5
  35. package/dist/{index-DXqG0r3o.d.mts → index-CxwqnZpT.d.mts} +62 -62
  36. package/dist/{index-BkbnC65b.d.mts → index-CyWGSxrs.d.mts} +291 -291
  37. package/dist/{index-B9V3T4EQ.d.mts → index-D037TVsm.d.mts} +4 -4
  38. package/dist/{index-C146Eq_J.d.mts → index-D1wTWSLR.d.mts} +327 -327
  39. package/dist/{index-DWkFkvRn2.d.mts → index-D8D-yibS2.d.mts} +3 -3
  40. package/dist/{index-Bqk0pJBQ2.d.mts → index-DBD_oFEt2.d.mts} +1 -1
  41. package/dist/{index-DJ2KgJDJ2.d.mts → index-DV38-klA2.d.mts} +59 -83
  42. package/dist/{index-C3lu_fy5.d.mts → index-I5a37JCm.d.mts} +76 -76
  43. package/dist/{namespace-l-HG1rLF.d.mts → namespace-Bo94cenp.d.mts} +136 -136
  44. package/dist/{namespace-DknCutQZ.d.mts → namespace-CPm9dhi2.d.mts} +2 -2
  45. package/dist/{namespace-BNp7n_gu.d.mts → namespace-CsnrP8AD.d.mts} +3 -3
  46. package/dist/{namespace-BGRHcrmp.d.mts → namespace-CstawJgN.d.mts} +2 -2
  47. package/dist/{namespace-C06lJSuj.d.mts → namespace-K23m4b0n.d.mts} +6 -6
  48. package/dist/{package-BNFTUFLB.d.mts → package-DkZmsdCd.d.mts} +107 -30
  49. package/dist/package-UemD2NWn.mjs +7 -0
  50. package/dist/package.json +1 -1
  51. package/dist/runtime-node/index.d.mts +2 -2
  52. package/dist/runtime-node/index.mjs +24 -24
  53. package/dist/runtime-node/makaio-config.d.mts +2 -2
  54. package/dist/runtime-node/makaio-config.mjs +1 -1
  55. package/dist/runtime-node/workflow-execution-bus-access.mjs +1 -1
  56. package/dist/runtime-node/workflow-worker/index.d.mts +2 -2
  57. package/dist/runtime-node/workflow-worker/index.mjs +1 -1
  58. package/dist/runtime-node/workflow-worker/worker-entry.d.mts +49 -9
  59. package/dist/runtime-node/workflow-worker/worker-entry.mjs +1 -1
  60. package/dist/runtime-registration-client-BTtFpt_k.mjs +1 -0
  61. package/dist/{schemas-OWvBn7AH.d.mts → schemas-BCXvEWyF.d.mts} +4 -4
  62. package/dist/{schemas-Dd0po67F.d.mts → schemas-CJKHYluy.d.mts} +16 -16
  63. package/dist/{schemas-C1mxTfd7.d.mts → schemas-CenET9Cq.d.mts} +1 -1
  64. package/dist/{schemas-D7ScxLrf.d.mts → schemas-DTJtS14K.d.mts} +136 -136
  65. package/dist/services/adapter-runtime/index.d.mts +3 -3
  66. package/dist/services/adapter-runtime/namespace.d.mts +1 -1
  67. package/dist/services/adapter-runtime/schemas.d.mts +1 -1
  68. package/dist/services/adapter-subsystem/index.d.mts +2 -2
  69. package/dist/services/adapter-subsystem/namespace.d.mts +1 -1
  70. package/dist/services/agent-runtime/index.d.mts +2 -2
  71. package/dist/services/agent-runtime/namespace.d.mts +1 -1
  72. package/dist/services/agent-runtime/schemas.d.mts +1 -1
  73. package/dist/services/filesystem/namespace.d.mts +6 -6
  74. package/dist/services/filesystem/schemas.d.mts +3 -3
  75. package/dist/services/harness/index.d.mts +3 -3
  76. package/dist/services/index.d.mts +93 -93
  77. package/dist/services/provider-context/index.d.mts +1 -1
  78. package/dist/services/session/index.d.mts +2 -2
  79. package/dist/services/session/messages/namespace.d.mts +1 -1
  80. package/dist/services/settings/namespace.d.mts +12 -12
  81. package/dist/services/settings/storage/extension-configs/namespace.d.mts +3 -3
  82. package/dist/services/subagent-template/index.d.mts +2 -2
  83. package/dist/services/subagent-template/namespace.d.mts +1 -1
  84. package/dist/services/subagent-template/schemas.d.mts +1 -1
  85. package/dist/{transition-DXmCUq6w.d.mts → transition-DxsrTsn4.d.mts} +1 -1
  86. package/dist/{types-DcxBYlPA.d.mts → types-Czdm5op1.d.mts} +306 -306
  87. package/dist/ui-components/index.d.mts +4 -4
  88. package/dist/{view-builder-k82f5KFd.d.mts → view-builder-D-Wz_l_B.d.mts} +1 -1
  89. package/dist/worker-CLsRbzpk.mjs +1 -0
  90. package/dist/worker-DlRdLf2d.mjs +1 -0
  91. package/dist/workflow-BomH9DBB.mjs +1 -0
  92. package/dist/workflow-engine/execution-attempt-repository.d.mts +2 -2
  93. package/dist/workflow-engine/execution-attempt-repository.mjs +1 -1
  94. package/dist/workflow-engine/index.d.mts +352 -62
  95. package/dist/workflow-engine/index.mjs +1 -1
  96. package/dist/workflow-engine/package.d.mts +1 -1
  97. package/dist/workflow-engine/package.mjs +1 -1
  98. package/dist/workflow-engine/testing/index.d.mts +83 -10
  99. package/dist/workflow-engine/testing/index.mjs +1 -1
  100. package/dist/workflow-engine/testing/sqlite.d.mts +3 -2
  101. package/dist/workflow-engine/testing/sqlite.mjs +107 -39
  102. package/dist/workflow-engine/workflow-orchestrator.mjs +1 -1
  103. package/dist/workflow-worker-DjUfKshi.mjs +1 -0
  104. package/package.json +4 -4
  105. package/dist/attempt-record-codec-BYfYkj4M.mjs +0 -1
  106. package/dist/authority-state-bootstrap-CLYus369.mjs +0 -1
  107. package/dist/await-trigger-Bkg2BQfg.mjs +0 -1
  108. package/dist/capabilities-BUwuA7XX.mjs +0 -1
  109. package/dist/contracts/worker-node/index.d.mts +0 -2
  110. package/dist/contracts/worker-node/index.mjs +0 -1
  111. package/dist/package-B01gmu75.mjs +0 -7
  112. package/dist/worker-node-CjuQb9hl.mjs +0 -1
  113. package/dist/worker-node-Dtf9ilsR.mjs +0 -1
  114. package/dist/workflow-C4mck_NW.mjs +0 -1
  115. package/dist/workflow-worker-aNbdgqml.mjs +0 -1
@@ -1,5 +1,5 @@
1
1
  import { a as ProviderOperationClaim, i as ProcessBoundProvisionerLossProof, l as ProviderOperationOwnershipRecord, o as ProviderOperationClaimDecision, s as ProviderOperationMutationDecision } from "./provider-operation-DbdyFwNm.mjs";
2
- import { BoundedRecoveryEvidence, ProviderAllocationRef, WorkerNodeAllocationLifetime, WorkflowRunResult } from "@makaio/framework/contracts";
2
+ import { BoundedRecoveryEvidence, ExecutionAttemptOperationKind, ProviderAllocationRef, WorkerAllocationLifetime } from "@makaio/framework/contracts";
3
3
 
4
4
  //#region subsystems/workflow-engine/src/execution-attempt-repository.d.ts
5
5
  /**
@@ -28,9 +28,9 @@ declare const EXECUTION_ATTEMPT_SETTLEMENT_KINDS: readonly ["outcome", "abandone
28
28
  /**
29
29
  * How a settled attempt reached its terminal state.
30
30
  *
31
- * - `outcome`: a worker submitted a workflow result that was accepted.
31
+ * - `outcome`: a worker submitted an outcome that was accepted.
32
32
  * - `infrastructure-failure`: the provider allocation terminated without
33
- * an acknowledged worker outcome. The workflow run may be retried.
33
+ * an acknowledged worker outcome. The owner may retry the work.
34
34
  * - `abandoned`: dispatch ended before allocation, including a positively
35
35
  * proven absence recorded through
36
36
  * {@link ExecutionAttemptRepository.recordProvisioningAbsent} or a
@@ -40,6 +40,25 @@ declare const EXECUTION_ATTEMPT_SETTLEMENT_KINDS: readonly ["outcome", "abandone
40
40
  * `null` when the attempt has not yet settled.
41
41
  */
42
42
  type ExecutionAttemptSettlementKind = (typeof EXECUTION_ATTEMPT_SETTLEMENT_KINDS)[number] | null;
43
+ /**
44
+ * Constant array of every state the attempt's operation start gate can hold.
45
+ *
46
+ * Declared as an array for the same reason the status vocabulary is: a stored
47
+ * value outside it is corruption, and a realization narrows what it read
48
+ * against this list rather than against a literal of its own.
49
+ */
50
+ declare const ATTEMPT_OPERATION_START_GATES: readonly ["open", "closed"];
51
+ /**
52
+ * State of the single durable ordering point an attempt admits operations
53
+ * through.
54
+ *
55
+ * - `open`: the attempt may still admit operations, subject to every other
56
+ * guard.
57
+ * - `closed`: the attempt will never admit another operation. Closing is
58
+ * one-way and happens exactly where the attempt stops being a place work may
59
+ * begin — when a newer attempt supersedes it, and when it settles.
60
+ */
61
+ type AttemptOperationStartGate = (typeof ATTEMPT_OPERATION_START_GATES)[number];
43
62
  /**
44
63
  * Compare two provider allocation references as values.
45
64
  *
@@ -54,16 +73,196 @@ type ExecutionAttemptSettlementKind = (typeof EXECUTION_ATTEMPT_SETTLEMENT_KINDS
54
73
  */
55
74
  declare function sameAllocationRef(stored: ProviderAllocationRef, candidate: ProviderAllocationRef): boolean;
56
75
  /**
57
- * Compare two terminal workflow results as values.
58
- *
59
- * The rule {@link sameAllocationRef} states, for the same reason: a result may
60
- * carry caller-authored data whose key order is incidental, and a replay of the
61
- * identical result must be reported as `duplicate` by every realization.
62
- * @param committed - Result already committed for the attempt.
63
- * @param candidate - Result the caller presented.
64
- * @returns `true` when the two denote the same terminal result.
76
+ * Identifier of the durable aggregate that owns a series of attempts.
77
+ *
78
+ * For the workflow adapter this is the `WorkflowExecution` id. The generic
79
+ * port never interprets it; it is the fence key that decides which attempt is
80
+ * active for an owner. The alias is scoped to the repository port, the
81
+ * authority, the dispatch runner, and the convergence ports — wire claims and
82
+ * workflow-storage lookup keys keep plain `string`.
83
+ */
84
+ type ExecutionOwnerId = string;
85
+ /**
86
+ * Compare two durable outcome texts as values.
87
+ *
88
+ * The rule {@link sameAllocationRef} states, for the same reason: an outcome
89
+ * may carry caller-authored data whose key order is incidental, and a replay
90
+ * of the identical outcome must be reported as `duplicate` by every
91
+ * realization. The texts are parsed back before canonicalization because a
92
+ * codec is free to emit whatever key order it likes, and key order is not
93
+ * part of the value.
94
+ *
95
+ * Both operands are the codec's durable text — the only representation every
96
+ * realization shares. The stored one is what the attempt actually holds, read
97
+ * out of the realization's own record rather than reproduced from the decoded
98
+ * value: a codec may normalize while serializing, and the contract requires
99
+ * `parse(JSON.parse(serialize(outcome)))` only to succeed, never to serialize
100
+ * back to the same text. Re-serializing the decoded outcome would therefore
101
+ * compare a retry against a text the first commit never wrote, and would
102
+ * answer `conflict` for a worker's honest replay. Comparing texts also keeps
103
+ * a value such as a `bigint` — which a codec may legitimately encode, and
104
+ * which has no JSON form of its own — away from the canonicalizer entirely.
105
+ * @param stored - Durable text the attempt committed.
106
+ * @param candidate - Durable text the caller's submission would commit.
107
+ * @returns `true` when the two denote the same outcome.
65
108
  */
66
- declare function sameWorkflowResult(committed: WorkflowRunResult, candidate: WorkflowRunResult): boolean;
109
+ declare function sameDurableOutcome(stored: string, candidate: string): boolean;
110
+ /**
111
+ * The durable text a submission commits as, with the value that text yields.
112
+ *
113
+ * The two are produced together, by one call to {@link durableOutcome}, because
114
+ * they are one durable fact: the text is what a realization writes, and the
115
+ * outcome is what a reload of that text returns. Deriving either from the
116
+ * other later would re-serialize an already-normalized value, and a codec is
117
+ * not required to serialize such a value back to the text it came from.
118
+ *
119
+ * It is the currency of the whole outcome path. A caller renders a submission
120
+ * once through {@link ExecutionAttemptRepository.canonicalizeOutcome},
121
+ * validates `outcome`, and hands the same rendering to
122
+ * {@link ExecutionAttemptRepository.commitOutcome}, which stores `text`
123
+ * verbatim. Nothing between those steps re-reads the submitter's object, so a
124
+ * mutable outcome the caller changes afterwards cannot make the committed
125
+ * value differ from the validated one.
126
+ * @typeParam TOutcome - Owner-specific outcome type committed per attempt.
127
+ */
128
+ interface DurableOutcome<TOutcome> {
129
+ /** The codec text a realization persists for this submission. */
130
+ readonly text: string;
131
+ /** The outcome that text reads back as, produced by the same rendering. */
132
+ readonly outcome: TOutcome;
133
+ }
134
+ /**
135
+ * Render a caller-supplied outcome as the durable fact a commit would write.
136
+ *
137
+ * The rendering rule every realization owes, stated once here for the same
138
+ * reason {@link sameDurableOutcome} is: it decides what an attempt holds, so
139
+ * two realizations deriving it independently could disagree about it.
140
+ *
141
+ * Three steps, in this order and each exactly once. `parse` validates the
142
+ * submission before any durable decision, so a value the codec rejects is
143
+ * refused at the same point by every realization. `serialize` produces the
144
+ * text to persist — the single serialization the pair is built from.
145
+ * `parse(JSON.parse(text))` yields what a reload returns, which is the
146
+ * outcome the port reports and an owner converges on; a codec may normalize
147
+ * while serializing, so it is not in general the submitted value.
148
+ *
149
+ * Nothing is cloned and nothing is frozen. The round trip already produces a
150
+ * value derived from freshly parsed JSON rather than from the caller's
151
+ * object, so no reference reaches back into anything the caller still holds.
152
+ * A `structuredClone` in front of it would reject an outcome type that is
153
+ * codec-serializable but not structured-cloneable, such as a `URL`, and an
154
+ * `Object.freeze` behind it would throw outright for one that is not
155
+ * freezable, such as a non-empty `Uint8Array` — both of which the codec
156
+ * contract allows. What keeps a committed outcome stable instead is that a
157
+ * realization stores the text and decodes it afresh on every read, so a
158
+ * caller that mutates the value it was handed changes nothing a later read
159
+ * reports.
160
+ * @param codec - Owner-injected codec that owns the durable representation.
161
+ * @param outcome - Outcome the caller presented.
162
+ * @returns The text to persist and the outcome it reads back as.
163
+ * @throws When the codec rejects the outcome or its own durable text.
164
+ * @typeParam TOutcome - Owner-specific outcome type committed per attempt.
165
+ */
166
+ declare function durableOutcome<TOutcome>(codec: OutcomeCodec<TOutcome>, outcome: TOutcome): DurableOutcome<TOutcome>;
167
+ /**
168
+ * Read a committed durable text back as the outcome it holds.
169
+ *
170
+ * The read rule every realization owes, stated once here for the same reason
171
+ * {@link durableOutcome} states the write rule: what a stored text yields
172
+ * must not depend on which realization reads it. `JSON.parse` undoes the
173
+ * transport form and `parse` validates the envelope, so a text the codec
174
+ * refuses — durable corruption, or a codec an owner changed under an existing
175
+ * row — fails loudly rather than reaching a caller as an ordinary outcome.
176
+ *
177
+ * Every read decodes afresh, and nothing is shared, cloned, or frozen. A
178
+ * codec may reconstruct a mutable object whose state a freeze does not even
179
+ * reach, such as a `URL`, so one reader mutating the value it was handed must
180
+ * not change what the next read reports; the stored text stays the only
181
+ * source of truth.
182
+ * @param codec - Owner-injected codec that owns the durable representation.
183
+ * @param text - Durable text an attempt committed.
184
+ * @returns The outcome that text holds, held by nobody else.
185
+ * @throws When the text is not JSON, or not JSON the codec accepts.
186
+ * @typeParam TOutcome - Owner-specific outcome type committed per attempt.
187
+ */
188
+ declare function decodeDurableOutcome<TOutcome>(codec: OutcomeCodec<TOutcome>, text: string): TOutcome;
189
+ /**
190
+ * Validates and serializes the owner-specific outcome type of an attempt.
191
+ *
192
+ * Injected into every {@link ExecutionAttemptRepository} realization so the
193
+ * generic port can enforce "input validation precedes every durable decision"
194
+ * without knowing the outcome shape. `parse` runs on every submitted outcome
195
+ * before the durable decision and on every committed outcome read back from
196
+ * storage; `serialize` produces the durable representation.
197
+ *
198
+ * **The durable representation is JSON text, and the two members round-trip
199
+ * through it.** A realization persists exactly what `serialize` returned,
200
+ * reads it back with `JSON.parse`, and hands the parsed value to `parse`; a
201
+ * codec must therefore accept `JSON.parse(serialize(outcome))` for every
202
+ * outcome it produced. Which envelope lives inside that text is the codec's
203
+ * own choice — no realization may assume it is `JSON.stringify(outcome)`.
204
+ *
205
+ * **The text is strict JSON, in the sense `JSON.stringify` defines.** Only
206
+ * values that function can represent are inside the contract: finite numbers,
207
+ * strings, booleans, `null`, arrays, and plain objects. A non-finite number —
208
+ * `Infinity`, `-Infinity`, `NaN`, written as `1e9999` or any other spelling —
209
+ * is outside it, as is anything else JSON has no form for, because the port
210
+ * decides outcome equality by canonicalizing the parsed text with
211
+ * `canonicalStringify` (see {@link sameDurableOutcome}), which renders every
212
+ * such value as `null` and would report two different outcomes as the same
213
+ * one. A codec whose outcomes need those values encodes them as values JSON
214
+ * does have — a string, or a tagged envelope — which is the codec's own job
215
+ * and not something a realization can do for it. Equality follows JSON
216
+ * semantics for the same reason: signed zero is outside the contract, `-0`
217
+ * and `0` are one and the same outcome, because `JSON.stringify` renders both
218
+ * as `0` and the canonical form cannot tell them apart. A codec that needs the
219
+ * sign encodes it explicitly, as it would any other value JSON does not carry.
220
+ *
221
+ * **Both members are deterministic, pure functions of their argument.** The
222
+ * same outcome serializes to the same text every time and the same value
223
+ * parses to the same outcome every time; neither may consult history, a
224
+ * counter, a clock, or any state outside the argument it was handed.
225
+ *
226
+ * The port itself renders a submission exactly once, through
227
+ * {@link ExecutionAttemptRepository.canonicalizeOutcome}, and carries that one
228
+ * {@link DurableOutcome} into {@link ExecutionAttemptRepository.commitOutcome}
229
+ * — so validation, the durable write, and convergence are one rendering and
230
+ * cannot drift apart. Determinism is still owed, because two renderings of
231
+ * the same outcome do meet: `commitOutcome` compares the text a retry renders
232
+ * against the text the first commit stored, and a codec that closed over a
233
+ * counter would misclassify a worker's honest retry.
234
+ *
235
+ * Determinism is not idempotence. `serialize` need not map its own decoded
236
+ * output back to the text it came from: a codec may normalize, and every
237
+ * decision the port makes about a committed outcome is made on the text that
238
+ * commit actually stored rather than on a re-serialization of it.
239
+ *
240
+ * `null` and `undefined` are not outcomes. A realization records "no outcome
241
+ * committed" as the absence of a stored value, so a codec that accepted a
242
+ * nullish outcome would make the two indistinguishable.
243
+ * @typeParam TOutcome - Owner-specific outcome type committed per attempt.
244
+ */
245
+ interface OutcomeCodec<TOutcome> {
246
+ /**
247
+ * Validate an untrusted value as an outcome.
248
+ *
249
+ * Deterministic and pure: the same input always yields the same outcome.
250
+ * @param input - Value to validate.
251
+ * @returns The validated outcome.
252
+ * @throws When the value violates the outcome contract, including when it is nullish.
253
+ */
254
+ parse(input: unknown): TOutcome;
255
+ /**
256
+ * Serialize an outcome for durable storage.
257
+ *
258
+ * Deterministic and pure: the same outcome always yields the same text,
259
+ * because a retry's rendering is compared against the text an earlier
260
+ * commit stored.
261
+ * @param outcome - Outcome to serialize.
262
+ * @returns The JSON text to persist, which `parse` accepts after `JSON.parse`.
263
+ */
264
+ serialize(outcome: TOutcome): string;
265
+ }
67
266
  /**
68
267
  * Rejection of an attempt identifier that already names a durable attempt.
69
268
  *
@@ -83,17 +282,136 @@ declare class DuplicateExecutionAttemptError extends Error {
83
282
  */
84
283
  constructor(executionAttemptId: string, options?: ErrorOptions);
85
284
  }
285
+ /**
286
+ * The runtime and operation control state of one attempt.
287
+ *
288
+ * Ten facts that together decide who may act on an attempt's runtime endpoint
289
+ * and whether an operation may start. They live *on* the attempt rather than in
290
+ * a record beside it: every guard that reads them is also a guard the write has
291
+ * to repeat, and a single-row compare-and-set is what keeps that expressible.
292
+ *
293
+ * The three fences are independent and each answers a different question:
294
+ * {@link runtimeGeneration} says which runtime incarnation is current,
295
+ * {@link operationStartGate} says whether the attempt still starts work at all,
296
+ * and {@link activeOperationId} says whether it is already busy.
297
+ *
298
+ * It is also the shape {@link ExecutionAttemptRepository.getAttemptControlState}
299
+ * reports, so a process that lost its own memory of an attempt can read back
300
+ * exactly what a fresh decision would be made against.
301
+ */
302
+ interface AttemptControlState {
303
+ /**
304
+ * Monotonic fence over runtime incarnations, `0` before any registered.
305
+ *
306
+ * Allocated by {@link ExecutionAttemptRepository.registerRuntime} and never
307
+ * proposed by a caller: a runtime only ever echoes the generation it was
308
+ * given. Anything presented against an older generation is
309
+ * `stale-generation`.
310
+ */
311
+ readonly runtimeGeneration: number;
312
+ /**
313
+ * Runtime incarnation currently registered, or `null` before any was.
314
+ *
315
+ * The registration idempotency key. A report naming the stored incarnation
316
+ * is a replay and is answered `duplicate`; a different one is a new
317
+ * incarnation and takes the next generation.
318
+ */
319
+ readonly runtimeIncarnationId: string | null;
320
+ /**
321
+ * ISO-8601 instant at which readiness was accepted for the current
322
+ * generation, or `null` while it has not been.
323
+ *
324
+ * Written by {@link ExecutionAttemptRepository.markRuntimeReady} and cleared
325
+ * by every {@link ExecutionAttemptRepository.registerRuntime} that allocates
326
+ * a new generation: readiness is a property of one incarnation, so it can
327
+ * never outlive the incarnation that proved it.
328
+ */
329
+ readonly runtimeReadyAt: string | null;
330
+ /**
331
+ * Whether the attempt still admits operations.
332
+ *
333
+ * `open` from creation. Closed by {@link ExecutionAttemptRepository.createAttempt}
334
+ * on the attempt it supersedes, and by every terminal settlement on the
335
+ * attempt it settles. Closing is one-way.
336
+ */
337
+ readonly operationStartGate: AttemptOperationStartGate;
338
+ /**
339
+ * Operation currently occupying the attempt, or `null` when it is idle.
340
+ *
341
+ * The at-most-one guard: an attempt runs one operation at a time. Cleared by
342
+ * {@link ExecutionAttemptRepository.completeOperation} together with
343
+ * {@link activeOperationKind}, {@link activeOperationKey},
344
+ * {@link activeOperationGeneration}, and {@link activeOperationAdmittedAt} —
345
+ * one write, because a half-cleared
346
+ * operation would be neither active nor absent.
347
+ *
348
+ * A terminal settlement deliberately leaves it in place, so a completion that
349
+ * arrives after the attempt settled reads `resolved` rather than
350
+ * `not-active`.
351
+ */
352
+ readonly activeOperationId: string | null;
353
+ /**
354
+ * Kind of the active operation, or `null` when the attempt is idle.
355
+ *
356
+ * Kept because the bounded runtime probe and a durable owner's run are not
357
+ * interchangeable: the probe is admitted while readiness is still unproven
358
+ * and is never announced to anyone but its own runtime.
359
+ */
360
+ readonly activeOperationKind: ExecutionAttemptOperationKind | null;
361
+ /**
362
+ * Idempotency key the active operation was admitted under, or `null` when the
363
+ * attempt is idle.
364
+ *
365
+ * A second admission presenting this key is the same admission retried, and
366
+ * is answered `duplicate` with the operation identifier the first one
367
+ * received.
368
+ */
369
+ readonly activeOperationKey: string | null;
370
+ /**
371
+ * Runtime generation the active operation is fenced against, or `null` when
372
+ * the attempt is idle.
373
+ *
374
+ * A completion reported against an older generation belongs to a runtime that
375
+ * has since been superseded and is refused as `stale-generation`.
376
+ */
377
+ readonly activeOperationGeneration: number | null;
378
+ /**
379
+ * ISO-8601 instant at which the active operation was admitted, or `null`
380
+ * when the attempt is idle.
381
+ *
382
+ * Recorded so a replayed admission announces the instant the authority
383
+ * admitted the operation, not the instant of the replay. Cleared together
384
+ * with the other active-operation members.
385
+ */
386
+ readonly activeOperationAdmittedAt: string | null;
387
+ /**
388
+ * Operation identifier of the most recent completion, or `null` before any.
389
+ *
390
+ * What makes a replayed completion answerable: the active operation is gone
391
+ * by then, so without it the replay would be indistinguishable from a
392
+ * completion for an operation that never existed.
393
+ */
394
+ readonly lastCompletedOperationId: string | null;
395
+ }
86
396
  /**
87
397
  * Durable record for one execution attempt.
88
398
  *
89
399
  * Produced by the injected {@link ExecutionAttemptRepository} and consumed by
90
400
  * the Authority service. All fields are JSON-safe and contain no secrets.
401
+ *
402
+ * The {@link AttemptControlState} members are part of the record because they
403
+ * are columns on the attempt, not a separate aggregate — and they are required,
404
+ * unlike {@link claimable} and {@link settlementKind}. Every attempt holds all
405
+ * ten from {@link ExecutionAttemptRepository.createAttempt} onwards, so a
406
+ * record that omits one describes an attempt that cannot exist. Requiring them
407
+ * is what makes that omission a type error at the place the record is built,
408
+ * rather than a default silently resolved at each place it is read.
91
409
  */
92
- interface ExecutionAttemptRecord {
410
+ interface ExecutionAttemptRecord extends AttemptControlState {
93
411
  /** Authority-created attempt identifier. */
94
412
  readonly executionAttemptId: string;
95
- /** Workflow execution identifier this attempt belongs to. */
96
- readonly executionId: string;
413
+ /** Owner identifier of the aggregate this attempt belongs to. */
414
+ readonly executionId: ExecutionOwnerId;
97
415
  /** Current lifecycle status of the attempt. */
98
416
  readonly status: ExecutionAttemptStatus;
99
417
  /** Provider allocation reference, set after allocation recording. */
@@ -116,7 +434,7 @@ interface ExecutionAttemptRecord {
116
434
  * Immutable alongside {@link providerId}. Remediation reads it to decide
117
435
  * whether losing the provisioning process also loses the allocation.
118
436
  */
119
- readonly allocationLifetime: WorkerNodeAllocationLifetime | null;
437
+ readonly allocationLifetime: WorkerAllocationLifetime | null;
120
438
  /**
121
439
  * Provisioner process incarnation that performed the provider call, or
122
440
  * `null` before provisioning began.
@@ -182,7 +500,7 @@ interface RecoverableAttemptRecord extends ExecutionAttemptRecord {
182
500
  /** Always bound for recoverable attempts. */
183
501
  readonly providerId: string;
184
502
  /** Always bound for recoverable attempts. */
185
- readonly allocationLifetime: WorkerNodeAllocationLifetime;
503
+ readonly allocationLifetime: WorkerAllocationLifetime;
186
504
  /** Always bound for recoverable attempts. */
187
505
  readonly provisionerIncarnationId: string;
188
506
  }
@@ -194,8 +512,8 @@ interface RecoverableAttemptRecord extends ExecutionAttemptRecord {
194
512
  interface ExecutionAttemptCreate {
195
513
  /** Authority-created attempt identifier. */
196
514
  readonly executionAttemptId: string;
197
- /** Workflow execution identifier. */
198
- readonly executionId: string;
515
+ /** Owner identifier the attempt belongs to. */
516
+ readonly executionId: ExecutionOwnerId;
199
517
  }
200
518
  /**
201
519
  * Input for claiming the provisioning phase of an attempt.
@@ -208,12 +526,12 @@ interface ExecutionAttemptCreate {
208
526
  interface BeginProvisioningInput {
209
527
  /** Attempt whose provider call is about to begin. */
210
528
  readonly executionAttemptId: string;
211
- /** Workflow execution identifier the attempt must belong to. */
212
- readonly executionId: string;
529
+ /** Owner identifier the attempt must belong to. */
530
+ readonly executionId: ExecutionOwnerId;
213
531
  /** Provider to bind to the attempt, immutably. */
214
532
  readonly providerId: string;
215
533
  /** Allocation lifetime declared by that provider, immutably. */
216
- readonly allocationLifetime: WorkerNodeAllocationLifetime;
534
+ readonly allocationLifetime: WorkerAllocationLifetime;
217
535
  /** Provisioner process incarnation performing the call, immutably. */
218
536
  readonly provisionerIncarnationId: string;
219
537
  /** Controller process incarnation that will hold the initial claim. */
@@ -228,14 +546,22 @@ interface BeginProvisioningInput {
228
546
  * and returns the canonical outcome for convergence. Outcome commitment
229
547
  * carries no claim: a worker's answer never depends on who currently owns
230
548
  * the attempt's provider operation.
549
+ * @typeParam TOutcome - Owner-specific outcome type committed per attempt.
231
550
  */
232
- interface ExecutionAttemptOutcomeCommit {
551
+ interface ExecutionAttemptOutcomeCommit<TOutcome> {
233
552
  /** Authority-created attempt identifier. */
234
553
  readonly executionAttemptId: string;
235
- /** Workflow execution identifier. */
236
- readonly executionId: string;
237
- /** Terminal workflow result to commit. */
238
- readonly result: WorkflowRunResult;
554
+ /** Owner identifier the attempt belongs to. */
555
+ readonly executionId: ExecutionOwnerId;
556
+ /**
557
+ * The rendering to commit, from
558
+ * {@link ExecutionAttemptRepository.canonicalizeOutcome}.
559
+ *
560
+ * A rendering rather than a raw outcome so the value a caller validated and
561
+ * the value that becomes durable are the same one: the caller renders the
562
+ * submission once and never reads its own object again.
563
+ */
564
+ readonly result: DurableOutcome<TOutcome>;
239
565
  }
240
566
  /** Input for extending the lease of a currently held provider operation. */
241
567
  interface RenewProviderOperationClaimInput {
@@ -311,8 +637,8 @@ interface RecordAllocationInput {
311
637
  interface RecordProvisioningAbsentInput {
312
638
  /** Claim authorizing the record. */
313
639
  readonly claim: ProviderOperationClaim;
314
- /** Workflow execution identifier the attempt must belong to. */
315
- readonly executionId: string;
640
+ /** Owner identifier the attempt must belong to. */
641
+ readonly executionId: ExecutionOwnerId;
316
642
  /** Bounded evidence supporting the absence claim. */
317
643
  readonly evidence: BoundedRecoveryEvidence;
318
644
  }
@@ -327,8 +653,8 @@ interface RecordProvisioningAbsentInput {
327
653
  interface RecordProvisionerIncarnationLostInput {
328
654
  /** Claim authorizing the record. */
329
655
  readonly claim: ProviderOperationClaim;
330
- /** Workflow execution identifier the attempt must belong to. */
331
- readonly executionId: string;
656
+ /** Owner identifier the attempt must belong to. */
657
+ readonly executionId: ExecutionOwnerId;
332
658
  /** Proof that a specific provisioner process incarnation is gone. */
333
659
  readonly proof: ProcessBoundProvisionerLossProof;
334
660
  }
@@ -348,8 +674,8 @@ interface RecordAllocationTerminatedInput {
348
674
  interface RecordInfrastructureFailureInput {
349
675
  /** Claim authorizing the settlement. */
350
676
  readonly claim: ProviderOperationClaim;
351
- /** Workflow execution identifier the attempt must belong to. */
352
- readonly executionId: string;
677
+ /** Owner identifier the attempt must belong to. */
678
+ readonly executionId: ExecutionOwnerId;
353
679
  }
354
680
  /**
355
681
  * Input for a compare-and-set evolution of an allocation reference.
@@ -365,8 +691,8 @@ interface RecordInfrastructureFailureInput {
365
691
  interface AllocationRefEvolution {
366
692
  /** Claim authorizing the evolution. */
367
693
  readonly claim: ProviderOperationClaim;
368
- /** Workflow execution identifier the attempt must belong to. */
369
- readonly executionId: string;
694
+ /** Owner identifier the attempt must belong to. */
695
+ readonly executionId: ExecutionOwnerId;
370
696
  /**
371
697
  * The allocation reference the caller believes is currently stored.
372
698
  *
@@ -381,6 +707,78 @@ interface AllocationRefEvolution {
381
707
  /** The new allocation reference to store if the CAS check passes. */
382
708
  readonly nextRef: ProviderAllocationRef;
383
709
  }
710
+ /**
711
+ * Input for registering a runtime incarnation as an attempt's endpoint.
712
+ *
713
+ * `executionId` is the active-attempt fence, not merely an ownership check: a
714
+ * superseded attempt must never acquire a fresh runtime endpoint, because
715
+ * nothing would ever address it again.
716
+ *
717
+ * No generation is supplied. The repository allocates it, exactly as
718
+ * {@link ExecutionAttemptRepository.beginProvisioning} mints the first claim,
719
+ * so a runtime can never propose a fence for itself.
720
+ */
721
+ interface RegisterRuntimeInput {
722
+ /** Attempt whose runtime endpoint is being registered. */
723
+ readonly executionAttemptId: string;
724
+ /** Owner identifier the attempt must belong to, and be active for. */
725
+ readonly executionId: ExecutionOwnerId;
726
+ /** Identifier of this concrete runtime incarnation, unique per boot. */
727
+ readonly runtimeIncarnationId: string;
728
+ }
729
+ /**
730
+ * Input for admitting one operation through an attempt's start gate.
731
+ *
732
+ * `admissionKey` is the caller's idempotency key and the only thing that makes
733
+ * a retry answerable: the repository mints the operation identifier, so a
734
+ * caller that lost the reply has no other way to ask which operation it got.
735
+ */
736
+ interface AdmitOperationInput {
737
+ /** Attempt the operation would run under. */
738
+ readonly executionAttemptId: string;
739
+ /** Owner identifier the attempt must belong to, and be active for. */
740
+ readonly executionId: ExecutionOwnerId;
741
+ /** Kind of operation being admitted. */
742
+ readonly operationKind: ExecutionAttemptOperationKind;
743
+ /** Caller-chosen idempotency key for this admission. */
744
+ readonly admissionKey: string;
745
+ /** Runtime generation the caller fences the admission against. */
746
+ readonly runtimeGeneration: number;
747
+ }
748
+ /**
749
+ * Input for completing the operation an attempt currently runs.
750
+ *
751
+ * Carries no `executionId`: completion frees a slot the attempt already
752
+ * occupies, and a superseded attempt owes that release just as much as an
753
+ * active one does. Refusing it would strand the operation forever.
754
+ */
755
+ interface CompleteOperationInput {
756
+ /** Attempt whose active operation is completing. */
757
+ readonly executionAttemptId: string;
758
+ /** Operation the caller believes it is completing. */
759
+ readonly operationId: string;
760
+ /** Runtime generation the completion is fenced against. */
761
+ readonly runtimeGeneration: number;
762
+ }
763
+ /**
764
+ * Input for recording that a registered runtime proved itself ready.
765
+ *
766
+ * Carries `executionId`, unlike {@link CompleteOperationInput}: completion
767
+ * releases a slot the attempt already occupies, but readiness asserts that the
768
+ * attempt's endpoint is current, and an attempt superseded between the probe's
769
+ * completion and this write no longer has a current endpoint. The generation
770
+ * fence alone cannot see that — a superseded attempt keeps its generation.
771
+ */
772
+ interface MarkRuntimeReadyInput {
773
+ /** Attempt whose runtime proved ready. */
774
+ readonly executionAttemptId: string;
775
+ /** Owner identifier the attempt must belong to, and be active for. */
776
+ readonly executionId: ExecutionOwnerId;
777
+ /** Generation the readiness belongs to. */
778
+ readonly runtimeGeneration: number;
779
+ /** ISO-8601 instant at which readiness was observed. */
780
+ readonly readyAt: string;
781
+ }
384
782
  /**
385
783
  * Durable decision for claiming provider provisioning ownership.
386
784
  *
@@ -510,7 +908,7 @@ type ProvisionerIncarnationLossDecision = {
510
908
  readonly kind: 'recorded';
511
909
  } | {
512
910
  readonly kind: 'not-process-bound';
513
- readonly allocationLifetime: WorkerNodeAllocationLifetime | null;
911
+ readonly allocationLifetime: WorkerAllocationLifetime | null;
514
912
  } | {
515
913
  readonly kind: 'incarnation-mismatch';
516
914
  readonly provisionerIncarnationId: string | null;
@@ -620,25 +1018,220 @@ type PendingAttemptAbandonmentDecision = {
620
1018
  * Durable outcome decision returned by {@link ExecutionAttemptRepository.commitOutcome}.
621
1019
  *
622
1020
  * - `accepted`: the outcome was committed as canonical for the first time.
623
- * - `duplicate`: an outcome {@link sameWorkflowResult} judges identical to the
624
- * committed one was submitted again; this is a replay. The committed outcome
625
- * is reported, never the caller's copy of it.
1021
+ * The stored text decoded is reported, never the caller's copy of it.
1022
+ * - `duplicate`: an outcome whose durable text {@link sameDurableOutcome}
1023
+ * judges identical to the committed one was submitted again; this is a
1024
+ * replay. The committed outcome is reported, never the caller's copy of it.
626
1025
  * - `conflict`: the attempt already reached a different terminal state — either
627
1026
  * a different committed outcome, or a competing terminal transition that
628
1027
  * settled it without one.
629
1028
  * - `fenced`: the attempt is no longer the active attempt for this execution.
1029
+ *
1030
+ * Both settling kinds carry `text`: the durable text the attempt holds for
1031
+ * this outcome. For `accepted` that is the text the commit just wrote; for
1032
+ * `duplicate` it is the text the earlier commit wrote, which is not
1033
+ * necessarily the retry's own rendering — {@link sameDurableOutcome} judges
1034
+ * two texts the same outcome while member order, and anything else a codec
1035
+ * may render differently, still differs between them. A caller that needs a
1036
+ * copy of the committed outcome nobody else has held decodes this text
1037
+ * through {@link ExecutionAttemptRepository.decodeOutcome}; decoding its own
1038
+ * submission's text instead would hand out the retry's representation rather
1039
+ * than the committed one.
1040
+ * @typeParam TOutcome - Owner-specific outcome type committed per attempt.
630
1041
  */
631
- type ExecutionAttemptOutcomeDecision = {
1042
+ type ExecutionAttemptOutcomeDecision<TOutcome> = {
632
1043
  readonly kind: 'accepted';
633
- readonly outcome: WorkflowRunResult;
1044
+ readonly outcome: TOutcome;
1045
+ readonly text: string;
634
1046
  } | {
635
1047
  readonly kind: 'duplicate';
636
- readonly outcome: WorkflowRunResult;
1048
+ readonly outcome: TOutcome;
1049
+ readonly text: string;
637
1050
  } | {
638
1051
  readonly kind: 'conflict';
639
1052
  } | {
640
1053
  readonly kind: 'fenced';
641
1054
  };
1055
+ /**
1056
+ * Durable decision for registering a runtime incarnation as an attempt's
1057
+ * endpoint.
1058
+ *
1059
+ * - `registered`: the incarnation now owns the attempt's runtime endpoint at
1060
+ * `runtimeGeneration`, and everything it later presents must carry that
1061
+ * generation. Readiness starts unproven.
1062
+ * - `duplicate`: the attempt already holds exactly this incarnation. The
1063
+ * report is a replay, so the stored generation is reported unchanged
1064
+ * together with the readiness that generation has — `runtimeReadyAt` is
1065
+ * `null` when readiness was not proven yet, and an instant when it was,
1066
+ * which is what lets a caller tell "register again" from "already ready"
1067
+ * without a second read.
1068
+ * - `not-found`: no such attempt, or it does not belong to the named owner.
1069
+ * - `resolved`: the attempt has settled, so it will never run anything again.
1070
+ * - `fenced`: the attempt is no longer the active attempt for its owner.
1071
+ * - `not-allocated`: no allocation is recorded, or the recorded one is durably
1072
+ * confirmed terminated and only awaits its settlement, so there is no
1073
+ * infrastructure a runtime could be the endpoint of.
1074
+ * - `operation-active`: a workload operation is running against the current
1075
+ * generation. Registering would fence it mid-flight, so the reported
1076
+ * operation must complete first. A `runtime-probe` left active is not in the
1077
+ * way: the probe is the authority's own proof of an endpoint, and one that
1078
+ * was never completed belongs to a handshake that died. Registration
1079
+ * reclaims it in the same write that allocates the new generation, so a
1080
+ * crashed handshake cannot block the attempt's next incarnation.
1081
+ */
1082
+ type RuntimeRegistrationDecision = {
1083
+ readonly kind: 'registered';
1084
+ readonly runtimeGeneration: number;
1085
+ } | {
1086
+ readonly kind: 'duplicate';
1087
+ readonly runtimeGeneration: number;
1088
+ readonly runtimeReadyAt: string | null;
1089
+ } | {
1090
+ readonly kind: 'not-found';
1091
+ } | {
1092
+ readonly kind: 'resolved';
1093
+ } | {
1094
+ readonly kind: 'fenced';
1095
+ } | {
1096
+ readonly kind: 'not-allocated';
1097
+ } | {
1098
+ readonly kind: 'operation-active';
1099
+ readonly operationId: string;
1100
+ };
1101
+ /**
1102
+ * Durable decision for admitting one operation through an attempt's start gate.
1103
+ *
1104
+ * - `admitted`: the operation now occupies the attempt, under the reported
1105
+ * identifier and fenced against the reported generation.
1106
+ * - `duplicate`: an operation admitted under the same `admissionKey` is already
1107
+ * the active one. The retry receives that operation's identifier and the
1108
+ * generation it was admitted under rather than a second admission.
1109
+ * - `not-found`: no such attempt, or it does not belong to the named owner.
1110
+ * - `resolved`: the attempt has settled.
1111
+ * - `fenced`: the attempt is no longer the active attempt for its owner.
1112
+ * - `not-allocated`: no allocation is recorded, or the recorded one is durably
1113
+ * confirmed terminated and only awaits its settlement, so there is nothing
1114
+ * to run on.
1115
+ * - `operation-active`: a different operation already occupies the attempt.
1116
+ * - `gate-closed`: the attempt was superseded or settled, so it will never
1117
+ * admit another operation. Distinct from `fenced` and `resolved` because the
1118
+ * gate is the durable fact, and the two of them are how it came to be closed.
1119
+ * - `not-ready`: readiness has not been proven for the current generation.
1120
+ * Every kind but `runtime-probe` waits for it — the probe is precisely what
1121
+ * proves readiness, so it cannot require it.
1122
+ * - `stale-generation`: the caller fenced against a generation the attempt has
1123
+ * moved past. The current generation is reported so the caller can re-fence
1124
+ * rather than re-read.
1125
+ */
1126
+ type OperationAdmissionDecision = {
1127
+ readonly kind: 'admitted';
1128
+ readonly operationId: string;
1129
+ readonly runtimeGeneration: number; /** ISO-8601 instant the admission was recorded at. */
1130
+ readonly admittedAt: string;
1131
+ } | {
1132
+ readonly kind: 'duplicate';
1133
+ readonly operationId: string;
1134
+ readonly runtimeGeneration: number; /** ISO-8601 instant the first pass recorded the admission at. */
1135
+ readonly admittedAt: string;
1136
+ } | {
1137
+ readonly kind: 'not-found';
1138
+ } | {
1139
+ readonly kind: 'resolved';
1140
+ } | {
1141
+ readonly kind: 'fenced';
1142
+ } | {
1143
+ readonly kind: 'not-allocated';
1144
+ } | {
1145
+ readonly kind: 'operation-active';
1146
+ readonly operationId: string;
1147
+ } | {
1148
+ readonly kind: 'gate-closed';
1149
+ } | {
1150
+ readonly kind: 'not-ready';
1151
+ } | {
1152
+ readonly kind: 'stale-generation';
1153
+ readonly runtimeGeneration: number;
1154
+ };
1155
+ /**
1156
+ * Durable decision for completing the operation an attempt currently runs.
1157
+ *
1158
+ * - `completed`: the operation was the active one and the attempt is idle
1159
+ * again.
1160
+ * - `duplicate`: this operation was already completed. A replay, answered from
1161
+ * {@link AttemptControlState.lastCompletedOperationId} rather than from an
1162
+ * active operation that is by then gone.
1163
+ * - `mismatch`: a different operation occupies the attempt. The active one is
1164
+ * reported, because the caller's next move depends on which it is.
1165
+ * - `not-active`: no operation occupies the attempt and this one is not the
1166
+ * last completed one, so the caller is completing something that never ran.
1167
+ * - `stale-generation`: the completion is fenced against an older generation
1168
+ * than the operation it names, so it comes from a superseded runtime.
1169
+ * - `resolved`: the attempt has settled. Reported ahead of `not-active`
1170
+ * because a terminal settlement leaves the active operation in place
1171
+ * precisely so a late completion learns why nobody is waiting for it.
1172
+ * - `not-found`: no such attempt.
1173
+ */
1174
+ type OperationCompletionDecision = {
1175
+ readonly kind: 'completed';
1176
+ } | {
1177
+ readonly kind: 'duplicate';
1178
+ } | {
1179
+ readonly kind: 'mismatch';
1180
+ readonly activeOperationId: string;
1181
+ } | {
1182
+ readonly kind: 'not-active';
1183
+ } | {
1184
+ readonly kind: 'stale-generation';
1185
+ } | {
1186
+ readonly kind: 'resolved';
1187
+ } | {
1188
+ readonly kind: 'not-found';
1189
+ };
1190
+ /**
1191
+ * Durable decision for recording that a registered runtime proved itself ready.
1192
+ *
1193
+ * Evaluated in this order, in both realizations:
1194
+ * `not-found → resolved → fenced → not-allocated → stale-generation → duplicate → operation-active`.
1195
+ *
1196
+ * - `ready`: readiness is now durable for the fenced generation, at the
1197
+ * reported instant.
1198
+ * - `duplicate`: readiness was already recorded for this generation. The
1199
+ * instant reported is the stored one, not the caller's, so two callers
1200
+ * converge on one answer.
1201
+ * - `operation-active`: an operation occupies the attempt. Readiness is a
1202
+ * statement about an idle runtime, and recording it under a running
1203
+ * operation would claim a proof nothing performed.
1204
+ * - `stale-generation`: the caller fenced against a generation the attempt has
1205
+ * moved past, so the readiness it proved belongs to a runtime that is gone.
1206
+ * - `not-allocated`: no allocation is recorded, or the recorded one is durably
1207
+ * confirmed terminated and only awaits its settlement. A probe completed on
1208
+ * a dead allocation proves nothing that can be announced.
1209
+ * - `fenced`: the attempt is no longer the active attempt for its owner. Its
1210
+ * generation may still match, but a superseded attempt has no current
1211
+ * endpoint to declare ready.
1212
+ * - `resolved`: the attempt has settled.
1213
+ * - `not-found`: no such attempt for the given execution.
1214
+ */
1215
+ type RuntimeReadinessDecision = {
1216
+ readonly kind: 'ready';
1217
+ readonly acceptedAt: string;
1218
+ } | {
1219
+ readonly kind: 'duplicate';
1220
+ readonly acceptedAt: string;
1221
+ } | {
1222
+ readonly kind: 'operation-active';
1223
+ readonly operationId: string;
1224
+ } | {
1225
+ readonly kind: 'stale-generation';
1226
+ } | {
1227
+ readonly kind: 'not-allocated';
1228
+ } | {
1229
+ readonly kind: 'fenced';
1230
+ } | {
1231
+ readonly kind: 'resolved';
1232
+ } | {
1233
+ readonly kind: 'not-found';
1234
+ };
642
1235
  /**
643
1236
  * Passive injected port for durable execution attempt persistence.
644
1237
  *
@@ -682,11 +1275,37 @@ type ExecutionAttemptOutcomeDecision = {
682
1275
  * let a caller assert that infrastructure ended without ever recording the
683
1276
  * evidence that it did, and the settlement is irreversible.
684
1277
  *
685
- * 2. **Provider-side evidence is claim-fenced; workflow outcome is not.**
1278
+ * 2. **Provider-side evidence is claim-fenced; the worker outcome is not.**
686
1279
  * Every provider-side mutation requires the current generation and token.
687
1280
  * {@link commitOutcome} deliberately requires neither, so a worker can
688
1281
  * always deliver its canonical answer.
689
1282
  *
1283
+ * 3. **An attempt starts work through one gate, and the gate closes for
1284
+ * good.** {@link AttemptControlState.operationStartGate} is the single
1285
+ * durable ordering point between "this attempt may still run something" and
1286
+ * "it never will again". It opens at {@link createAttempt} and closes
1287
+ * exactly twice over an attempt's life, both times inside the transaction
1288
+ * that made the closing true: on the attempt a newer {@link createAttempt}
1289
+ * supersedes, and on the attempt a terminal settlement settles. Closing it
1290
+ * anywhere else, or reopening it, would let work begin on an attempt whose
1291
+ * answer is already fixed.
1292
+ *
1293
+ * The gate orders admission only. It never gates {@link commitOutcome}: a
1294
+ * settled attempt closes its gate and *keeps* its active operation, so a
1295
+ * worker's canonical answer and a late completion both still find the state
1296
+ * that explains them.
1297
+ *
1298
+ * The runtime fence beside it is monotonic in the same one-way sense.
1299
+ * {@link registerRuntime} allocates each generation, refuses while an
1300
+ * operation is active, and clears readiness when it advances — so a
1301
+ * generation always names one incarnation, and readiness always names one
1302
+ * generation.
1303
+ *
1304
+ * Every refusal these transitions report is evaluated in one fixed order,
1305
+ * stated with {@link RuntimeRegistrationDecision} and
1306
+ * {@link OperationAdmissionDecision}. A realization that reorders it is
1307
+ * non-conforming.
1308
+ *
690
1309
  * An operation stays remediable after its attempt stops being the active
691
1310
  * attempt for its execution. Claim-fenced discovery, absence, cleanup, and
692
1311
  * terminal convergence may update such an attempt and close its operation,
@@ -725,9 +1344,46 @@ type ExecutionAttemptOutcomeDecision = {
725
1344
  * — including when the caller's claim is also stale. Validating after the
726
1345
  * guards would make the rejection depend on ownership, so the same malformed
727
1346
  * payload would throw against one implementation and return `stale` from
728
- * another.
1347
+ * another. Submitted outcomes follow the same rule through the injected
1348
+ * {@link OutcomeCodec}: `parse` runs before the durable outcome decision. A
1349
+ * committed outcome is always a defined value — a nullish outcome is outside
1350
+ * this port, because "no outcome committed" is itself recorded as the absence
1351
+ * of a stored value and the two would be indistinguishable.
1352
+ *
1353
+ * **The codec's durable text is what an attempt holds, and it is rendered
1354
+ * exactly once per submission.** {@link canonicalizeOutcome} produces the
1355
+ * {@link DurableOutcome} — the text to persist and the outcome that text
1356
+ * reads back as — and {@link commitOutcome} receives that rendering rather
1357
+ * than a raw value, persisting `text` verbatim. What an attempt reports is
1358
+ * therefore never the submitter's copy, which a normalizing codec makes a
1359
+ * different value, and never a second serialization, which a codec whose
1360
+ * serialization is not a fixed point makes a different text. Every later
1361
+ * decision about that outcome is made on the stored text or on the value it
1362
+ * yields: {@link commitOutcome} compares a retry's rendered text against the
1363
+ * stored one through {@link sameDurableOutcome}.
1364
+ *
1365
+ * **Every stored outcome is parsed before it decides anything.** An
1366
+ * implementation that finds a committed text takes it through `parse` ahead
1367
+ * of the duplicate-or-conflict decision, not only on the branch that reports
1368
+ * a value. A text the codec rejects is broken durable state — corruption, or
1369
+ * a codec changed under an existing row — and it fails loudly rather than
1370
+ * reaching the caller as an ordinary competing outcome. For the same reason
1371
+ * an outcome is decoded on every read instead of being handed out as one
1372
+ * shared instance: a codec may reconstruct a mutable object — one that no
1373
+ * freeze even reaches, or that cannot be frozen at all — and one reader
1374
+ * mutating it must not change what the next read reports.
1375
+ * {@link decodeOutcome} is that read, stated on the port so a caller holding
1376
+ * only a durable text can perform it too.
1377
+ *
1378
+ * **An `accepted` decision reports that same fresh decode of the text it just
1379
+ * stored**, not the outcome half of the rendering it was handed. The two are
1380
+ * one value only until someone touches it: a caller validates
1381
+ * {@link DurableOutcome.outcome} before the commit, and a mutable outcome it
1382
+ * changed there would otherwise be reported back as the committed one — a
1383
+ * value no reload of the attempt ever yields.
1384
+ * @typeParam TOutcome - Owner-specific outcome type committed per attempt.
729
1385
  */
730
- interface ExecutionAttemptRepository {
1386
+ interface ExecutionAttemptRepository<TOutcome> {
731
1387
  /**
732
1388
  * Persist a new execution attempt record.
733
1389
  *
@@ -735,6 +1391,17 @@ interface ExecutionAttemptRepository {
735
1391
  * `executionAttemptId` generation; the repository only persists. The new
736
1392
  * attempt atomically becomes the active attempt for its execution.
737
1393
  *
1394
+ * The new attempt starts with its {@link AttemptControlState} at rest:
1395
+ * generation `0`, no incarnation, no readiness, no active operation, and
1396
+ * {@link AttemptControlState.operationStartGate} `open`.
1397
+ *
1398
+ * **The attempt it supersedes has its start gate closed in this same
1399
+ * transaction**, alongside the active pointer moving. A superseded attempt
1400
+ * whose gate stayed open could admit an operation between the pointer move
1401
+ * and any later cleanup, which is work begun on an attempt nobody addresses
1402
+ * any more. The pointer and the gate therefore become true together or not
1403
+ * at all.
1404
+ *
738
1405
  * `executionAttemptId` is unique for all time. Creating an attempt whose
739
1406
  * identifier already exists is a caller bug and is rejected — never
740
1407
  * answered with a decision and never applied. There is no correct way to
@@ -905,16 +1572,145 @@ interface ExecutionAttemptRepository {
905
1572
  * @returns The durable termination decision.
906
1573
  */
907
1574
  recordAllocationTerminated(input: RecordAllocationTerminatedInput): Promise<AllocationTerminationDecision>;
1575
+ /**
1576
+ * Register a runtime incarnation as the attempt's endpoint.
1577
+ *
1578
+ * The repository allocates the generation — the caller supplies only the
1579
+ * incarnation identifier, which is both what it is registering and the
1580
+ * idempotency key for having registered it. A registration that succeeds
1581
+ * advances the generation by exactly one and clears
1582
+ * {@link AttemptControlState.runtimeReadyAt}, because the readiness the
1583
+ * previous incarnation proved says nothing about this one.
1584
+ *
1585
+ * It refuses while an operation is active. Advancing the generation there
1586
+ * would fence a running operation's own completion, so the reported
1587
+ * operation has to finish first — and this is why a replay by the incarnation
1588
+ * that is already registered is answered `duplicate` ahead of that refusal:
1589
+ * the operation in the way is frequently the very probe that registration
1590
+ * started.
1591
+ *
1592
+ * The refusal order is the fixed one; see {@link RuntimeRegistrationDecision}.
1593
+ * @param input - Attempt identity, owning execution, and the runtime incarnation.
1594
+ * @returns The durable registration decision.
1595
+ */
1596
+ registerRuntime(input: RegisterRuntimeInput): Promise<RuntimeRegistrationDecision>;
1597
+ /**
1598
+ * Admit one operation through the attempt's start gate.
1599
+ *
1600
+ * At most one operation occupies an attempt at a time, and the repository
1601
+ * mints its identifier. `admissionKey` is what makes a retry answerable: a
1602
+ * second admission presenting the key the active operation was admitted
1603
+ * under receives that operation's identifier rather than a second slot.
1604
+ *
1605
+ * Every kind requires proven readiness except `runtime-probe`, which is
1606
+ * admitted while {@link AttemptControlState.runtimeReadyAt} is still `null` —
1607
+ * the probe is the bounded no-op that *proves* the endpoint, so requiring
1608
+ * readiness of it would make readiness unreachable.
1609
+ *
1610
+ * The refusal order is the fixed one; see {@link OperationAdmissionDecision}.
1611
+ * @param input - Attempt identity, owning execution, kind, idempotency key, and fence.
1612
+ * @returns The durable admission decision.
1613
+ */
1614
+ admitOperation(input: AdmitOperationInput): Promise<OperationAdmissionDecision>;
1615
+ /**
1616
+ * Release the attempt's active operation.
1617
+ *
1618
+ * Clears the four active-operation members in one write and records the
1619
+ * completed identifier, so a replay is answered `duplicate` rather than
1620
+ * mistaken for a completion of something that never ran.
1621
+ *
1622
+ * Deliberately unfenced by the active-attempt pointer: a superseded attempt
1623
+ * owes the release exactly as much as an active one, and refusing it would
1624
+ * leave the operation occupying the attempt for good.
1625
+ * @param input - Attempt identity, the operation being completed, and its fence.
1626
+ * @returns The durable completion decision.
1627
+ */
1628
+ completeOperation(input: CompleteOperationInput): Promise<OperationCompletionDecision>;
1629
+ /**
1630
+ * Record that the registered runtime proved itself ready.
1631
+ *
1632
+ * Written only for the generation the caller fences against, so a proof that
1633
+ * a superseded incarnation produced can never mark the current one ready, and
1634
+ * only while the attempt is still the active attempt for its owner, so a
1635
+ * proof that completed before the attempt was superseded is refused `fenced`
1636
+ * rather than announced for an endpoint nobody will address. Recording is
1637
+ * idempotent: a second call for the same generation reports the instant
1638
+ * already stored, never the caller's own.
1639
+ * @param input - Attempt identity, the generation the proof belongs to, and when it was observed.
1640
+ * @returns The durable readiness decision.
1641
+ */
1642
+ markRuntimeReady(input: MarkRuntimeReadyInput): Promise<RuntimeReadinessDecision>;
1643
+ /**
1644
+ * Read an attempt's runtime and operation control state.
1645
+ *
1646
+ * The recovery read of {@link AttemptControlState}: a process that lost its
1647
+ * own memory of an attempt — a restart, a second controller — asks what the
1648
+ * durable state is instead of inferring it. Unfenced and regardless of
1649
+ * status, exactly like
1650
+ * {@link ExecutionAttemptRecoveryOperations.getAttemptWithAllocation}, because
1651
+ * the state of a superseded or settled attempt is precisely what a recovering
1652
+ * process needs to see.
1653
+ * @param executionAttemptId - Attempt whose control state to read.
1654
+ * @returns The control state, or `null` when no such attempt exists.
1655
+ */
1656
+ getAttemptControlState(executionAttemptId: string): Promise<AttemptControlState | null>;
908
1657
  /**
909
1658
  * Retrieve the active attempt for a given execution.
910
1659
  *
911
1660
  * Returns `null` when the attempt does not exist or has been superseded
912
1661
  * (fenced) by a newer attempt for the same execution.
913
- * @param executionId - Workflow execution identifier.
1662
+ * @param executionId - Owner identifier the attempt belongs to.
914
1663
  * @param executionAttemptId - Attempt identifier to look up.
915
1664
  * @returns The attempt record if active, or `null`.
916
1665
  */
917
- getActiveAttempt(executionId: string, executionAttemptId: string): Promise<ExecutionAttemptRecord | null>;
1666
+ getActiveAttempt(executionId: ExecutionOwnerId, executionAttemptId: string): Promise<ExecutionAttemptRecord | null>;
1667
+ /**
1668
+ * Render a submission as the durable fact a commit of it would write.
1669
+ *
1670
+ * **The port renders an outcome exactly once, and this is where.** A
1671
+ * realization stores the codec's durable text and reports what a reload of
1672
+ * that text yields, so the value an owner converges on is not in general
1673
+ * the value the submitter handed in — a codec may normalize while
1674
+ * serializing. This member produces both halves of that fact together,
1675
+ * without committing anything, so a caller can validate the outcome it will
1676
+ * actually receive and then hand the very same rendering to
1677
+ * {@link commitOutcome}.
1678
+ *
1679
+ * Carrying the rendering rather than re-deriving it is what closes the gap
1680
+ * between the two calls: the submitter's object is read once, so neither a
1681
+ * mutation of it nor a second serialization can make the committed outcome
1682
+ * differ from the validated one.
1683
+ *
1684
+ * Synchronous and free of durable effects: it consults the injected
1685
+ * {@link OutcomeCodec} and nothing else — {@link durableOutcome} is the
1686
+ * rendering rule, and a realization has no freedom to deviate from it.
1687
+ * @param outcome - Outcome a caller is about to submit.
1688
+ * @returns The text a commit would persist and the outcome that text yields.
1689
+ * @throws When the codec rejects the outcome or its own durable text.
1690
+ */
1691
+ canonicalizeOutcome(outcome: TOutcome): DurableOutcome<TOutcome>;
1692
+ /**
1693
+ * Read a committed durable text back as the outcome it holds.
1694
+ *
1695
+ * The counterpart of {@link canonicalizeOutcome}: that member says what a
1696
+ * commit writes, this one says what a read of that text yields. Both are
1697
+ * the codec's rules rather than a realization's, so
1698
+ * {@link decodeDurableOutcome} is the rendering and a realization has no
1699
+ * freedom to deviate from it.
1700
+ *
1701
+ * It exists because the durable text is the only copy of an outcome nobody
1702
+ * can have touched. Every value the port hands out is decoded from it, and
1703
+ * a caller that has passed one on — to an owner validation, to convergence
1704
+ * — and needs the committed outcome again asks for a fresh decode instead
1705
+ * of reusing a value some other step may have mutated. Each call returns
1706
+ * its own value; a mutation of one changes nothing the next one reports.
1707
+ *
1708
+ * Synchronous and free of durable effects: the caller supplies the text.
1709
+ * @param text - Durable text an attempt committed, as {@link DurableOutcome.text} carries it.
1710
+ * @returns The outcome that text holds, held by nobody else.
1711
+ * @throws When the text is not JSON, or not JSON the codec accepts.
1712
+ */
1713
+ decodeOutcome(text: string): TOutcome;
918
1714
  /**
919
1715
  * Commit a terminal outcome for an attempt.
920
1716
  *
@@ -928,12 +1724,13 @@ interface ExecutionAttemptRepository {
928
1724
  *
929
1725
  * 1. `fenced` — the attempt is no longer the active attempt for its
930
1726
  * execution. Evaluated first because `accepted` and `duplicate` oblige
931
- * the caller to converge workflow state, and a superseded attempt must
1727
+ * the caller to converge owner state, and a superseded attempt must
932
1728
  * never drive that convergence.
933
1729
  * 2. `duplicate` / `conflict` — an outcome is already committed for this
934
- * attempt: `duplicate` when {@link sameWorkflowResult} judges it
935
- * canonically equal, including member-order-insensitive objects;
936
- * `conflict` when it differs under that rule.
1730
+ * attempt: `duplicate` when {@link sameDurableOutcome} judges the text
1731
+ * the submission would commit canonically equal to the stored one,
1732
+ * including member-order-insensitive objects; `conflict` when it differs
1733
+ * under that rule.
937
1734
  * 3. `conflict` — a competing terminal transition already settled the
938
1735
  * attempt without committing an outcome, that is
939
1736
  * {@link recordInfrastructureFailure} or
@@ -943,10 +1740,24 @@ interface ExecutionAttemptRepository {
943
1740
  * `settlementKind` nor reopen the attempt.
944
1741
  * 4. `accepted` — the outcome becomes canonical, the attempt settles as
945
1742
  * `outcome`, and its operation closes.
946
- * @param input - Attempt identity and terminal result to commit.
1743
+ *
1744
+ * The submission arrives already rendered, as the {@link DurableOutcome} the
1745
+ * caller obtained from {@link canonicalizeOutcome}. An implementation
1746
+ * persists `result.text` verbatim and never re-serializes: a second
1747
+ * rendering is what would let the durable answer differ from the one the
1748
+ * owner validated. What it reports for `accepted` is that text decoded
1749
+ * again — {@link decodeOutcome} of `result.text` — rather than
1750
+ * `result.outcome`, which the caller has held since before its own
1751
+ * validation and may have mutated there.
1752
+ *
1753
+ * A settling decision also reports the durable text the attempt holds:
1754
+ * `result.text` for `accepted`, and the stored text for `duplicate` — the
1755
+ * record's own, not the submission's, because the two are the same outcome
1756
+ * without being the same text.
1757
+ * @param input - Attempt identity and the rendering to commit.
947
1758
  * @returns The durable decision with the canonical outcome when applicable.
948
1759
  */
949
- commitOutcome(input: ExecutionAttemptOutcomeCommit): Promise<ExecutionAttemptOutcomeDecision>;
1760
+ commitOutcome(input: ExecutionAttemptOutcomeCommit<TOutcome>): Promise<ExecutionAttemptOutcomeDecision<TOutcome>>;
950
1761
  /**
951
1762
  * Settle a pending attempt when dispatch cannot continue before provisioning.
952
1763
  *
@@ -954,10 +1765,10 @@ interface ExecutionAttemptRepository {
954
1765
  * mean provisioning already began, so the caller must converge the provider
955
1766
  * operation instead of abandoning the attempt.
956
1767
  * @param executionAttemptId - Pending attempt to abandon.
957
- * @param executionId - Workflow execution identifier.
1768
+ * @param executionId - Owner identifier the attempt belongs to.
958
1769
  * @returns The durable abandonment decision.
959
1770
  */
960
- abandonPendingAttempt(executionAttemptId: string, executionId: string): Promise<PendingAttemptAbandonmentDecision>;
1771
+ abandonPendingAttempt(executionAttemptId: string, executionId: ExecutionOwnerId): Promise<PendingAttemptAbandonmentDecision>;
961
1772
  /**
962
1773
  * Recovery operations, present only on a recovery-capable repository.
963
1774
  *
@@ -1047,10 +1858,10 @@ interface ExecutionAttemptRecoveryOperations {
1047
1858
  * same millisecond from ordering differently on two stores. An
1048
1859
  * implementation that returned an arbitrary order would make a caller that
1049
1860
  * bounds its pass reclaim a different subset on each realization.
1050
- * @param executionId - Workflow execution identifier.
1861
+ * @param executionId - Owner identifier the attempts belong to.
1051
1862
  * @returns Allocated, non-settled attempts eligible for recovery, oldest first.
1052
1863
  */
1053
- getRecoverableAttempts(executionId: string): Promise<readonly RecoverableAttemptRecord[]>;
1864
+ getRecoverableAttempts(executionId: ExecutionOwnerId): Promise<readonly RecoverableAttemptRecord[]>;
1054
1865
  }
1055
1866
  //#endregion
1056
- export { RecoverableAttemptRecord as A, ProvisioningClaimDecision as C, RecordProviderOperationUncertaintyInput as D, RecordInfrastructureFailureInput as E, TakeOverProviderOperationInput as M, sameAllocationRef as N, RecordProvisionerIncarnationLostInput as O, sameWorkflowResult as P, ProvisioningAbsenceDecision as S, RecordAllocationTerminatedInput as T, ExecutionAttemptStatus as _, BeginProvisioningInput as a, PendingAttemptAbandonmentDecision as b, EXECUTION_ATTEMPT_SETTLEMENT_KINDS as c, ExecutionAttemptOutcomeCommit as d, ExecutionAttemptOutcomeDecision as f, ExecutionAttemptSettlementKind as g, ExecutionAttemptRepository as h, AllocationTerminationDecision as i, RenewProviderOperationClaimInput as j, RecordProvisioningAbsentInput as k, EXECUTION_ATTEMPT_STATUSES as l, ExecutionAttemptRecoveryOperations as m, AllocationRefEvolution as n, DiscoveredAllocationDecision as o, ExecutionAttemptRecord as p, AllocationRefEvolutionDecision as r, DuplicateExecutionAttemptError as s, AllocationRecordingDecision as t, ExecutionAttemptCreate as u, HandoffProviderOperationInput as v, RecordAllocationInput as w, ProvisionerIncarnationLossDecision as x, InfrastructureFailureDecision as y };
1867
+ export { OutcomeCodec as A, RecordProvisioningAbsentInput as B, ExecutionAttemptStatus as C, MarkRuntimeReadyInput as D, InfrastructureFailureDecision as E, RecordAllocationInput as F, RuntimeRegistrationDecision as G, RegisterRuntimeInput as H, RecordAllocationTerminatedInput as I, durableOutcome as J, TakeOverProviderOperationInput as K, RecordInfrastructureFailureInput as L, ProvisionerIncarnationLossDecision as M, ProvisioningAbsenceDecision as N, OperationAdmissionDecision as O, ProvisioningClaimDecision as P, RecordProviderOperationUncertaintyInput as R, ExecutionAttemptSettlementKind as S, HandoffProviderOperationInput as T, RenewProviderOperationClaimInput as U, RecoverableAttemptRecord as V, RuntimeReadinessDecision as W, sameDurableOutcome as X, sameAllocationRef as Y, ExecutionAttemptOutcomeCommit as _, AllocationRefEvolutionDecision as a, ExecutionAttemptRecoveryOperations as b, AttemptOperationStartGate as c, DiscoveredAllocationDecision as d, DuplicateExecutionAttemptError as f, ExecutionAttemptCreate as g, EXECUTION_ATTEMPT_STATUSES as h, AllocationRefEvolution as i, PendingAttemptAbandonmentDecision as j, OperationCompletionDecision as k, BeginProvisioningInput as l, EXECUTION_ATTEMPT_SETTLEMENT_KINDS as m, AdmitOperationInput as n, AllocationTerminationDecision as o, DurableOutcome as p, decodeDurableOutcome as q, AllocationRecordingDecision as r, AttemptControlState as s, ATTEMPT_OPERATION_START_GATES as t, CompleteOperationInput as u, ExecutionAttemptOutcomeDecision as v, ExecutionOwnerId as w, ExecutionAttemptRepository as x, ExecutionAttemptRecord as y, RecordProvisionerIncarnationLostInput as z };