@unrulysystems/native-motion 0.1.0-alpha.0

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 (117) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/LICENSE +21 -0
  3. package/README.md +55 -0
  4. package/android/build.gradle +24 -0
  5. package/android/src/main/AndroidManifest.xml +1 -0
  6. package/android/src/main/java/com/unrulysystems/nativemotion/GestureExclusionModule.kt +55 -0
  7. package/android/src/main/java/com/unrulysystems/nativemotion/NativeMotionPackage.kt +27 -0
  8. package/package.json +57 -0
  9. package/react-native.config.js +14 -0
  10. package/src/native/driver/instantWindow.ts +31 -0
  11. package/src/native/driver/strictModeReplay.ts +20 -0
  12. package/src/native/driver/uiLayoutEngine.ts +845 -0
  13. package/src/native/driver/uiLayoutGraph.ts +338 -0
  14. package/src/native/driver/uiValueChannel.ts +4640 -0
  15. package/src/native/driver/workletDriver.ts +3860 -0
  16. package/src/native/motion/AnimatePresence.tsx +1605 -0
  17. package/src/native/motion/LayoutGroup.tsx +163 -0
  18. package/src/native/motion/MotionConfig.tsx +400 -0
  19. package/src/native/motion/MotionRoot.tsx +250 -0
  20. package/src/native/motion/MotionView.tsx +6761 -0
  21. package/src/native/motion/addScaleCorrector.ts +97 -0
  22. package/src/native/motion/colorEndpointUiFeed.ts +32 -0
  23. package/src/native/motion/colorProjection.ts +39 -0
  24. package/src/native/motion/composeTransform.ts +271 -0
  25. package/src/native/motion/constraintMeasure.ts +157 -0
  26. package/src/native/motion/deferredPendingSnapshots.ts +25 -0
  27. package/src/native/motion/discreteProjection.ts +36 -0
  28. package/src/native/motion/dragAncestorPanContext.ts +28 -0
  29. package/src/native/motion/dragControls.ts +152 -0
  30. package/src/native/motion/dragGestureWiring.ts +1168 -0
  31. package/src/native/motion/dragHandoffBinding.ts +179 -0
  32. package/src/native/motion/dragHubStream.ts +756 -0
  33. package/src/native/motion/dragPropagationLock.ts +57 -0
  34. package/src/native/motion/driverValueChannel.ts +3288 -0
  35. package/src/native/motion/externalDragDriver.ts +214 -0
  36. package/src/native/motion/frameData.ts +31 -0
  37. package/src/native/motion/gestureBinding.ts +107 -0
  38. package/src/native/motion/gestureStateGate.ts +563 -0
  39. package/src/native/motion/gestureStateResolver.ts +286 -0
  40. package/src/native/motion/identityValueChannelControllerAdapter.ts +2043 -0
  41. package/src/native/motion/identityValueChannelControllerReconciliation.ts +176 -0
  42. package/src/native/motion/identityValueChannelLaneMarker.ts +14 -0
  43. package/src/native/motion/imperativeAnimate.ts +816 -0
  44. package/src/native/motion/keyframeTiming.ts +7 -0
  45. package/src/native/motion/layoutIdBinding.ts +261 -0
  46. package/src/native/motion/layoutIdFlightConfig.ts +51 -0
  47. package/src/native/motion/layoutProjection.ts +89 -0
  48. package/src/native/motion/layoutScroll.ts +204 -0
  49. package/src/native/motion/layoutTransition.ts +1302 -0
  50. package/src/native/motion/lengthLayoutContext.tsx +100 -0
  51. package/src/native/motion/lengthLayoutHost.ts +44 -0
  52. package/src/native/motion/mappedKeys.ts +184 -0
  53. package/src/native/motion/motionViewController.ts +3180 -0
  54. package/src/native/motion/nativeHostMarker.ts +22 -0
  55. package/src/native/motion/panSessionWiring.ts +127 -0
  56. package/src/native/motion/pathTransition.ts +101 -0
  57. package/src/native/motion/popLayout.ts +176 -0
  58. package/src/native/motion/presenceBinding.ts +382 -0
  59. package/src/native/motion/scaleCorrectorRegistry.ts +123 -0
  60. package/src/native/motion/scrollValues.ts +260 -0
  61. package/src/native/motion/serializablePayload.ts +151 -0
  62. package/src/native/motion/severity.ts +16 -0
  63. package/src/native/motion/shippedSurface.ts +843 -0
  64. package/src/native/motion/staticLengthGate.ts +86 -0
  65. package/src/native/motion/styleBaseGate.ts +72 -0
  66. package/src/native/motion/styleValueBinding.ts +657 -0
  67. package/src/native/motion/systemGestureExclusion.ts +61 -0
  68. package/src/native/motion/tapGestureWiring.ts +215 -0
  69. package/src/native/motion/transformOrder.ts +38 -0
  70. package/src/native/motion/transformStringBinding.ts +200 -0
  71. package/src/native/motion/transformTemplateGate.ts +45 -0
  72. package/src/native/motion/transitionGate.ts +435 -0
  73. package/src/native/motion/useAnimate.ts +52 -0
  74. package/src/native/motion/useCycle.ts +44 -0
  75. package/src/native/motion/useInstantTransition.ts +68 -0
  76. package/src/native/motion/useReducedMotion.ts +58 -0
  77. package/src/native/motion/useScroll.ts +162 -0
  78. package/src/native/motion/useViewportScroll.ts +29 -0
  79. package/src/native/motion/valueChannel.ts +7121 -0
  80. package/src/native/motion/valueHooks.ts +901 -0
  81. package/src/native/motion/variantChildRegistry.ts +67 -0
  82. package/src/native/motion/variantContext.tsx +172 -0
  83. package/src/native/motion/variantProps.ts +598 -0
  84. package/src/native.ts +159 -0
  85. package/src/verification/harnessMetrics.ts +78 -0
  86. package/src/verification/probe/LayoutIdentityWorkletProbe.tsx +251 -0
  87. package/src/verification/probe/WorkletParityProbe.tsx +162 -0
  88. package/src/verification/probe/layoutIdentityProbeEngine.ts +429 -0
  89. package/src/verification/screens/ArcPathChecksScreen.tsx +273 -0
  90. package/src/verification/screens/BooleanAnimateChecksScreen.tsx +358 -0
  91. package/src/verification/screens/ChoreographyGalleryScreen.tsx +1010 -0
  92. package/src/verification/screens/ColorBindingChecksScreen.tsx +568 -0
  93. package/src/verification/screens/CompletionChecksScreen.tsx +294 -0
  94. package/src/verification/screens/ConformanceScreen.tsx +573 -0
  95. package/src/verification/screens/ContentionProbeScreen.tsx +224 -0
  96. package/src/verification/screens/DriverSmokeScreen.tsx +99 -0
  97. package/src/verification/screens/DurationOnlyTweenChecksScreen.tsx +294 -0
  98. package/src/verification/screens/DynamicDragConfigChecksScreen.tsx +237 -0
  99. package/src/verification/screens/FrameDataChecksScreen.tsx +252 -0
  100. package/src/verification/screens/GestureChecksScreen.tsx +685 -0
  101. package/src/verification/screens/InstantTransitionChecksScreen.tsx +839 -0
  102. package/src/verification/screens/LayoutAnimationStartChecksScreen.tsx +648 -0
  103. package/src/verification/screens/LayoutChecksScreen.tsx +822 -0
  104. package/src/verification/screens/LayoutCommitSpikeScreen.tsx +142 -0
  105. package/src/verification/screens/MotionViewChecksScreen.tsx +930 -0
  106. package/src/verification/screens/PresenceChecksScreen.tsx +614 -0
  107. package/src/verification/screens/ReducedMotionChecksScreen.tsx +614 -0
  108. package/src/verification/screens/RestThresholdChecksScreen.tsx +634 -0
  109. package/src/verification/screens/ScaleCorrectorChecksScreen.tsx +425 -0
  110. package/src/verification/screens/SharedLayoutContinuityChecksScreen.tsx +338 -0
  111. package/src/verification/screens/SharedLayoutCrossfadeChecksScreen.tsx +425 -0
  112. package/src/verification/screens/TransitionDefaultSelectionChecksScreen.tsx +514 -0
  113. package/src/verification/screens/ViewportScrollAliasChecksScreen.tsx +303 -0
  114. package/src/verification/screens/conformanceBanner.ts +21 -0
  115. package/src/verification/screens/proofConsoleTap.ts +18 -0
  116. package/src/verification.ts +47 -0
  117. package/src/web.ts +98 -0
@@ -0,0 +1,4640 @@
1
+ // Private UI-global value-channel coordinator (REQ-DRIVER-034).
2
+ // Creation-ordered callback/admission records, one timestamp-global begin/invoke/revoke/commit
3
+ // frame transaction, stable callback registration, runner admission/reselection, cold-work relay
4
+ // through preallocated canonical records, private dependency events, sink fanout, and the manual
5
+ // frame group. Every kind-keyed dispatch refuses unrecognized kinds with a typed invariant error
6
+ // and leaves state untouched on refusal.
7
+
8
+ import type { FrameInfo } from 'react-native-reanimated'
9
+ import type { MotionValue } from '@unrulysystems/native-motion-core'
10
+ import type {
11
+ DestinationCommitAcknowledgement,
12
+ ImmutableDestinationCommit,
13
+ NormalizedRetainedWorkEntry,
14
+ ValueHandoffDestinationLedgerState,
15
+ } from '../motion/driverValueChannel'
16
+ import type { ChannelMailboxEntry } from '../motion/valueChannel'
17
+ import type {
18
+ MotionValueDriverPort,
19
+ PrimitiveNumericHistory,
20
+ TransportedExecutionGeneratorSample,
21
+ } from '@unrulysystems/native-motion-core/internal-driver'
22
+
23
+ export type UiCoordinatorFrameInfo = Pick<
24
+ FrameInfo,
25
+ 'timestamp' | 'timeSincePreviousFrame' | 'timeSinceFirstFrame'
26
+ >
27
+
28
+ export type UiCallbackLeaseState =
29
+ | 'REGISTERED_INACTIVE'
30
+ | 'ACTIVATION_REQUESTED'
31
+ | 'ADMITTED'
32
+ | 'RUNNER_CANDIDATE'
33
+ | 'RETIRING'
34
+ | 'REVOKED'
35
+
36
+ export interface UiCallbackRegistrationState {
37
+ readonly driverId: number
38
+ readonly callbackIdentityId: number
39
+ readonly callbackRegistrationGeneration: number
40
+ readonly callbackLeaseEpoch: number
41
+ readonly state: UiCallbackLeaseState
42
+ readonly admittedFromTimestampMs: number | null
43
+ readonly lastInvocationTimestampMs: number | null
44
+ readonly observerRevision: number
45
+ readonly activatorRegistered: boolean
46
+ readonly reanimatedCallbackActive: boolean
47
+ }
48
+
49
+ export type UiRelayWorkClass =
50
+ | 'channel-ordinary-first-sample'
51
+ | 'private-ordinary-first-sample'
52
+ | 'instant-target'
53
+ | 'instant-completion'
54
+ | 'equal-target-reassertion'
55
+ | 'direct-write'
56
+ | 'idle-write'
57
+ | 'transition-end-carrier'
58
+ | 'exit-carrier'
59
+ | 'packet-b-carrier'
60
+
61
+ export type UiColdWorkRelayLeaseState =
62
+ | 'ARMED'
63
+ | 'RELAYED_BY_INCUMBENT'
64
+ | 'CLAIMED_BY_TARGET'
65
+ | 'RELEASED'
66
+
67
+ export type UiColdRelayGeneratorExecutionEntry = Extract<
68
+ NormalizedRetainedWorkEntry,
69
+ { readonly kind: 'generator-execution' }
70
+ >
71
+
72
+ export type UiColdRelayUpdateTaskEntry<
73
+ TaskClass extends Extract<
74
+ NormalizedRetainedWorkEntry,
75
+ { readonly kind: 'update-task' }
76
+ >['taskClass'],
77
+ > = Extract<NormalizedRetainedWorkEntry, { readonly kind: 'update-task' }> & {
78
+ readonly taskClass: TaskClass
79
+ }
80
+
81
+ export type UiColdRelayDirectWriteEntry = Extract<
82
+ NormalizedRetainedWorkEntry,
83
+ { readonly kind: 'direct-write' }
84
+ >
85
+
86
+ export type UiColdRelayCompletionEntry = Extract<
87
+ NormalizedRetainedWorkEntry,
88
+ { readonly kind: 'value-completion' }
89
+ >
90
+
91
+ export type UiColdRelayCarrierEntry<
92
+ TaskClass extends Extract<
93
+ NormalizedRetainedWorkEntry,
94
+ { readonly kind: 'carrier-task' }
95
+ >['taskClass'],
96
+ > = Extract<NormalizedRetainedWorkEntry, { readonly kind: 'carrier-task' }> & {
97
+ readonly taskClass: TaskClass
98
+ }
99
+
100
+ export interface UiColdRelayEnvelopeWatermarks {
101
+ readonly mailboxDrainId: number
102
+ readonly drainedThroughAuthoritativeSequence: number
103
+ readonly deliveredWriteWatermark: number
104
+ readonly deliveredEventWatermark: number
105
+ }
106
+
107
+ export type UiColdRelayWriteResultSlot =
108
+ | {
109
+ readonly kind: 'GENERATOR_SAMPLE_WRITE'
110
+ readonly resultSlotId: number
111
+ readonly entry: UiColdRelayGeneratorExecutionEntry
112
+ }
113
+ | {
114
+ readonly kind: 'UPDATE_TASK_WRITE'
115
+ readonly resultSlotId: number
116
+ readonly entry: UiColdRelayUpdateTaskEntry<'instant' | 'equal' | 'idle-direct-write'>
117
+ }
118
+ | {
119
+ readonly kind: 'DIRECT_WRITE'
120
+ readonly resultSlotId: number
121
+ readonly entry: UiColdRelayDirectWriteEntry
122
+ }
123
+
124
+ export type UiColdRelayCallbackResultSlot =
125
+ | {
126
+ readonly kind: 'CHANNEL_TRANSITION_ON_UPDATE'
127
+ readonly resultSlotId: number
128
+ readonly callbackId: number
129
+ readonly eventSequence: number
130
+ }
131
+ | {
132
+ readonly kind: 'TASK_CALLBACK'
133
+ readonly resultSlotId: number
134
+ readonly taskId: number
135
+ readonly callback: UiColdRelayUpdateTaskEntry<
136
+ 'instant' | 'equal' | 'idle-direct-write'
137
+ >['callbacks'][number]
138
+ }
139
+ | {
140
+ readonly kind: 'VALUE_COMPLETION_CALLBACKS'
141
+ readonly resultSlotId: number
142
+ readonly completionSequence: number
143
+ readonly transitionOnCompleteCallbackId: number | null
144
+ readonly lifecycleCallbackIds: readonly number[]
145
+ readonly publicStartPromiseId: number | null
146
+ }
147
+
148
+ export interface UiColdRelayCarrierResultSlot<
149
+ TaskClass extends 'transition-end-carrier' | 'exit-carrier' | 'packet-b-carrier' =
150
+ | 'transition-end-carrier'
151
+ | 'exit-carrier'
152
+ | 'packet-b-carrier',
153
+ > {
154
+ readonly kind: 'CARRIER'
155
+ readonly resultSlotId: number
156
+ readonly entry: UiColdRelayCarrierEntry<TaskClass>
157
+ }
158
+
159
+ export type UiColdRelayHostCommitResultSlot = Extract<
160
+ ChannelMailboxEntry,
161
+ { readonly kind: 'ELEMENT_HOST_COMMIT' }
162
+ >
163
+
164
+ interface UiColdRelayDeliverySlotsCommon<Class extends UiRelayWorkClass> {
165
+ readonly workClass: Class
166
+ readonly envelope: UiColdRelayEnvelopeWatermarks
167
+ }
168
+
169
+ export type UiColdRelayDeliverySlots =
170
+ | (UiColdRelayDeliverySlotsCommon<'channel-ordinary-first-sample'> & {
171
+ readonly writeSlots: readonly [
172
+ Extract<UiColdRelayWriteResultSlot, { readonly kind: 'GENERATOR_SAMPLE_WRITE' }>,
173
+ ]
174
+ readonly callbackSlots: readonly Extract<
175
+ UiColdRelayCallbackResultSlot,
176
+ { readonly kind: 'CHANNEL_TRANSITION_ON_UPDATE' }
177
+ >[]
178
+ readonly carrierSlots: readonly []
179
+ readonly hostSlots: readonly [UiColdRelayHostCommitResultSlot]
180
+ })
181
+ | (UiColdRelayDeliverySlotsCommon<'private-ordinary-first-sample'> & {
182
+ readonly writeSlots: readonly [
183
+ Extract<UiColdRelayWriteResultSlot, { readonly kind: 'GENERATOR_SAMPLE_WRITE' }>,
184
+ ]
185
+ readonly callbackSlots: readonly []
186
+ readonly carrierSlots: readonly []
187
+ readonly hostSlots: readonly [UiColdRelayHostCommitResultSlot]
188
+ })
189
+ | (UiColdRelayDeliverySlotsCommon<'instant-target'> & {
190
+ readonly writeSlots: readonly [
191
+ Extract<UiColdRelayWriteResultSlot, { readonly kind: 'UPDATE_TASK_WRITE' }> & {
192
+ readonly entry: UiColdRelayUpdateTaskEntry<'instant'>
193
+ },
194
+ ]
195
+ readonly callbackSlots: readonly Extract<
196
+ UiColdRelayCallbackResultSlot,
197
+ { readonly kind: 'TASK_CALLBACK' }
198
+ >[]
199
+ readonly carrierSlots: readonly []
200
+ readonly hostSlots: readonly [UiColdRelayHostCommitResultSlot]
201
+ })
202
+ | (UiColdRelayDeliverySlotsCommon<'instant-completion'> & {
203
+ readonly writeSlots: readonly []
204
+ readonly callbackSlots: readonly [
205
+ Extract<UiColdRelayCallbackResultSlot, { readonly kind: 'VALUE_COMPLETION_CALLBACKS' }>,
206
+ ]
207
+ readonly carrierSlots: readonly []
208
+ readonly hostSlots: readonly []
209
+ })
210
+ | (UiColdRelayDeliverySlotsCommon<'equal-target-reassertion'> & {
211
+ readonly writeSlots: readonly [
212
+ Extract<UiColdRelayWriteResultSlot, { readonly kind: 'UPDATE_TASK_WRITE' }> & {
213
+ readonly entry: UiColdRelayUpdateTaskEntry<'equal'>
214
+ },
215
+ ]
216
+ readonly callbackSlots: readonly Extract<
217
+ UiColdRelayCallbackResultSlot,
218
+ { readonly kind: 'TASK_CALLBACK' }
219
+ >[]
220
+ readonly carrierSlots: readonly []
221
+ readonly hostSlots: readonly [UiColdRelayHostCommitResultSlot]
222
+ })
223
+ | (UiColdRelayDeliverySlotsCommon<'direct-write'> & {
224
+ readonly writeSlots: readonly [
225
+ Extract<UiColdRelayWriteResultSlot, { readonly kind: 'DIRECT_WRITE' }>,
226
+ ]
227
+ readonly callbackSlots: readonly []
228
+ readonly carrierSlots: readonly []
229
+ readonly hostSlots: readonly [UiColdRelayHostCommitResultSlot]
230
+ })
231
+ | (UiColdRelayDeliverySlotsCommon<'idle-write'> & {
232
+ readonly writeSlots: readonly [
233
+ Extract<UiColdRelayWriteResultSlot, { readonly kind: 'UPDATE_TASK_WRITE' }> & {
234
+ readonly entry: UiColdRelayUpdateTaskEntry<'idle-direct-write'>
235
+ },
236
+ ]
237
+ readonly callbackSlots: readonly Extract<
238
+ UiColdRelayCallbackResultSlot,
239
+ { readonly kind: 'TASK_CALLBACK' }
240
+ >[]
241
+ readonly carrierSlots: readonly []
242
+ readonly hostSlots: readonly [UiColdRelayHostCommitResultSlot]
243
+ })
244
+ | (UiColdRelayDeliverySlotsCommon<'transition-end-carrier'> & {
245
+ readonly writeSlots: readonly []
246
+ readonly callbackSlots: readonly []
247
+ readonly carrierSlots: readonly [UiColdRelayCarrierResultSlot<'transition-end-carrier'>]
248
+ readonly hostSlots: readonly [UiColdRelayHostCommitResultSlot]
249
+ })
250
+ | (UiColdRelayDeliverySlotsCommon<'exit-carrier'> & {
251
+ readonly writeSlots: readonly []
252
+ readonly callbackSlots: readonly []
253
+ readonly carrierSlots: readonly [UiColdRelayCarrierResultSlot<'exit-carrier'>]
254
+ readonly hostSlots: readonly [UiColdRelayHostCommitResultSlot]
255
+ })
256
+ | (UiColdRelayDeliverySlotsCommon<'packet-b-carrier'> & {
257
+ readonly writeSlots: readonly []
258
+ readonly callbackSlots: readonly []
259
+ readonly carrierSlots: readonly [UiColdRelayCarrierResultSlot<'packet-b-carrier'>]
260
+ readonly hostSlots: readonly [UiColdRelayHostCommitResultSlot]
261
+ })
262
+
263
+ interface UiColdRelayCommandAuthorityCommon<Class extends UiRelayWorkClass> {
264
+ readonly workClass: Class
265
+ readonly destinationRecordId: number
266
+ }
267
+
268
+ type UiColdRelayCommandAuthority =
269
+ | (UiColdRelayCommandAuthorityCommon<'channel-ordinary-first-sample'> & {
270
+ readonly owner: { readonly kind: 'PUBLIC_IDENTITY'; readonly channelId: number }
271
+ readonly executionId: number
272
+ })
273
+ | (UiColdRelayCommandAuthorityCommon<'private-ordinary-first-sample'> & {
274
+ readonly owner: { readonly kind: 'PRIVATE_CONTROL'; readonly controlId: number }
275
+ readonly executionId: number
276
+ })
277
+ | (UiColdRelayCommandAuthorityCommon<'instant-target'> & {
278
+ readonly taskId: number
279
+ readonly taskSequence: number
280
+ })
281
+ | (UiColdRelayCommandAuthorityCommon<'instant-completion'> & {
282
+ readonly completionSequence: number
283
+ readonly completionControllerId: number
284
+ })
285
+ | (UiColdRelayCommandAuthorityCommon<'equal-target-reassertion'> & {
286
+ readonly taskId: number
287
+ readonly taskSequence: number
288
+ })
289
+ | (UiColdRelayCommandAuthorityCommon<'direct-write'> & {
290
+ readonly directOperationId: number
291
+ readonly directOperationEpoch: number
292
+ })
293
+ | (UiColdRelayCommandAuthorityCommon<'idle-write'> & {
294
+ readonly taskId: number
295
+ readonly taskSequence: number
296
+ })
297
+ | (UiColdRelayCommandAuthorityCommon<'transition-end-carrier'> & {
298
+ readonly carrierControllerId: number
299
+ readonly taskId: number
300
+ })
301
+ | (UiColdRelayCommandAuthorityCommon<'exit-carrier'> & {
302
+ readonly carrierControllerId: number
303
+ readonly taskId: number
304
+ })
305
+ | (UiColdRelayCommandAuthorityCommon<'packet-b-carrier'> & {
306
+ readonly carrierControllerId: number
307
+ readonly taskId: number
308
+ })
309
+
310
+ declare const uiColdRelayCanonicalRecordBrand: unique symbol
311
+
312
+ export interface UiColdRelayCanonicalRecord {
313
+ readonly [uiColdRelayCanonicalRecordBrand]: true
314
+ }
315
+
316
+ export interface UiColdWorkRelayValueBearingEntry {
317
+ readonly kind: 'COMPLETE_TRANSITION_ON_UPDATE'
318
+ readonly channelId: number
319
+ readonly targetCallbackIdentityId: number
320
+ readonly transitionCallbackId: number
321
+ readonly valueWriteEntryId: number
322
+ readonly transitionCallbackEntryId: number
323
+ readonly executionId: number
324
+ readonly directOperationEpoch: number
325
+ readonly executionLease: number
326
+ readonly authoritativeSequence: number
327
+ readonly writeSequence: number
328
+ readonly eventSequence: number
329
+ readonly candidateHistory: PrimitiveNumericHistory
330
+ readonly completion: TransportedExecutionGeneratorSample['completion']
331
+ }
332
+
333
+ export type UiColdWorkRelayValueWriteMailboxEntry = Extract<
334
+ ChannelMailboxEntry,
335
+ { readonly kind: 'VALUE_WRITE' }
336
+ > & {
337
+ readonly sample: TransportedExecutionGeneratorSample
338
+ }
339
+
340
+ export type UiColdWorkRelayTransitionCallbackMailboxEntry = Extract<
341
+ ChannelMailboxEntry,
342
+ { readonly kind: 'TRANSITION_CALLBACK' }
343
+ > & {
344
+ readonly event: Extract<
345
+ ChannelMailboxEntry,
346
+ { readonly kind: 'TRANSITION_CALLBACK' }
347
+ >['event'] & { readonly kind: 'transition-on-update' }
348
+ }
349
+
350
+ export interface UiColdWorkRelayMailboxPrefix {
351
+ readonly mailboxOrigin: 'UI'
352
+ readonly mailboxDrainId: number
353
+ readonly stagedEntries: readonly [
354
+ UiColdWorkRelayValueWriteMailboxEntry,
355
+ UiColdWorkRelayTransitionCallbackMailboxEntry,
356
+ ]
357
+ readonly sealed: false
358
+ }
359
+
360
+ export interface UiColdWorkRelayStagedValueBearingPrefix {
361
+ readonly mailboxDrainId: number
362
+ readonly valueWriteEntryId: number
363
+ readonly transitionCallbackEntryId: number
364
+ readonly transitionCallbackId: number
365
+ readonly authoritativeSequence: number
366
+ readonly writeSequence: number
367
+ readonly eventSequence: number
368
+ }
369
+
370
+ /** Canonical public-identity authority retained by the coordinator, never reconstructed by relay. */
371
+ export interface UiPublicIdentityChannelRecord {
372
+ readonly channelId: number
373
+ readonly motionValue: MotionValue<number>
374
+ readonly driverPort: MotionValueDriverPort<number>
375
+ }
376
+
377
+ interface UiGeneratorExecutionRecordCommon<Class extends UiRelayWorkClass> {
378
+ readonly workClass: Class
379
+ readonly executionRecordId: number
380
+ readonly entry: UiColdRelayGeneratorExecutionEntry
381
+ readonly valueBearingEntry: UiColdWorkRelayValueBearingEntry | null
382
+ readonly writeSlot: Extract<
383
+ UiColdRelayWriteResultSlot,
384
+ { readonly kind: 'GENERATOR_SAMPLE_WRITE' }
385
+ >
386
+ readonly callbackSlots: readonly Extract<
387
+ UiColdRelayCallbackResultSlot,
388
+ { readonly kind: 'CHANNEL_TRANSITION_ON_UPDATE' }
389
+ >[]
390
+ readonly mailboxDrainId: number
391
+ readonly hostSinkRecordIds: readonly number[]
392
+ }
393
+
394
+ export type UiGeneratorExecutionRecord =
395
+ | (UiGeneratorExecutionRecordCommon<'channel-ordinary-first-sample'> & {
396
+ readonly owner: { readonly kind: 'PUBLIC_IDENTITY'; readonly channelId: number }
397
+ readonly publicIdentityChannel: UiPublicIdentityChannelRecord
398
+ readonly valueBearingEntry: UiColdWorkRelayValueBearingEntry
399
+ })
400
+ | (UiGeneratorExecutionRecordCommon<'private-ordinary-first-sample'> & {
401
+ readonly owner: { readonly kind: 'PRIVATE_CONTROL'; readonly controlId: number }
402
+ readonly publicIdentityChannel: null
403
+ })
404
+
405
+ type UiDueWorkTaskClass = Extract<
406
+ NormalizedRetainedWorkEntry,
407
+ { readonly kind: 'update-task' }
408
+ >['taskClass']
409
+
410
+ interface UiDueWorkTaskRecordCommon<
411
+ Class extends UiRelayWorkClass,
412
+ TaskClass extends UiDueWorkTaskClass,
413
+ > {
414
+ readonly workClass: Class
415
+ readonly taskRecordId: number
416
+ readonly entry: UiColdRelayUpdateTaskEntry<TaskClass>
417
+ readonly writeSlot: Extract<
418
+ UiColdRelayWriteResultSlot,
419
+ { readonly kind: 'UPDATE_TASK_WRITE' }
420
+ > & { readonly entry: UiColdRelayUpdateTaskEntry<TaskClass> }
421
+ readonly callbackSlots: readonly Extract<
422
+ UiColdRelayCallbackResultSlot,
423
+ { readonly kind: 'TASK_CALLBACK' }
424
+ >[]
425
+ readonly mailboxDrainId: number
426
+ readonly hostSinkRecordIds: readonly number[]
427
+ }
428
+
429
+ export type UiDueWorkTaskRecord =
430
+ | UiDueWorkTaskRecordCommon<'instant-target', 'instant'>
431
+ | UiDueWorkTaskRecordCommon<'equal-target-reassertion', 'equal'>
432
+ | UiDueWorkTaskRecordCommon<'idle-write', 'idle-direct-write'>
433
+
434
+ export interface UiValueCompletionControllerRecord {
435
+ readonly workClass: 'instant-completion'
436
+ readonly completionControllerId: number
437
+ readonly entry: UiColdRelayCompletionEntry
438
+ readonly callbackSlot: Extract<
439
+ UiColdRelayCallbackResultSlot,
440
+ { readonly kind: 'VALUE_COMPLETION_CALLBACKS' }
441
+ >
442
+ readonly mailboxDrainId: number
443
+ }
444
+
445
+ export interface UiDirectOperationRecord {
446
+ readonly workClass: 'direct-write'
447
+ readonly directOperationId: number
448
+ readonly directOperationEpoch: number
449
+ readonly entry: UiColdRelayDirectWriteEntry
450
+ readonly writeSlot: Extract<UiColdRelayWriteResultSlot, { readonly kind: 'DIRECT_WRITE' }>
451
+ readonly mailboxDrainId: number
452
+ readonly hostSinkRecordIds: readonly number[]
453
+ }
454
+
455
+ interface UiCarrierControllerRecordCommon<
456
+ Class extends 'transition-end-carrier' | 'exit-carrier' | 'packet-b-carrier' =
457
+ | 'transition-end-carrier'
458
+ | 'exit-carrier'
459
+ | 'packet-b-carrier',
460
+ > {
461
+ readonly workClass: Class
462
+ readonly carrierControllerId: number
463
+ readonly entry: UiColdRelayCarrierEntry<Class>
464
+ readonly carrierSlot: UiColdRelayCarrierResultSlot<Class>
465
+ readonly mailboxDrainId: number
466
+ readonly hostSinkRecordIds: readonly number[]
467
+ }
468
+
469
+ export type UiCarrierControllerRecord = {
470
+ readonly [Class in
471
+ | 'transition-end-carrier'
472
+ | 'exit-carrier'
473
+ | 'packet-b-carrier']: UiCarrierControllerRecordCommon<Class>
474
+ }['transition-end-carrier' | 'exit-carrier' | 'packet-b-carrier']
475
+
476
+ export interface UiMailboxTurnRecord {
477
+ readonly mailboxDrainId: number
478
+ readonly envelope: UiColdRelayEnvelopeWatermarks
479
+ }
480
+
481
+ export interface UiHostSinkRecord {
482
+ readonly hostSinkRecordId: number
483
+ readonly slot: UiColdRelayHostCommitResultSlot
484
+ }
485
+
486
+ type UiColdRelayPrimaryRecordByClass = {
487
+ readonly 'channel-ordinary-first-sample': Extract<
488
+ UiGeneratorExecutionRecord,
489
+ { readonly workClass: 'channel-ordinary-first-sample' }
490
+ >
491
+ readonly 'private-ordinary-first-sample': Extract<
492
+ UiGeneratorExecutionRecord,
493
+ { readonly workClass: 'private-ordinary-first-sample' }
494
+ >
495
+ readonly 'instant-target': Extract<UiDueWorkTaskRecord, { readonly workClass: 'instant-target' }>
496
+ readonly 'instant-completion': UiValueCompletionControllerRecord
497
+ readonly 'equal-target-reassertion': Extract<
498
+ UiDueWorkTaskRecord,
499
+ { readonly workClass: 'equal-target-reassertion' }
500
+ >
501
+ readonly 'direct-write': UiDirectOperationRecord
502
+ readonly 'idle-write': Extract<UiDueWorkTaskRecord, { readonly workClass: 'idle-write' }>
503
+ readonly 'transition-end-carrier': Extract<
504
+ UiCarrierControllerRecord,
505
+ { readonly workClass: 'transition-end-carrier' }
506
+ >
507
+ readonly 'exit-carrier': Extract<
508
+ UiCarrierControllerRecord,
509
+ { readonly workClass: 'exit-carrier' }
510
+ >
511
+ readonly 'packet-b-carrier': Extract<
512
+ UiCarrierControllerRecord,
513
+ { readonly workClass: 'packet-b-carrier' }
514
+ >
515
+ }
516
+
517
+ type UiColdRelayCallbackRegistrationsByClass = {
518
+ readonly 'channel-ordinary-first-sample': readonly [UiCallbackRegistrationState]
519
+ readonly 'private-ordinary-first-sample': readonly []
520
+ readonly 'instant-target': readonly [UiCallbackRegistrationState]
521
+ readonly 'instant-completion': readonly [UiCallbackRegistrationState]
522
+ readonly 'equal-target-reassertion': readonly [UiCallbackRegistrationState]
523
+ readonly 'direct-write': readonly []
524
+ readonly 'idle-write': readonly []
525
+ readonly 'transition-end-carrier': readonly []
526
+ readonly 'exit-carrier': readonly []
527
+ readonly 'packet-b-carrier': readonly []
528
+ }
529
+
530
+ type UiColdRelayHostSinkRecordsByClass = {
531
+ readonly 'channel-ordinary-first-sample': readonly [UiHostSinkRecord]
532
+ readonly 'private-ordinary-first-sample': readonly [UiHostSinkRecord]
533
+ readonly 'instant-target': readonly [UiHostSinkRecord]
534
+ readonly 'instant-completion': readonly []
535
+ readonly 'equal-target-reassertion': readonly [UiHostSinkRecord]
536
+ readonly 'direct-write': readonly [UiHostSinkRecord]
537
+ readonly 'idle-write': readonly [UiHostSinkRecord]
538
+ readonly 'transition-end-carrier': readonly [UiHostSinkRecord]
539
+ readonly 'exit-carrier': readonly [UiHostSinkRecord]
540
+ readonly 'packet-b-carrier': readonly [UiHostSinkRecord]
541
+ }
542
+
543
+ const uiColdRelaySourceRecordsBrand = Symbol('UiColdRelaySourceRecords')
544
+
545
+ export type UiColdRelaySourceRecords = {
546
+ readonly [Class in UiRelayWorkClass]: {
547
+ readonly [uiColdRelaySourceRecordsBrand]: true
548
+ readonly workClass: Class
549
+ readonly primaryRecord: UiColdRelayPrimaryRecordByClass[Class]
550
+ readonly callbackRegistrations: UiColdRelayCallbackRegistrationsByClass[Class]
551
+ readonly mailboxRecord: UiMailboxTurnRecord
552
+ readonly hostSinkRecords: UiColdRelayHostSinkRecordsByClass[Class]
553
+ }
554
+ }[UiRelayWorkClass]
555
+
556
+ export type UiColdRelayCommandProductionRequest =
557
+ | {
558
+ readonly kind: 'START_PUBLIC_IDENTITY_EXECUTION'
559
+ readonly destinationRecordId: number
560
+ readonly channelId: number
561
+ readonly executionId: number
562
+ }
563
+ | {
564
+ readonly kind: 'START_PRIVATE_CONTROL_EXECUTION'
565
+ readonly destinationRecordId: number
566
+ readonly controlId: number
567
+ readonly executionId: number
568
+ }
569
+ | {
570
+ readonly kind: 'QUEUE_INSTANT_TARGET'
571
+ readonly destinationRecordId: number
572
+ readonly taskId: number
573
+ readonly taskSequence: number
574
+ }
575
+ | {
576
+ readonly kind: 'ARM_INSTANT_COMPLETION'
577
+ readonly destinationRecordId: number
578
+ readonly completionSequence: number
579
+ readonly completionControllerId: number
580
+ }
581
+ | {
582
+ readonly kind: 'QUEUE_EQUAL_TARGET_REASSERTION'
583
+ readonly destinationRecordId: number
584
+ readonly taskId: number
585
+ readonly taskSequence: number
586
+ }
587
+ | {
588
+ readonly kind: 'APPLY_DIRECT_WRITE'
589
+ readonly destinationRecordId: number
590
+ readonly directOperationId: number
591
+ readonly directOperationEpoch: number
592
+ }
593
+ | {
594
+ readonly kind: 'QUEUE_IDLE_WRITE'
595
+ readonly destinationRecordId: number
596
+ readonly taskId: number
597
+ readonly taskSequence: number
598
+ }
599
+ | {
600
+ readonly kind:
601
+ | 'QUEUE_TRANSITION_END_CARRIER'
602
+ | 'QUEUE_EXIT_CARRIER'
603
+ | 'QUEUE_PACKET_B_CARRIER'
604
+ readonly destinationRecordId: number
605
+ readonly carrierControllerId: number
606
+ readonly taskId: number
607
+ }
608
+
609
+ const uiColdRelayProducerReceiptBrand = Symbol('UiColdRelayProducerReceipt')
610
+
611
+ export interface UiColdRelayCommandProductionTransition {
612
+ readonly [uiColdRelayProducerReceiptBrand]: true
613
+ readonly state: UiValueChannelCoordinatorState
614
+ readonly commandAuthority: UiColdRelayCommandAuthority
615
+ readonly sourceRecords: UiColdRelaySourceRecords
616
+ }
617
+
618
+ interface UiColdRelayCanonicalRecordObservationCommon<Class extends UiRelayWorkClass> {
619
+ readonly recordId: number
620
+ readonly authority: Extract<UiColdRelayCommandAuthority, { readonly workClass: Class }>
621
+ }
622
+
623
+ type UiColdRelayFilledCanonicalRecordObservation = {
624
+ readonly [Class in UiRelayWorkClass]: UiColdRelayCanonicalRecordObservationCommon<Class> & {
625
+ readonly fillState: 'FILLED_FROM_LIVE_RECORDS'
626
+ readonly sourceRecords: Extract<UiColdRelaySourceRecords, { readonly workClass: Class }>
627
+ readonly deliverySlots: Extract<UiColdRelayDeliverySlots, { readonly workClass: Class }>
628
+ }
629
+ }[UiRelayWorkClass]
630
+
631
+ export type UiColdRelayCanonicalRecordObservation =
632
+ | ({
633
+ readonly fillState: 'EMPTY'
634
+ readonly sourceRecords: null
635
+ readonly deliverySlots: null
636
+ } & {
637
+ readonly [Class in UiRelayWorkClass]: UiColdRelayCanonicalRecordObservationCommon<Class>
638
+ }[UiRelayWorkClass])
639
+ | UiColdRelayFilledCanonicalRecordObservation
640
+
641
+ export type UiColdRelayEffect =
642
+ | {
643
+ readonly kind: 'allocate-empty-canonical-cold-relay-record'
644
+ readonly relayId: number
645
+ readonly canonicalRecord: UiColdRelayCanonicalRecord
646
+ }
647
+ | {
648
+ readonly kind: 'fill-canonical-cold-relay-record-from-live-records'
649
+ readonly relayId: number
650
+ readonly canonicalRecord: UiColdRelayCanonicalRecord
651
+ readonly sourceRecords: UiColdRelaySourceRecords
652
+ }
653
+ | {
654
+ readonly kind: 'apply-canonical-cold-relay-record'
655
+ readonly relayId: number
656
+ readonly targetDriverId: number
657
+ readonly canonicalRecord: UiColdRelayCanonicalRecord
658
+ }
659
+ | {
660
+ readonly kind: 'arm-cold-relay-lease-at-command-edge'
661
+ readonly relayId: number
662
+ readonly targetDriverId: number
663
+ readonly targetCallbackRegistrationGeneration: number
664
+ readonly relayLeaseEpoch: number
665
+ readonly commandReceipt: UiColdRelayCommandProductionTransition
666
+ readonly canonicalRecord: UiColdRelayCanonicalRecord
667
+ }
668
+ | {
669
+ readonly kind: 'activate-cold-relay-target-after-command-arm'
670
+ readonly relayId: number
671
+ readonly targetDriverId: number
672
+ readonly targetCallbackRegistrationGeneration: number
673
+ }
674
+
675
+ export interface UiColdWorkRelayState {
676
+ readonly relayId: number
677
+ readonly targetDriverId: number
678
+ readonly commandReceipt: UiColdRelayCommandProductionTransition
679
+ readonly canonicalRecord: UiColdRelayCanonicalRecord
680
+ readonly commandSequence: number
681
+ readonly targetCallbackRegistrationGeneration: number
682
+ readonly relayLeaseEpoch: number
683
+ readonly leaseState: UiColdWorkRelayLeaseState
684
+ readonly lifetime: 'ONE_SHOT' | 'ONGOING_EXECUTION'
685
+ readonly armedAtTimestampMs: number | null
686
+ readonly lastRelayedStepTimestampMs: number | null
687
+ readonly claimedAtTimestampMs: number | null
688
+ readonly claimedByDriverId: number | null
689
+ readonly pendingValueBearingEntry: UiColdWorkRelayValueBearingEntry | null
690
+ readonly stagedValueBearingPrefix: UiColdWorkRelayStagedValueBearingPrefix | null
691
+ }
692
+
693
+ export interface UiRetainedFrameCallbackActivatorRegistry {
694
+ hasStableActivator(driverId: number, callbackRegistrationGeneration: number): boolean
695
+ setActive(driverId: number, callbackRegistrationGeneration: number, active: boolean): void
696
+ }
697
+
698
+ export interface UiRunnerAdmissionRequestState {
699
+ readonly requestedRunnerLeaseEpoch: number
700
+ readonly candidateDriverId: number
701
+ readonly callbackRegistrationGeneration: number
702
+ readonly admissionToken: number
703
+ readonly absoluteDeadlineMs: number
704
+ readonly actualInvocationObserved: boolean
705
+ }
706
+
707
+ export interface UiIdentityFrameState {
708
+ readonly channelId: number
709
+ readonly lastAbsoluteTimestampMs: number | null
710
+ readonly stepCount: number
711
+ readonly hostCommitCount: number
712
+ readonly lastCommittedValueSequence: number
713
+ }
714
+
715
+ export interface UiOwnedIdentitySinkCommitState {
716
+ readonly sinkId: number
717
+ readonly driverId: number
718
+ readonly handle: number
719
+ readonly key: string
720
+ readonly bindingGeneration: number
721
+ readonly lastCommittedValue: number
722
+ readonly lastCommittedWriteSequence: number
723
+ readonly commitCount: number
724
+ }
725
+
726
+ export interface UiOwnedIdentitySampleFanoutState {
727
+ readonly channelId: number
728
+ readonly ownership: 'UI'
729
+ readonly lastAcceptedAbsoluteTimestampMs: number | null
730
+ readonly sinks: readonly UiOwnedIdentitySinkCommitState[]
731
+ readonly uiSinkCommitCount: number
732
+ readonly jsToUiWriteLaneInvocationCount: number
733
+ }
734
+
735
+ export interface UiOwnedIdentitySampleFanoutRequest {
736
+ readonly source: 'UI_OWNED_IDENTITY_SAMPLE'
737
+ readonly channelId: number
738
+ readonly executionId: number
739
+ readonly value: number
740
+ readonly writeSequence: number
741
+ readonly absoluteTimestampMs: number
742
+ }
743
+
744
+ export type UiOwnedIdentitySampleFanoutEffect =
745
+ | {
746
+ readonly kind: 'adopt-ui-owned-identity-sample'
747
+ readonly channelId: number
748
+ readonly executionId: number
749
+ readonly value: number
750
+ readonly writeSequence: number
751
+ readonly absoluteTimestampMs: number
752
+ }
753
+ | {
754
+ readonly kind: 'fanout-ui-owned-identity-sample-to-sink'
755
+ readonly sinkId: number
756
+ readonly driverId: number
757
+ readonly handle: number
758
+ readonly key: string
759
+ readonly bindingGeneration: number
760
+ readonly value: number
761
+ readonly writeSequence: number
762
+ }
763
+ | {
764
+ readonly kind: 'commit-ui-owned-identity-sinks-once'
765
+ readonly channelId: number
766
+ readonly sinkIds: readonly number[]
767
+ readonly absoluteTimestampMs: number
768
+ }
769
+
770
+ export interface UiOwnedIdentitySampleFanoutObservation {
771
+ readonly channelId: number
772
+ readonly sinkCount: number
773
+ readonly committedSinkCount: number
774
+ readonly committedSinkIds: readonly number[]
775
+ readonly uiSinkCommitCount: number
776
+ readonly jsToUiWriteLaneInvocationCount: number
777
+ }
778
+
779
+ export interface UiOwnedIdentitySampleFanoutTransition {
780
+ readonly state: UiOwnedIdentitySampleFanoutState
781
+ readonly observation: UiOwnedIdentitySampleFanoutObservation
782
+ readonly orderedEffects: readonly UiOwnedIdentitySampleFanoutEffect[]
783
+ }
784
+
785
+ interface UiFrameTransactionCommon {
786
+ readonly lastCommittedTimestampMs: number | null
787
+ readonly committedFrameCount: number
788
+ }
789
+
790
+ export type UiFrameTransactionState =
791
+ | (UiFrameTransactionCommon & { readonly kind: 'CLOSED' })
792
+ | (UiFrameTransactionCommon & {
793
+ readonly kind: 'OPEN'
794
+ readonly mode: 'LIVE' | 'MANUAL'
795
+ readonly absoluteTimestampMs: number
796
+ readonly mailboxDrainId: number
797
+ readonly expectedAttendeeDriverIds: readonly number[]
798
+ readonly visitedAttendeeDriverIds: readonly number[]
799
+ readonly revokedAttendeeDriverIds: readonly number[]
800
+ readonly steppedChannelIds: readonly number[]
801
+ readonly frozenInvocationOrder: readonly number[]
802
+ })
803
+
804
+ export interface UiManualDestinationCommitSlot extends ImmutableDestinationCommit {
805
+ readonly commitSlotId: number
806
+ readonly acknowledgementSlotId: number
807
+ }
808
+
809
+ export interface UiDestinationCommitAuthority {
810
+ readonly channelId: number
811
+ readonly sourceRecordId: number
812
+ readonly destinationRecordId: number
813
+ readonly direction: 'UI_TO_JS' | 'JS_TO_UI'
814
+ readonly transferLease: number
815
+ readonly releaseFenceSequence: number
816
+ }
817
+
818
+ export interface UiPreparedDestinationRecordState extends UiDestinationCommitAuthority {
819
+ readonly adoptedCommitSlotId: number | null
820
+ readonly appliedThroughAuthoritativeSequence: number
821
+ readonly ledgers: ValueHandoffDestinationLedgerState
822
+ }
823
+
824
+ export type UiDestinationCommitRefusalReason =
825
+ | 'envelope-not-open'
826
+ | 'missing-prepared-destination-record'
827
+ | 'missing-acknowledgement-slot'
828
+ | 'wrong-channel'
829
+ | 'wrong-source-record'
830
+ | 'wrong-destination-record'
831
+ | 'wrong-direction'
832
+ | 'wrong-transfer-lease'
833
+ | 'wrong-release-fence'
834
+ | 'ahead-of-sent-watermark'
835
+ | 'sent-watermark-regressed'
836
+ | 'prefix-not-contiguous'
837
+
838
+ export type UiDestinationCommitCanonicalRefusalReason = Exclude<
839
+ UiDestinationCommitRefusalReason,
840
+ 'envelope-not-open' | 'missing-acknowledgement-slot'
841
+ >
842
+
843
+ export interface UiDestinationCommitCanonicalValidationRequest {
844
+ readonly commit: ImmutableDestinationCommit
845
+ readonly preparedDestinationRecords: readonly UiPreparedDestinationRecordState[]
846
+ }
847
+
848
+ export type UiDestinationCommitCanonicalValidationOutcome =
849
+ | {
850
+ readonly kind: 'VALID'
851
+ readonly authority: UiPreparedDestinationRecordState
852
+ }
853
+ | {
854
+ readonly kind: 'REFUSED'
855
+ readonly authority: UiPreparedDestinationRecordState | null
856
+ readonly reason: UiDestinationCommitCanonicalRefusalReason
857
+ }
858
+
859
+ const uiDestinationCommitCanonicalValidatorCapabilityBrand = Symbol(
860
+ 'UiDestinationCommitCanonicalValidatorCapability',
861
+ )
862
+
863
+ export interface UiDestinationCommitCanonicalValidatorCapability {
864
+ readonly [uiDestinationCommitCanonicalValidatorCapabilityBrand]: true
865
+ readonly validate: typeof validateUiDestinationCommitWithCanonicalAuthority
866
+ }
867
+
868
+ export type UiDestinationCommitCanonicalValidationEffect =
869
+ | {
870
+ readonly kind: 'validate-ui-destination-commit-with-canonical-authority'
871
+ readonly root: 'LIVE'
872
+ readonly commitSlotId: number
873
+ readonly authority: UiPreparedDestinationRecordState
874
+ readonly validator: UiDestinationCommitCanonicalValidatorCapability
875
+ }
876
+ | {
877
+ readonly kind: 'validate-ui-destination-commit-with-canonical-authority'
878
+ readonly root: 'MANUAL'
879
+ readonly groupId: number
880
+ readonly commitSlotId: number
881
+ readonly authority: UiPreparedDestinationRecordState
882
+ readonly validator: UiDestinationCommitCanonicalValidatorCapability
883
+ }
884
+
885
+ export type UiDestinationCommitRefusalReportEffect =
886
+ | {
887
+ readonly kind: 'report-ui-destination-commit-refusal'
888
+ readonly root: 'LIVE'
889
+ readonly commitSlotId: number
890
+ readonly authority: UiPreparedDestinationRecordState | null
891
+ readonly reason: UiDestinationCommitRefusalReason
892
+ }
893
+ | {
894
+ readonly kind: 'report-ui-destination-commit-refusal'
895
+ readonly root: 'MANUAL'
896
+ readonly groupId: number
897
+ readonly commitSlotId: number
898
+ readonly authority: UiPreparedDestinationRecordState | null
899
+ readonly reason: UiDestinationCommitRefusalReason
900
+ }
901
+
902
+ export interface UiDestinationCommitAcknowledgementSlotState {
903
+ readonly acknowledgementSlotId: number
904
+ readonly commitSlotId: number
905
+ readonly state: 'EMPTY' | 'FILLED' | 'STAGED_IN_CURRENT_ENVELOPE'
906
+ readonly acknowledgement: DestinationCommitAcknowledgement | null
907
+ }
908
+
909
+ export interface ManualFrameGroupState {
910
+ readonly groupId: number
911
+ readonly currentAbsoluteTimestampMs: number
912
+ readonly participantDriverIds: readonly number[]
913
+ readonly callbackRegistrationGenerations: readonly number[]
914
+ readonly pendingDestinationCommits: readonly UiManualDestinationCommitSlot[]
915
+ readonly consumedCommitSlotIds: readonly number[]
916
+ readonly armedForExplicitStep: boolean
917
+ readonly explicitStepCount: number
918
+ }
919
+
920
+ export interface UiValueChannelCoordinatorState {
921
+ readonly runnerDriverId: number | null
922
+ readonly runnerLeaseEpoch: number
923
+ readonly runnerAdmissionRequest: UiRunnerAdmissionRequestState | null
924
+ readonly nextRunnerAdmissionToken: number
925
+ readonly nextMailboxDrainId: number
926
+ readonly publicIdentityChannels: readonly UiPublicIdentityChannelRecord[]
927
+ readonly generatorExecutions: readonly UiGeneratorExecutionRecord[]
928
+ readonly dueWorkTasks: readonly UiDueWorkTaskRecord[]
929
+ readonly valueCompletionControllers: readonly UiValueCompletionControllerRecord[]
930
+ readonly directOperations: readonly UiDirectOperationRecord[]
931
+ readonly carrierControllers: readonly UiCarrierControllerRecord[]
932
+ readonly mailboxTurns: readonly UiMailboxTurnRecord[]
933
+ readonly hostSinks: readonly UiHostSinkRecord[]
934
+ readonly preparedDestinationRecords: readonly UiPreparedDestinationRecordState[]
935
+ readonly destinationCommitAcknowledgementSlots: readonly UiDestinationCommitAcknowledgementSlotState[]
936
+ readonly callbacks: readonly UiCallbackRegistrationState[]
937
+ readonly relays: readonly UiColdWorkRelayState[]
938
+ readonly identities: readonly UiIdentityFrameState[]
939
+ readonly transaction: UiFrameTransactionState
940
+ readonly manualGroups: readonly ManualFrameGroupState[]
941
+ }
942
+
943
+ export interface UiValueChannelObservation {
944
+ readonly runnerDriverId: number | null
945
+ readonly runnerLeaseEpoch: number
946
+ readonly callbackCount: number
947
+ readonly callbackIdentityIds: readonly number[]
948
+ readonly callbackRegistrationGenerations: readonly number[]
949
+ readonly admittedDriverIds: readonly number[]
950
+ readonly relayCount: number
951
+ readonly unclaimedRelayCount: number
952
+ readonly identityCount: number
953
+ readonly totalIdentityStepCount: number
954
+ readonly totalHostCommitCount: number
955
+ readonly transactionKind: UiFrameTransactionState['kind']
956
+ readonly openTimestampMs: number | null
957
+ readonly expectedAttendeeCount: number
958
+ readonly visitedAttendeeCount: number
959
+ readonly revokedAttendeeCount: number
960
+ readonly lastCommittedTimestampMs: number | null
961
+ readonly committedFrameCount: number
962
+ readonly manualGroupCount: number
963
+ readonly armedManualGroupIds: readonly number[]
964
+ readonly pendingManualDestinationCommitCount: number
965
+ }
966
+
967
+ export type UiCoordinatorEvent =
968
+ | {
969
+ readonly kind: 'arm-cold-work-relay-at-command-edge'
970
+ readonly relayId: number
971
+ readonly targetDriverId: number
972
+ readonly commandSequence: number
973
+ readonly targetCallbackRegistrationGeneration: number
974
+ readonly relayLeaseEpoch: number
975
+ readonly lifetime: 'ONE_SHOT' | 'ONGOING_EXECUTION'
976
+ readonly armedAtTimestampMs: number
977
+ readonly commandReceipt: UiColdRelayCommandProductionTransition
978
+ }
979
+ | {
980
+ readonly kind: 'refresh-callback-observer'
981
+ readonly driverId: number
982
+ readonly callbackRegistrationGeneration: number
983
+ readonly observerRevision: number
984
+ }
985
+ | {
986
+ readonly kind: 'request-callback-activation'
987
+ readonly driverId: number
988
+ readonly callbackRegistrationGeneration: number
989
+ readonly requestedAtTimestampMs: number
990
+ readonly requestedRunnerLeaseEpoch: number
991
+ readonly admissionToken: number
992
+ readonly absoluteDeadlineMs: number
993
+ }
994
+ | {
995
+ readonly kind: 'invoke-live-callback'
996
+ readonly driverId: number
997
+ readonly callbackRegistrationGeneration: number
998
+ readonly callbackLeaseEpoch: number
999
+ readonly frame: UiCoordinatorFrameInfo
1000
+ }
1001
+ | {
1002
+ readonly kind: 'acknowledge-callback-admission'
1003
+ readonly candidateDriverId: number
1004
+ readonly callbackRegistrationGeneration: number
1005
+ readonly requestedRunnerLeaseEpoch: number
1006
+ readonly admissionToken: number
1007
+ }
1008
+ | {
1009
+ readonly kind: 'runner-admission-timeout'
1010
+ readonly candidateDriverId: number
1011
+ readonly callbackRegistrationGeneration: number
1012
+ readonly requestedRunnerLeaseEpoch: number
1013
+ readonly admissionToken: number
1014
+ readonly nowMs: number
1015
+ }
1016
+ | {
1017
+ readonly kind: 'retire-callback'
1018
+ readonly driverId: number
1019
+ readonly callbackRegistrationGeneration: number
1020
+ }
1021
+ | {
1022
+ readonly kind: 'dispose-callback'
1023
+ readonly driverId: number
1024
+ readonly callbackRegistrationGeneration: number
1025
+ }
1026
+
1027
+ export interface UiManualFrameCrossing {
1028
+ readonly groupId: number
1029
+ readonly absoluteTimestampMs: number
1030
+ readonly orderedAttendeeDriverIds: readonly number[]
1031
+ readonly callbackRegistrationGenerations: readonly number[]
1032
+ }
1033
+
1034
+ export interface UiManualParticipantInvocation {
1035
+ readonly groupId: number
1036
+ readonly absoluteTimestampMs: number
1037
+ readonly driverId: number
1038
+ readonly callbackRegistrationGeneration: number
1039
+ readonly invocationIndex: number
1040
+ }
1041
+
1042
+ export interface UiManualParticipantRevocation {
1043
+ readonly groupId: number
1044
+ readonly absoluteTimestampMs: number
1045
+ readonly driverId: number
1046
+ readonly callbackRegistrationGeneration: number
1047
+ }
1048
+
1049
+ export interface UiManualFrameCommitRequest {
1050
+ readonly groupId: number
1051
+ readonly absoluteTimestampMs: number
1052
+ }
1053
+
1054
+ export interface UiLiveDestinationCommitSlot extends ImmutableDestinationCommit {
1055
+ readonly commitSlotId: number
1056
+ readonly acknowledgementSlotId: number
1057
+ }
1058
+
1059
+ export interface UiLiveSiblingEmission {
1060
+ readonly emissionSequence: number
1061
+ readonly emissionKind: 'FRAME_WRITE' | 'LIFECYCLE' | 'TARGET_BATCH_DEPENDENCY' | 'HOST'
1062
+ }
1063
+
1064
+ export type UiLiveDestinationEnvelopeEntry =
1065
+ | {
1066
+ readonly kind: 'DESTINATION_COMMIT_ACKNOWLEDGEMENT'
1067
+ readonly acknowledgementSlotId: number
1068
+ readonly drainedThroughAuthoritativeSequence: number
1069
+ }
1070
+ | ({ readonly kind: 'SIBLING_EMISSION' } & UiLiveSiblingEmission)
1071
+
1072
+ export interface UiLiveDestinationEnvelopeState {
1073
+ readonly mailboxDrainId: number
1074
+ readonly state: 'OPEN' | 'SEALED'
1075
+ readonly entries: readonly UiLiveDestinationEnvelopeEntry[]
1076
+ readonly sealCount: number
1077
+ }
1078
+
1079
+ export interface UiLiveDestinationCommitConsumeState {
1080
+ readonly coordinator: UiValueChannelCoordinatorState
1081
+ readonly envelope: UiLiveDestinationEnvelopeState
1082
+ }
1083
+
1084
+ export interface UiLiveDestinationCommitConsumeRequest {
1085
+ readonly driverId: number
1086
+ readonly callbackRegistrationGeneration: number
1087
+ readonly absoluteTimestampMs: number
1088
+ readonly commit: UiLiveDestinationCommitSlot
1089
+ readonly siblingEmissions: readonly UiLiveSiblingEmission[]
1090
+ }
1091
+
1092
+ export type UiLiveDestinationCommitRefusalReason = UiDestinationCommitRefusalReason
1093
+
1094
+ export type UiLiveDestinationCommitConsumeOutcome =
1095
+ | {
1096
+ readonly kind: 'APPLIED'
1097
+ readonly commitSlotId: number
1098
+ readonly acknowledgement: DestinationCommitAcknowledgement
1099
+ }
1100
+ | {
1101
+ readonly kind: 'DUPLICATE_REACKNOWLEDGED'
1102
+ readonly commitSlotId: number
1103
+ readonly acknowledgement: DestinationCommitAcknowledgement
1104
+ }
1105
+ | {
1106
+ readonly kind: 'REFUSED'
1107
+ readonly commitSlotId: number
1108
+ readonly reason: UiLiveDestinationCommitRefusalReason
1109
+ }
1110
+
1111
+ export type UiLiveDestinationCommitEffect =
1112
+ | {
1113
+ readonly kind: 'lookup-live-prepared-destination-record'
1114
+ readonly destinationRecordId: number
1115
+ }
1116
+ | UiDestinationCommitCanonicalValidationEffect
1117
+ | {
1118
+ readonly kind: 'adopt-live-immutable-destination-commit'
1119
+ readonly commitSlotId: number
1120
+ }
1121
+ | {
1122
+ readonly kind: 'apply-live-included-post-fence-ledger-entry-in-place'
1123
+ readonly commitSlotId: number
1124
+ readonly prefixIndex: number
1125
+ readonly destinationSlot: NormalizedRetainedWorkEntry['destinationSlot']
1126
+ readonly entry: NormalizedRetainedWorkEntry
1127
+ }
1128
+ | {
1129
+ readonly kind: 'fill-live-destination-acknowledgement-slot'
1130
+ readonly commitSlotId: number
1131
+ readonly acknowledgementSlotId: number
1132
+ }
1133
+ | {
1134
+ readonly kind: 'stage-live-destination-acknowledgement-in-current-envelope'
1135
+ readonly acknowledgementSlotId: number
1136
+ readonly mailboxDrainId: number
1137
+ }
1138
+ | UiDestinationCommitRefusalReportEffect
1139
+ | ({ readonly kind: 'emit-live-ui-sibling' } & UiLiveSiblingEmission)
1140
+ | {
1141
+ readonly kind: 'seal-live-ui-envelope-once'
1142
+ readonly mailboxDrainId: number
1143
+ readonly entryCount: number
1144
+ }
1145
+
1146
+ export interface UiLiveDestinationCommitTransition {
1147
+ readonly state: UiLiveDestinationCommitConsumeState
1148
+ readonly outcome: UiLiveDestinationCommitConsumeOutcome
1149
+ readonly orderedEffects: readonly UiLiveDestinationCommitEffect[]
1150
+ }
1151
+
1152
+ interface UiSharedManualIdentityTransferGapCommon {
1153
+ readonly groupId: number
1154
+ readonly channelId: number
1155
+ readonly absoluteTimestampMs: number
1156
+ readonly orderedAttendeeDriverIds: readonly [number, number]
1157
+ readonly callbackRegistrationGenerations: readonly [number, number]
1158
+ readonly transferLease: number
1159
+ readonly sourceRecordId: number
1160
+ readonly destinationRecordId: number
1161
+ }
1162
+
1163
+ export type UiSharedManualIdentityTransferGapRequest =
1164
+ | (UiSharedManualIdentityTransferGapCommon & {
1165
+ readonly direction: 'UI_TO_JS'
1166
+ readonly ownershipAtBegin: 'UI_RELEASE_PENDING_TO_JS'
1167
+ readonly ownershipAtCommit: 'UI_RELEASED_TO_JS'
1168
+ })
1169
+ | (UiSharedManualIdentityTransferGapCommon & {
1170
+ readonly direction: 'JS_TO_UI'
1171
+ readonly ownershipAtBegin: 'JS_RELEASE_PENDING_TO_UI'
1172
+ readonly ownershipAtCommit: 'JS_RELEASED_TO_UI'
1173
+ })
1174
+
1175
+ export type UiSharedManualIdentityTransferGapEffect =
1176
+ | {
1177
+ readonly kind: 'begin-shared-manual-transfer-transaction'
1178
+ readonly groupId: number
1179
+ readonly channelId: number
1180
+ readonly absoluteTimestampMs: number
1181
+ readonly orderedAttendeeDriverIds: readonly [number, number]
1182
+ readonly callbackRegistrationGenerations: readonly [number, number]
1183
+ }
1184
+ | {
1185
+ readonly kind: 'invoke-shared-manual-transfer-participant'
1186
+ readonly groupId: number
1187
+ readonly driverId: number
1188
+ readonly callbackRegistrationGeneration: number
1189
+ readonly invocationIndex: 0 | 1
1190
+ readonly absoluteTimestampMs: number
1191
+ }
1192
+ | {
1193
+ readonly kind: 'bridge-shared-identity-transfer-gap'
1194
+ readonly channelId: number
1195
+ readonly direction: 'UI_TO_JS' | 'JS_TO_UI'
1196
+ readonly transferLease: number
1197
+ readonly sourceRecordId: number
1198
+ readonly destinationRecordId: number
1199
+ readonly absoluteTimestampMs: number
1200
+ }
1201
+ | {
1202
+ readonly kind: 'step-shared-manual-transfer-identity-once'
1203
+ readonly channelId: number
1204
+ readonly absoluteTimestampMs: number
1205
+ }
1206
+ | {
1207
+ readonly kind: 'commit-shared-manual-transfer-transaction-once'
1208
+ readonly groupId: number
1209
+ readonly absoluteTimestampMs: number
1210
+ }
1211
+
1212
+ export interface UiSharedManualIdentityTransferGapTransition {
1213
+ readonly state: UiValueChannelCoordinatorState
1214
+ readonly observation: UiValueChannelObservation
1215
+ readonly orderedEffects: readonly UiSharedManualIdentityTransferGapEffect[]
1216
+ }
1217
+
1218
+ export interface ManualFrameGroupStepRequest {
1219
+ readonly groupId: number
1220
+ readonly elapsedMs: number
1221
+ readonly invocationOrder?: readonly number[]
1222
+ }
1223
+
1224
+ export interface LegacyManualDriverStepRequest {
1225
+ readonly groupId: number
1226
+ readonly driverId: number
1227
+ readonly elapsedMs: number
1228
+ }
1229
+
1230
+ export type UiValueChannelEffect =
1231
+ | UiColdRelayEffect
1232
+ | UiDestinationCommitCanonicalValidationEffect
1233
+ | UiDestinationCommitRefusalReportEffect
1234
+ | {
1235
+ readonly kind: 'retain-stable-callback-registration'
1236
+ readonly driverId: number
1237
+ readonly callbackIdentityId: number
1238
+ readonly callbackRegistrationGeneration: number
1239
+ }
1240
+ | {
1241
+ readonly kind: 'defer-callback-admission-to-next-timestamp'
1242
+ readonly driverId: number
1243
+ readonly afterTimestampMs: number
1244
+ }
1245
+ | {
1246
+ readonly kind: 'admit-callback-lease'
1247
+ readonly driverId: number
1248
+ readonly callbackLeaseEpoch: number
1249
+ readonly absoluteTimestampMs: number
1250
+ }
1251
+ | {
1252
+ readonly kind: 'publish-actual-callback-invocation-admission'
1253
+ readonly driverId: number
1254
+ readonly callbackRegistrationGeneration: number
1255
+ readonly callbackLeaseEpoch: number
1256
+ }
1257
+ | {
1258
+ readonly kind: 'start-runner-admission-timer'
1259
+ readonly requestedRunnerLeaseEpoch: number
1260
+ readonly candidateDriverId: number
1261
+ readonly callbackRegistrationGeneration: number
1262
+ readonly admissionToken: number
1263
+ readonly absoluteDeadlineMs: number
1264
+ }
1265
+ | { readonly kind: 'cancel-runner-admission-timer'; readonly admissionToken: number }
1266
+ | {
1267
+ readonly kind: 'transfer-runner-lease-after-admission-acknowledgement'
1268
+ readonly fromDriverId: number | null
1269
+ readonly toDriverId: number
1270
+ readonly runnerLeaseEpoch: number
1271
+ }
1272
+ | {
1273
+ readonly kind: 'invalidate-runner-admission-candidate'
1274
+ readonly driverId: number
1275
+ readonly admissionToken: number
1276
+ }
1277
+ | {
1278
+ readonly kind: 'select-next-live-runner-candidate'
1279
+ readonly excludedDriverIds: readonly number[]
1280
+ readonly selectedDriverId: number
1281
+ }
1282
+ | {
1283
+ readonly kind: 'open-frame-transaction'
1284
+ readonly mode: 'LIVE' | 'MANUAL'
1285
+ readonly absoluteTimestampMs: number
1286
+ }
1287
+ | {
1288
+ readonly kind: 'claim-cold-work-relay'
1289
+ readonly relayId: number
1290
+ readonly driverId: number
1291
+ }
1292
+ | {
1293
+ readonly kind: 'peek-relayed-driver-state'
1294
+ readonly relayId: number
1295
+ readonly targetDriverId: number
1296
+ }
1297
+ | {
1298
+ readonly kind: 'step-cold-work-relay'
1299
+ readonly relayId: number
1300
+ readonly targetDriverId: number
1301
+ readonly absoluteTimestampMs: number
1302
+ }
1303
+ | {
1304
+ readonly kind: 'form-cold-work-relay-value-bearing-mailbox-prefix'
1305
+ readonly relayId: number
1306
+ readonly canonicalRecord: UiColdRelayCanonicalRecord
1307
+ readonly sourceEntry: UiColdWorkRelayValueBearingEntry
1308
+ readonly openTurn: UiColdWorkRelayMailboxPrefix
1309
+ }
1310
+ | { readonly kind: 'retain-ongoing-relay-until-target-claim'; readonly relayId: number }
1311
+ | { readonly kind: 'release-claimed-relay'; readonly relayId: number }
1312
+ | {
1313
+ readonly kind: 'step-shared-identity-once'
1314
+ readonly channelId: number
1315
+ readonly absoluteTimestampMs: number
1316
+ readonly deltaMs: number
1317
+ }
1318
+ | { readonly kind: 'record-attendance'; readonly driverId: number }
1319
+ | { readonly kind: 'record-synthetic-revocation-attendance'; readonly driverId: number }
1320
+ | { readonly kind: 'retire-callback-effective-next-timestamp'; readonly driverId: number }
1321
+ | { readonly kind: 'delete-disposed-callback-after-attendance'; readonly driverId: number }
1322
+ | { readonly kind: 'commit-frame-once'; readonly absoluteTimestampMs: number }
1323
+ | {
1324
+ readonly kind: 'advance-manual-group-clock-once'
1325
+ readonly groupId: number
1326
+ readonly absoluteTimestampMs: number
1327
+ }
1328
+ | {
1329
+ readonly kind: 'freeze-manual-attendee-batch'
1330
+ readonly groupId: number
1331
+ readonly orderedAttendeeDriverIds: readonly number[]
1332
+ }
1333
+ | {
1334
+ readonly kind: 'arm-manual-group-for-destination-commit'
1335
+ readonly groupId: number
1336
+ readonly commitSlotId: number
1337
+ }
1338
+ | {
1339
+ readonly kind: 'consume-manual-destination-commit-on-explicit-step'
1340
+ readonly groupId: number
1341
+ readonly commitSlotId: number
1342
+ }
1343
+ | {
1344
+ readonly kind: 'lookup-prepared-destination-record'
1345
+ readonly groupId: number
1346
+ readonly destinationRecordId: number
1347
+ }
1348
+ | {
1349
+ readonly kind: 'adopt-immutable-destination-commit'
1350
+ readonly groupId: number
1351
+ readonly commitSlotId: number
1352
+ }
1353
+ | {
1354
+ readonly kind: 'apply-included-post-fence-ledger-entry-in-place'
1355
+ readonly groupId: number
1356
+ readonly commitSlotId: number
1357
+ readonly prefixIndex: number
1358
+ readonly destinationSlot: NormalizedRetainedWorkEntry['destinationSlot']
1359
+ readonly entry: NormalizedRetainedWorkEntry
1360
+ }
1361
+ | {
1362
+ readonly kind: 'fill-prefilled-destination-acknowledgement-slot'
1363
+ readonly groupId: number
1364
+ readonly commitSlotId: number
1365
+ readonly acknowledgementSlotId: number
1366
+ }
1367
+ | {
1368
+ readonly kind: 'stage-destination-acknowledgement-in-current-envelope'
1369
+ readonly groupId: number
1370
+ readonly acknowledgementSlotId: number
1371
+ readonly mailboxDrainId: number
1372
+ }
1373
+ | {
1374
+ readonly kind: 'delegate-legacy-step-to-private-single-member-group'
1375
+ readonly groupId: number
1376
+ readonly driverId: number
1377
+ }
1378
+ | { readonly kind: 'already-committed-no-op'; readonly absoluteTimestampMs: number }
1379
+
1380
+ export type UiManualFrameRefusal =
1381
+ | {
1382
+ readonly kind: 'MISSING_ATTENDEES'
1383
+ readonly missingDriverIds: readonly number[]
1384
+ }
1385
+ | {
1386
+ readonly kind: 'LATE_ATTENDANCE'
1387
+ readonly driverId: number
1388
+ readonly alreadyCommittedTimestampMs: number
1389
+ }
1390
+ | {
1391
+ readonly kind: 'MULTI_MEMBER_GROUP_REQUIRES_GROUP_STEP'
1392
+ readonly groupId: number
1393
+ readonly participantCount: number
1394
+ }
1395
+ | {
1396
+ readonly kind: 'DESTINATION_COMMIT_REFUSED'
1397
+ readonly groupId: number
1398
+ readonly commitSlotId: number
1399
+ readonly authority: UiPreparedDestinationRecordState | null
1400
+ readonly reason: UiDestinationCommitRefusalReason
1401
+ }
1402
+
1403
+ export interface UiValueChannelTransition {
1404
+ readonly state: UiValueChannelCoordinatorState
1405
+ readonly observation: UiValueChannelObservation
1406
+ readonly orderedEffects: readonly UiValueChannelEffect[]
1407
+ readonly refusal: UiManualFrameRefusal | null
1408
+ }
1409
+
1410
+ export type UiPrivateTargetBatchDependencyEventKind =
1411
+ | 'RAW_RESOLVED'
1412
+ | 'VALUE_ACKNOWLEDGED'
1413
+ | 'PERMANENTLY_UNRESOLVED'
1414
+
1415
+ /**
1416
+ * UI-owned private controls never borrow a public MotionValue identity outbox. The owning adapter
1417
+ * keeps the primitive sequence needed to prefill one dependency event into the transaction that is
1418
+ * already open for the live or manual frame root.
1419
+ */
1420
+ export interface UiPrivateTargetBatchAdapterState {
1421
+ readonly controlId: number
1422
+ readonly batchId: number
1423
+ readonly dependencyId: number
1424
+ readonly nextDependencyEventSequence: number
1425
+ readonly stagedDependencyEventCount: number
1426
+ }
1427
+
1428
+ export interface UiPrivateTargetBatchDependencyEventRequest {
1429
+ readonly controlId: number
1430
+ readonly batchId: number
1431
+ readonly dependencyId: number
1432
+ readonly kind: UiPrivateTargetBatchDependencyEventKind
1433
+ }
1434
+
1435
+ export interface UiPrefilledPrivateTargetBatchDependencyEvent {
1436
+ readonly kind: 'TARGET_BATCH_DEPENDENCY_EVENT'
1437
+ readonly batchId: number
1438
+ readonly dependencyId: number
1439
+ readonly dependencyEventKind: UiPrivateTargetBatchDependencyEventKind
1440
+ readonly eventSequence: number
1441
+ readonly ownerControlId: number
1442
+ }
1443
+
1444
+ export type UiPrivateTargetBatchDependencyEventEffect =
1445
+ | {
1446
+ readonly kind: 'PREFILL_PRIVATE_TARGET_BATCH_DEPENDENCY_EVENT'
1447
+ readonly transactionMode: 'LIVE' | 'MANUAL'
1448
+ readonly event: UiPrefilledPrivateTargetBatchDependencyEvent
1449
+ }
1450
+ | {
1451
+ readonly kind: 'ADVANCE_PRIVATE_TARGET_BATCH_EVENT_SEQUENCE'
1452
+ readonly controlId: number
1453
+ readonly eventSequence: number
1454
+ }
1455
+
1456
+ export interface UiPrivateTargetBatchDependencyEventTransition {
1457
+ readonly adapter: UiPrivateTargetBatchAdapterState
1458
+ readonly orderedEffects: readonly UiPrivateTargetBatchDependencyEventEffect[]
1459
+ }
1460
+
1461
+ export type UiRunnerAdmissionCandidateKind =
1462
+ | 'RUNNER_CANDIDATE'
1463
+ | 'ADMITTED'
1464
+ | 'EXPIRED'
1465
+ | 'DISPOSED'
1466
+
1467
+ export interface UiRunnerAdmissionCandidateState {
1468
+ readonly driverId: number
1469
+ readonly callbackRegistrationGeneration: number
1470
+ readonly callbackLeaseEpoch: number
1471
+ readonly requestedAtTimestampMs: number
1472
+ readonly absoluteAdmissionDeadlineMs: number
1473
+ readonly state: UiRunnerAdmissionCandidateKind
1474
+ readonly invocationObserved: boolean
1475
+ }
1476
+
1477
+ export interface UiRunnerRetainedPassiveSinkState {
1478
+ readonly sinkId: number
1479
+ readonly driverId: number
1480
+ readonly handleId: number
1481
+ readonly bindingGeneration: number
1482
+ readonly key: string
1483
+ }
1484
+
1485
+ export interface UiRunnerInstalledPreArmControlSlotState {
1486
+ readonly controlId: number
1487
+ readonly executionId: number
1488
+ }
1489
+
1490
+ export interface UiRunnerRetainedCarrierReferenceState {
1491
+ readonly batchId: number
1492
+ readonly carrierId: number
1493
+ readonly identityId: number
1494
+ readonly authoredIndex: number
1495
+ }
1496
+
1497
+ export interface UiRunnerRetainedChannelState {
1498
+ readonly channelId: number
1499
+ readonly passiveSinks: readonly UiRunnerRetainedPassiveSinkState[]
1500
+ readonly installedPreArmControlSlot: UiRunnerInstalledPreArmControlSlotState | null
1501
+ readonly physicalExecutions: readonly Extract<
1502
+ NormalizedRetainedWorkEntry,
1503
+ { readonly kind: 'generator-execution' }
1504
+ >[]
1505
+ readonly dueWork: readonly Extract<
1506
+ NormalizedRetainedWorkEntry,
1507
+ { readonly kind: 'update-task' | 'carrier-task' | 'direct-write' }
1508
+ >[]
1509
+ readonly valueCompletions: readonly Extract<
1510
+ NormalizedRetainedWorkEntry,
1511
+ { readonly kind: 'value-completion' }
1512
+ >[]
1513
+ readonly batchDependencyEvents: readonly Extract<
1514
+ NormalizedRetainedWorkEntry,
1515
+ { readonly kind: 'target-batch-dependency-event' }
1516
+ >[]
1517
+ readonly carrierReferences: readonly UiRunnerRetainedCarrierReferenceState[]
1518
+ }
1519
+
1520
+ export interface UiRunnerRetainedWorkRuntime {
1521
+ reportFinalRunnerTimeoutRefusal(channelIds: readonly number[]): void
1522
+ stopInstalledPreArmSlot(channelId: number, slot: UiRunnerInstalledPreArmControlSlotState): void
1523
+ transferRetainedChannelWork(channel: UiRunnerRetainedChannelState): void
1524
+ }
1525
+
1526
+ export interface UiRunnerAdmissionState {
1527
+ readonly runnerDriverId: number | null
1528
+ readonly runnerLeaseEpoch: number
1529
+ readonly candidates: readonly UiRunnerAdmissionCandidateState[]
1530
+ readonly retainedChannels: readonly UiRunnerRetainedChannelState[]
1531
+ readonly timeoutRefusalCount: number
1532
+ readonly retainedWorkTransferRequestCount: number
1533
+ }
1534
+
1535
+ export type UiRunnerAdmissionEvent =
1536
+ | {
1537
+ readonly kind: 'runner-candidate-timeout'
1538
+ readonly driverId: number
1539
+ readonly callbackRegistrationGeneration: number
1540
+ readonly callbackLeaseEpoch: number
1541
+ readonly observedAtTimestampMs: number
1542
+ }
1543
+ | {
1544
+ readonly kind: 'invoke-runner-candidate'
1545
+ readonly driverId: number
1546
+ readonly callbackRegistrationGeneration: number
1547
+ readonly callbackLeaseEpoch: number
1548
+ readonly observedAtTimestampMs: number
1549
+ }
1550
+ | {
1551
+ readonly kind: 'dispose-runner-candidate'
1552
+ readonly driverId: number
1553
+ readonly callbackRegistrationGeneration: number
1554
+ readonly callbackLeaseEpoch: number
1555
+ }
1556
+
1557
+ export type UiRunnerAdmissionEffect =
1558
+ | { readonly kind: 'EXPIRE_RUNNER_CANDIDATE'; readonly driverId: number }
1559
+ | { readonly kind: 'DISPOSE_RUNNER_CANDIDATE'; readonly driverId: number }
1560
+ | {
1561
+ readonly kind: 'SELECT_SUCCESSOR_RUNNER_CANDIDATE'
1562
+ readonly driverId: number
1563
+ readonly callbackLeaseEpoch: number
1564
+ }
1565
+ | {
1566
+ readonly kind: 'ADMIT_INVOKED_RUNNER_CANDIDATE'
1567
+ readonly driverId: number
1568
+ readonly callbackLeaseEpoch: number
1569
+ }
1570
+ | { readonly kind: 'IGNORE_STALE_RUNNER_EVENT'; readonly driverId: number }
1571
+ | {
1572
+ readonly kind: 'REPORT_FINAL_RUNNER_TIMEOUT_REFUSAL'
1573
+ readonly channelIds: readonly number[]
1574
+ }
1575
+ | {
1576
+ readonly kind: 'STOP_INSTALLED_PRE_ARM_SLOT_ONLY'
1577
+ readonly channelId: number
1578
+ readonly slot: UiRunnerInstalledPreArmControlSlotState
1579
+ }
1580
+ | {
1581
+ readonly kind: 'TRANSFER_RETAINED_CHANNEL_WORK'
1582
+ readonly channel: UiRunnerRetainedChannelState
1583
+ }
1584
+
1585
+ export interface UiRunnerAdmissionTransition {
1586
+ readonly state: UiRunnerAdmissionState
1587
+ readonly orderedEffects: readonly UiRunnerAdmissionEffect[]
1588
+ }
1589
+
1590
+ export interface UiRecursionExecutionSeed {
1591
+ readonly executionId: number
1592
+ readonly targetValue: number
1593
+ readonly firstSampleValue: number
1594
+ readonly commandSequence: number
1595
+ readonly completionSequence: number
1596
+ }
1597
+
1598
+ export type UiRecursionExecutionPhase = 'RUNNING' | 'STOPPED' | 'COMPLETED'
1599
+
1600
+ export interface UiRecursionExecutionState extends UiRecursionExecutionSeed {
1601
+ readonly updateSequence: number
1602
+ readonly stopCount: number
1603
+ readonly phase: UiRecursionExecutionPhase
1604
+ readonly orphaned: boolean
1605
+ }
1606
+
1607
+ export interface UiQueuedInstantCompletionRecursionEntry {
1608
+ readonly completionId: number
1609
+ readonly completionSequence: number
1610
+ readonly callbackSuccessor: UiRecursionExecutionSeed
1611
+ }
1612
+
1613
+ export interface UiGuardedCancelListenerState {
1614
+ readonly listenerId: number
1615
+ readonly hasStartedSuccessor: boolean
1616
+ readonly successor: UiRecursionExecutionSeed
1617
+ }
1618
+
1619
+ /**
1620
+ * Primitive-only UI-channel state for the pin's synchronous listener-recursion seam. No callback,
1621
+ * host object, MotionValue, generator, or promise crosses this reducer boundary.
1622
+ */
1623
+ export interface UiValueChannelRecursionState {
1624
+ readonly channelId: number
1625
+ readonly currentValue: number
1626
+ readonly publicControlSlotExecutionId: number | null
1627
+ readonly executions: readonly UiRecursionExecutionState[]
1628
+ readonly queuedInstantCompletions: readonly UiQueuedInstantCompletionRecursionEntry[]
1629
+ readonly guardedCancelListeners: readonly UiGuardedCancelListenerState[]
1630
+ readonly nextUpdateSequence: number
1631
+ }
1632
+
1633
+ export type UiValueChannelRecursionEvent =
1634
+ | { readonly kind: 'drain-queued-instant-completions' }
1635
+ | { readonly kind: 'apply-recursive-outer-stop' }
1636
+ | { readonly kind: 'apply-recursive-outer-jump'; readonly value: number }
1637
+ | {
1638
+ readonly kind: 'apply-recursive-interrupting-start'
1639
+ readonly successor: UiRecursionExecutionSeed
1640
+ }
1641
+ | {
1642
+ readonly kind: 'sample-runnable-recursion-executions'
1643
+ readonly absoluteTimestampMs: number
1644
+ }
1645
+ | {
1646
+ readonly kind: 'install-recursion-successor'
1647
+ readonly successor: UiRecursionExecutionSeed
1648
+ }
1649
+ | {
1650
+ readonly kind: 'complete-recursion-execution'
1651
+ readonly executionId: number
1652
+ readonly completionSequence: number
1653
+ }
1654
+
1655
+ export type UiValueChannelRecursionEffect =
1656
+ | {
1657
+ readonly kind: 'DELIVER_QUEUED_INSTANT_COMPLETION'
1658
+ readonly completionId: number
1659
+ readonly completionSequence: number
1660
+ }
1661
+ | {
1662
+ readonly kind: 'DELIVER_GUARDED_CANCEL_LISTENER'
1663
+ readonly listenerId: number
1664
+ readonly cancelDeliveryOrdinal: number
1665
+ }
1666
+ | {
1667
+ readonly kind: 'ISSUE_REENTRANT_START_COMMAND'
1668
+ readonly executionId: number
1669
+ readonly commandSequence: number
1670
+ readonly source: 'INSTANT_COMPLETION' | 'GUARDED_CANCEL_LISTENER'
1671
+ readonly sourceId: number
1672
+ }
1673
+ | {
1674
+ readonly kind: 'STOP_EXECUTION_IDEMPOTENT'
1675
+ readonly executionId: number
1676
+ readonly stopOrdinal: number
1677
+ readonly source: 'OUTER_OPERATION' | 'REENTRANT_START'
1678
+ }
1679
+ | {
1680
+ readonly kind: 'INSTALL_RECURSION_EXECUTION'
1681
+ readonly executionId: number
1682
+ readonly commandSequence: number
1683
+ readonly updateSequence: number
1684
+ readonly role:
1685
+ | 'COMPLETION_SUCCESSOR'
1686
+ | 'CANCEL_LISTENER_SUCCESSOR'
1687
+ | 'INTERRUPTING_SUCCESSOR'
1688
+ | 'LATER_LIVE_SUCCESSOR'
1689
+ }
1690
+ | {
1691
+ readonly kind: 'CLEAR_PUBLIC_CONTROL_SLOT_TOKEN_BLIND'
1692
+ readonly source: 'INSTANT_COMPLETION' | 'STOP_CONTINUATION' | 'VALUE_COMPLETION'
1693
+ readonly sourceId: number
1694
+ readonly clearedExecutionId: number | null
1695
+ }
1696
+ | { readonly kind: 'APPLY_OUTER_JUMP'; readonly value: number }
1697
+ | {
1698
+ readonly kind: 'SAMPLE_RECURSION_EXECUTION'
1699
+ readonly executionId: number
1700
+ readonly updateSequence: number
1701
+ readonly value: number
1702
+ readonly absoluteTimestampMs: number
1703
+ readonly orphaned: boolean
1704
+ }
1705
+ | {
1706
+ readonly kind: 'COMPLETE_RECURSION_EXECUTION'
1707
+ readonly executionId: number
1708
+ readonly completionSequence: number
1709
+ }
1710
+
1711
+ export interface UiValueChannelRecursionTransition {
1712
+ readonly state: UiValueChannelRecursionState
1713
+ readonly orderedEffects: readonly UiValueChannelRecursionEffect[]
1714
+ }
1715
+
1716
+ export type UiValueChannelOperation =
1717
+ | UiCoordinatorEvent['kind']
1718
+ | 'ui-begin-manual-frame'
1719
+ | 'ui-invoke-manual-participant'
1720
+ | 'ui-revoke-manual-participant'
1721
+ | 'ui-commit-manual-frame'
1722
+ | 'arm-manual-destination-commit'
1723
+ | 'step-manual-frame-group'
1724
+ | 'consume-live-ui-destination-commit'
1725
+ | 'produce-cold-relay-command-from-canonical-state'
1726
+ | 'validate-ui-destination-commit-with-canonical-authority'
1727
+ | 'observe-cold-relay-canonical-record'
1728
+ | 'step-shared-manual-identity-transfer-gap'
1729
+ | 'fanout-ui-owned-identity-sample'
1730
+ | 'step-legacy-manual-driver'
1731
+ | 'stage-private-target-batch-dependency-event'
1732
+ | UiRunnerAdmissionEvent['kind']
1733
+ | UiValueChannelRecursionEvent['kind']
1734
+
1735
+ export const UI_VALUE_CHANNEL_UNIMPLEMENTED =
1736
+ 'NATIVE_MOTION_UI_VALUE_CHANNEL_UNIMPLEMENTED' as const
1737
+
1738
+ export class UiValueChannelUnimplementedError extends Error {
1739
+ readonly code = UI_VALUE_CHANNEL_UNIMPLEMENTED
1740
+ readonly operation: UiValueChannelOperation
1741
+
1742
+ constructor(operation: UiValueChannelOperation) {
1743
+ super(
1744
+ `native-motion: UI value-channel operation '${operation}' is unimplemented ` +
1745
+ '(REQ-DRIVER-034)',
1746
+ )
1747
+ this.name = 'UiValueChannelUnimplementedError'
1748
+ this.operation = operation
1749
+ }
1750
+ }
1751
+
1752
+ export function observeUiValueChannel(
1753
+ state: UiValueChannelCoordinatorState,
1754
+ ): UiValueChannelObservation {
1755
+ let totalIdentityStepCount = 0
1756
+ let totalHostCommitCount = 0
1757
+ for (const identity of state.identities) {
1758
+ totalIdentityStepCount += identity.stepCount
1759
+ totalHostCommitCount += identity.hostCommitCount
1760
+ }
1761
+
1762
+ let unclaimedRelayCount = 0
1763
+ for (const relay of state.relays) {
1764
+ if (relay.claimedAtTimestampMs === null) unclaimedRelayCount += 1
1765
+ }
1766
+
1767
+ const admittedDriverIds: number[] = []
1768
+ for (const callback of state.callbacks) {
1769
+ if (callback.state === 'ADMITTED') admittedDriverIds.push(callback.driverId)
1770
+ }
1771
+
1772
+ const armedManualGroupIds: number[] = []
1773
+ let pendingManualDestinationCommitCount = 0
1774
+ for (const group of state.manualGroups) {
1775
+ if (group.armedForExplicitStep) armedManualGroupIds.push(group.groupId)
1776
+ pendingManualDestinationCommitCount += group.pendingDestinationCommits.length
1777
+ }
1778
+
1779
+ const transaction = state.transaction
1780
+ return {
1781
+ runnerDriverId: state.runnerDriverId,
1782
+ runnerLeaseEpoch: state.runnerLeaseEpoch,
1783
+ callbackCount: state.callbacks.length,
1784
+ callbackIdentityIds: state.callbacks.map((callback) => callback.callbackIdentityId),
1785
+ callbackRegistrationGenerations: state.callbacks.map(
1786
+ (callback) => callback.callbackRegistrationGeneration,
1787
+ ),
1788
+ admittedDriverIds,
1789
+ relayCount: state.relays.length,
1790
+ unclaimedRelayCount,
1791
+ identityCount: state.identities.length,
1792
+ totalIdentityStepCount,
1793
+ totalHostCommitCount,
1794
+ transactionKind: transaction.kind,
1795
+ openTimestampMs: transaction.kind === 'OPEN' ? transaction.absoluteTimestampMs : null,
1796
+ expectedAttendeeCount:
1797
+ transaction.kind === 'OPEN' ? transaction.expectedAttendeeDriverIds.length : 0,
1798
+ visitedAttendeeCount:
1799
+ transaction.kind === 'OPEN' ? transaction.visitedAttendeeDriverIds.length : 0,
1800
+ revokedAttendeeCount:
1801
+ transaction.kind === 'OPEN' ? transaction.revokedAttendeeDriverIds.length : 0,
1802
+ lastCommittedTimestampMs: transaction.lastCommittedTimestampMs,
1803
+ committedFrameCount: transaction.committedFrameCount,
1804
+ manualGroupCount: state.manualGroups.length,
1805
+ armedManualGroupIds,
1806
+ pendingManualDestinationCommitCount,
1807
+ }
1808
+ }
1809
+
1810
+ export const UI_VALUE_CHANNEL_INVARIANT = 'NATIVE_MOTION_UI_VALUE_CHANNEL_INVARIANT' as const
1811
+
1812
+ export type UiValueChannelInvariant =
1813
+ | 'coordinator-event-kind-unrecognized'
1814
+ | 'runner-admission-event-kind-unrecognized'
1815
+ | 'recursion-event-kind-unrecognized'
1816
+ | 'cold-relay-command-kind-unrecognized'
1817
+ | 'cold-relay-source-record-missing'
1818
+ | 'cold-relay-mailbox-record-missing'
1819
+ | 'cold-relay-host-sink-missing'
1820
+ | 'cold-relay-target-callback-missing'
1821
+ | 'cold-relay-canonical-record-unknown'
1822
+ | 'callback-registration-missing'
1823
+ | 'callback-registration-conflict'
1824
+ | 'runner-admission-request-conflict'
1825
+ | 'manual-frame-group-missing'
1826
+ | 'frame-transaction-conflict'
1827
+ | 'frame-attendance-conflict'
1828
+ | 'owned-identity-channel-conflict'
1829
+ | 'private-target-batch-adapter-conflict'
1830
+ | 'private-target-batch-transaction-closed'
1831
+ | 'shared-transfer-identity-missing'
1832
+
1833
+ /** Typed fail-closed refusal for malformed, conflicting, or out-of-sequence UI-channel input. */
1834
+ export class UiValueChannelInvariantError extends Error {
1835
+ readonly code = UI_VALUE_CHANNEL_INVARIANT
1836
+ readonly invariant: UiValueChannelInvariant
1837
+ readonly operation: UiValueChannelOperation | null
1838
+
1839
+ constructor(invariant: UiValueChannelInvariant, operation?: UiValueChannelOperation) {
1840
+ super(
1841
+ `native-motion: UI value-channel invariant '${invariant}' was violated` +
1842
+ (operation === undefined ? '' : ` by operation '${operation}'`) +
1843
+ ' (REQ-DRIVER-034)',
1844
+ )
1845
+ this.name = 'UiValueChannelInvariantError'
1846
+ this.invariant = invariant
1847
+ this.operation = operation ?? null
1848
+ }
1849
+ }
1850
+
1851
+ /** Bounded window a runner candidate has to produce its first actual invocation (two frames). */
1852
+ const UI_RUNNER_ADMISSION_WINDOW_MS = 32
1853
+
1854
+ // ——— Canonical cold-relay record store ———
1855
+ // The canonical record is a frozen brand-only handle; its fill state lives in this coordinator-
1856
+ // private store so the frozen record can be observed before and after its single command-edge
1857
+ // fill without ever being mutated itself.
1858
+
1859
+ interface UiColdRelayCanonicalRecordEntry {
1860
+ readonly recordId: number
1861
+ readonly authority: UiColdRelayCommandAuthority
1862
+ fillState: 'EMPTY' | 'FILLED_FROM_LIVE_RECORDS'
1863
+ sourceRecords: UiColdRelaySourceRecords | null
1864
+ deliverySlots: UiColdRelayDeliverySlots | null
1865
+ }
1866
+
1867
+ const uiColdRelayCanonicalRecordIds = new WeakMap<UiColdRelayCanonicalRecord, number>()
1868
+ const uiColdRelayCanonicalRecordEntries = new Map<number, UiColdRelayCanonicalRecordEntry>()
1869
+ let nextUiColdRelayCanonicalRecordId = 1
1870
+
1871
+ function requireCanonicalRecordEntry(
1872
+ record: UiColdRelayCanonicalRecord,
1873
+ operation: UiValueChannelOperation,
1874
+ ): UiColdRelayCanonicalRecordEntry {
1875
+ const recordId = uiColdRelayCanonicalRecordIds.get(record)
1876
+ const entry = recordId === undefined ? undefined : uiColdRelayCanonicalRecordEntries.get(recordId)
1877
+ if (recordId === undefined || entry === undefined) {
1878
+ throw new UiValueChannelInvariantError('cold-relay-canonical-record-unknown', operation)
1879
+ }
1880
+ return entry
1881
+ }
1882
+
1883
+ function allocateCanonicalRecord(
1884
+ authority: UiColdRelayCommandAuthority,
1885
+ ): UiColdRelayCanonicalRecord {
1886
+ const record = Object.freeze({}) as UiColdRelayCanonicalRecord
1887
+ const recordId = nextUiColdRelayCanonicalRecordId
1888
+ nextUiColdRelayCanonicalRecordId += 1
1889
+ uiColdRelayCanonicalRecordIds.set(record, recordId)
1890
+ uiColdRelayCanonicalRecordEntries.set(recordId, {
1891
+ recordId,
1892
+ authority,
1893
+ fillState: 'EMPTY',
1894
+ sourceRecords: null,
1895
+ deliverySlots: null,
1896
+ })
1897
+ return record
1898
+ }
1899
+
1900
+ export function observeUiColdRelayCanonicalRecord(
1901
+ record: UiColdRelayCanonicalRecord,
1902
+ ): UiColdRelayCanonicalRecordObservation {
1903
+ const entry = requireCanonicalRecordEntry(record, 'observe-cold-relay-canonical-record')
1904
+ if (entry.fillState === 'EMPTY') {
1905
+ return Object.freeze({
1906
+ recordId: entry.recordId,
1907
+ authority: entry.authority,
1908
+ fillState: 'EMPTY',
1909
+ sourceRecords: null,
1910
+ deliverySlots: null,
1911
+ }) as UiColdRelayCanonicalRecordObservation
1912
+ }
1913
+ const sourceRecords = entry.sourceRecords
1914
+ const deliverySlots = entry.deliverySlots
1915
+ if (sourceRecords === null || deliverySlots === null) {
1916
+ throw new UiValueChannelInvariantError(
1917
+ 'cold-relay-canonical-record-unknown',
1918
+ 'observe-cold-relay-canonical-record',
1919
+ )
1920
+ }
1921
+ return Object.freeze({
1922
+ recordId: entry.recordId,
1923
+ authority: entry.authority,
1924
+ fillState: 'FILLED_FROM_LIVE_RECORDS',
1925
+ sourceRecords,
1926
+ deliverySlots,
1927
+ }) as UiColdRelayCanonicalRecordObservation
1928
+ }
1929
+
1930
+ // ——— Cold-relay command production from canonical coordinator records ———
1931
+
1932
+ function requireMailboxRecord(
1933
+ state: UiValueChannelCoordinatorState,
1934
+ mailboxDrainId: number,
1935
+ ): UiMailboxTurnRecord {
1936
+ const record = state.mailboxTurns.find((candidate) => candidate.mailboxDrainId === mailboxDrainId)
1937
+ if (record === undefined) {
1938
+ throw new UiValueChannelInvariantError(
1939
+ 'cold-relay-mailbox-record-missing',
1940
+ 'produce-cold-relay-command-from-canonical-state',
1941
+ )
1942
+ }
1943
+ return record
1944
+ }
1945
+
1946
+ function requireHostSinkRecords(
1947
+ state: UiValueChannelCoordinatorState,
1948
+ hostSinkRecordIds: readonly number[],
1949
+ ): readonly [UiHostSinkRecord] {
1950
+ const records = hostSinkRecordIds.map((hostSinkRecordId) => {
1951
+ const record = state.hostSinks.find(
1952
+ (candidate) => candidate.hostSinkRecordId === hostSinkRecordId,
1953
+ )
1954
+ if (record === undefined) {
1955
+ throw new UiValueChannelInvariantError(
1956
+ 'cold-relay-host-sink-missing',
1957
+ 'produce-cold-relay-command-from-canonical-state',
1958
+ )
1959
+ }
1960
+ return record
1961
+ })
1962
+ const first = records[0]
1963
+ if (first === undefined || records.length !== 1) {
1964
+ throw new UiValueChannelInvariantError(
1965
+ 'cold-relay-host-sink-missing',
1966
+ 'produce-cold-relay-command-from-canonical-state',
1967
+ )
1968
+ }
1969
+ return [first]
1970
+ }
1971
+
1972
+ /** The relay target is the one registered callback that has not yet been admitted to a frame. */
1973
+ function requireColdTargetCallback(
1974
+ state: UiValueChannelCoordinatorState,
1975
+ ): UiCallbackRegistrationState {
1976
+ const target = state.callbacks.find(
1977
+ (candidate) =>
1978
+ candidate.state === 'REGISTERED_INACTIVE' ||
1979
+ candidate.state === 'ACTIVATION_REQUESTED' ||
1980
+ candidate.state === 'RUNNER_CANDIDATE',
1981
+ )
1982
+ if (target === undefined) {
1983
+ throw new UiValueChannelInvariantError(
1984
+ 'cold-relay-target-callback-missing',
1985
+ 'produce-cold-relay-command-from-canonical-state',
1986
+ )
1987
+ }
1988
+ return target
1989
+ }
1990
+
1991
+ function missingColdRelaySourceRecord(): never {
1992
+ throw new UiValueChannelInvariantError(
1993
+ 'cold-relay-source-record-missing',
1994
+ 'produce-cold-relay-command-from-canonical-state',
1995
+ )
1996
+ }
1997
+
1998
+ export function produceUiColdRelayCommandFromCanonicalState(
1999
+ state: UiValueChannelCoordinatorState,
2000
+ request: UiColdRelayCommandProductionRequest,
2001
+ ): UiColdRelayCommandProductionTransition {
2002
+ switch (request.kind) {
2003
+ case 'START_PUBLIC_IDENTITY_EXECUTION': {
2004
+ const primaryRecord = state.generatorExecutions.find(
2005
+ (
2006
+ candidate,
2007
+ ): candidate is Extract<
2008
+ UiGeneratorExecutionRecord,
2009
+ { readonly workClass: 'channel-ordinary-first-sample' }
2010
+ > =>
2011
+ candidate.workClass === 'channel-ordinary-first-sample' &&
2012
+ candidate.owner.kind === 'PUBLIC_IDENTITY' &&
2013
+ candidate.owner.channelId === request.channelId &&
2014
+ candidate.entry.executionId === request.executionId,
2015
+ )
2016
+ if (primaryRecord === undefined) return missingColdRelaySourceRecord()
2017
+ const commandAuthority: UiColdRelayCommandAuthority = {
2018
+ workClass: 'channel-ordinary-first-sample',
2019
+ destinationRecordId: request.destinationRecordId,
2020
+ owner: { kind: 'PUBLIC_IDENTITY', channelId: request.channelId },
2021
+ executionId: request.executionId,
2022
+ }
2023
+ const sourceRecords = Object.freeze({
2024
+ [uiColdRelaySourceRecordsBrand]: true as const,
2025
+ workClass: 'channel-ordinary-first-sample' as const,
2026
+ primaryRecord,
2027
+ callbackRegistrations: [requireColdTargetCallback(state)] as const,
2028
+ mailboxRecord: requireMailboxRecord(state, primaryRecord.mailboxDrainId),
2029
+ hostSinkRecords: requireHostSinkRecords(state, primaryRecord.hostSinkRecordIds),
2030
+ })
2031
+ return {
2032
+ [uiColdRelayProducerReceiptBrand]: true,
2033
+ state,
2034
+ commandAuthority,
2035
+ sourceRecords,
2036
+ }
2037
+ }
2038
+ case 'START_PRIVATE_CONTROL_EXECUTION': {
2039
+ const primaryRecord = state.generatorExecutions.find(
2040
+ (
2041
+ candidate,
2042
+ ): candidate is Extract<
2043
+ UiGeneratorExecutionRecord,
2044
+ { readonly workClass: 'private-ordinary-first-sample' }
2045
+ > =>
2046
+ candidate.workClass === 'private-ordinary-first-sample' &&
2047
+ candidate.owner.kind === 'PRIVATE_CONTROL' &&
2048
+ candidate.owner.controlId === request.controlId &&
2049
+ candidate.entry.executionId === request.executionId,
2050
+ )
2051
+ if (primaryRecord === undefined) return missingColdRelaySourceRecord()
2052
+ const commandAuthority: UiColdRelayCommandAuthority = {
2053
+ workClass: 'private-ordinary-first-sample',
2054
+ destinationRecordId: request.destinationRecordId,
2055
+ owner: { kind: 'PRIVATE_CONTROL', controlId: request.controlId },
2056
+ executionId: request.executionId,
2057
+ }
2058
+ const sourceRecords = Object.freeze({
2059
+ [uiColdRelaySourceRecordsBrand]: true as const,
2060
+ workClass: 'private-ordinary-first-sample' as const,
2061
+ primaryRecord,
2062
+ callbackRegistrations: [] as const,
2063
+ mailboxRecord: requireMailboxRecord(state, primaryRecord.mailboxDrainId),
2064
+ hostSinkRecords: requireHostSinkRecords(state, primaryRecord.hostSinkRecordIds),
2065
+ })
2066
+ return {
2067
+ [uiColdRelayProducerReceiptBrand]: true,
2068
+ state,
2069
+ commandAuthority,
2070
+ sourceRecords,
2071
+ }
2072
+ }
2073
+ case 'QUEUE_INSTANT_TARGET': {
2074
+ const primaryRecord = state.dueWorkTasks.find(
2075
+ (
2076
+ candidate,
2077
+ ): candidate is Extract<UiDueWorkTaskRecord, { readonly workClass: 'instant-target' }> =>
2078
+ candidate.workClass === 'instant-target' &&
2079
+ candidate.entry.taskId === request.taskId &&
2080
+ candidate.entry.taskSequence === request.taskSequence,
2081
+ )
2082
+ if (primaryRecord === undefined) return missingColdRelaySourceRecord()
2083
+ const commandAuthority: UiColdRelayCommandAuthority = {
2084
+ workClass: 'instant-target',
2085
+ destinationRecordId: request.destinationRecordId,
2086
+ taskId: request.taskId,
2087
+ taskSequence: request.taskSequence,
2088
+ }
2089
+ const sourceRecords = Object.freeze({
2090
+ [uiColdRelaySourceRecordsBrand]: true as const,
2091
+ workClass: 'instant-target' as const,
2092
+ primaryRecord,
2093
+ callbackRegistrations: [requireColdTargetCallback(state)] as const,
2094
+ mailboxRecord: requireMailboxRecord(state, primaryRecord.mailboxDrainId),
2095
+ hostSinkRecords: requireHostSinkRecords(state, primaryRecord.hostSinkRecordIds),
2096
+ })
2097
+ return {
2098
+ [uiColdRelayProducerReceiptBrand]: true,
2099
+ state,
2100
+ commandAuthority,
2101
+ sourceRecords,
2102
+ }
2103
+ }
2104
+ case 'QUEUE_EQUAL_TARGET_REASSERTION': {
2105
+ const primaryRecord = state.dueWorkTasks.find(
2106
+ (
2107
+ candidate,
2108
+ ): candidate is Extract<
2109
+ UiDueWorkTaskRecord,
2110
+ { readonly workClass: 'equal-target-reassertion' }
2111
+ > =>
2112
+ candidate.workClass === 'equal-target-reassertion' &&
2113
+ candidate.entry.taskId === request.taskId &&
2114
+ candidate.entry.taskSequence === request.taskSequence,
2115
+ )
2116
+ if (primaryRecord === undefined) return missingColdRelaySourceRecord()
2117
+ const commandAuthority: UiColdRelayCommandAuthority = {
2118
+ workClass: 'equal-target-reassertion',
2119
+ destinationRecordId: request.destinationRecordId,
2120
+ taskId: request.taskId,
2121
+ taskSequence: request.taskSequence,
2122
+ }
2123
+ const sourceRecords = Object.freeze({
2124
+ [uiColdRelaySourceRecordsBrand]: true as const,
2125
+ workClass: 'equal-target-reassertion' as const,
2126
+ primaryRecord,
2127
+ callbackRegistrations: [requireColdTargetCallback(state)] as const,
2128
+ mailboxRecord: requireMailboxRecord(state, primaryRecord.mailboxDrainId),
2129
+ hostSinkRecords: requireHostSinkRecords(state, primaryRecord.hostSinkRecordIds),
2130
+ })
2131
+ return {
2132
+ [uiColdRelayProducerReceiptBrand]: true,
2133
+ state,
2134
+ commandAuthority,
2135
+ sourceRecords,
2136
+ }
2137
+ }
2138
+ case 'QUEUE_IDLE_WRITE': {
2139
+ const primaryRecord = state.dueWorkTasks.find(
2140
+ (
2141
+ candidate,
2142
+ ): candidate is Extract<UiDueWorkTaskRecord, { readonly workClass: 'idle-write' }> =>
2143
+ candidate.workClass === 'idle-write' &&
2144
+ candidate.entry.taskId === request.taskId &&
2145
+ candidate.entry.taskSequence === request.taskSequence,
2146
+ )
2147
+ if (primaryRecord === undefined) return missingColdRelaySourceRecord()
2148
+ const commandAuthority: UiColdRelayCommandAuthority = {
2149
+ workClass: 'idle-write',
2150
+ destinationRecordId: request.destinationRecordId,
2151
+ taskId: request.taskId,
2152
+ taskSequence: request.taskSequence,
2153
+ }
2154
+ const sourceRecords = Object.freeze({
2155
+ [uiColdRelaySourceRecordsBrand]: true as const,
2156
+ workClass: 'idle-write' as const,
2157
+ primaryRecord,
2158
+ callbackRegistrations: [] as const,
2159
+ mailboxRecord: requireMailboxRecord(state, primaryRecord.mailboxDrainId),
2160
+ hostSinkRecords: requireHostSinkRecords(state, primaryRecord.hostSinkRecordIds),
2161
+ })
2162
+ return {
2163
+ [uiColdRelayProducerReceiptBrand]: true,
2164
+ state,
2165
+ commandAuthority,
2166
+ sourceRecords,
2167
+ }
2168
+ }
2169
+ case 'ARM_INSTANT_COMPLETION': {
2170
+ const primaryRecord = state.valueCompletionControllers.find(
2171
+ (candidate) =>
2172
+ candidate.completionControllerId === request.completionControllerId &&
2173
+ candidate.entry.completionSequence === request.completionSequence,
2174
+ )
2175
+ if (primaryRecord === undefined) return missingColdRelaySourceRecord()
2176
+ const commandAuthority: UiColdRelayCommandAuthority = {
2177
+ workClass: 'instant-completion',
2178
+ destinationRecordId: request.destinationRecordId,
2179
+ completionSequence: request.completionSequence,
2180
+ completionControllerId: request.completionControllerId,
2181
+ }
2182
+ const sourceRecords = Object.freeze({
2183
+ [uiColdRelaySourceRecordsBrand]: true as const,
2184
+ workClass: 'instant-completion' as const,
2185
+ primaryRecord,
2186
+ callbackRegistrations: [requireColdTargetCallback(state)] as const,
2187
+ mailboxRecord: requireMailboxRecord(state, primaryRecord.mailboxDrainId),
2188
+ hostSinkRecords: [] as const,
2189
+ })
2190
+ return {
2191
+ [uiColdRelayProducerReceiptBrand]: true,
2192
+ state,
2193
+ commandAuthority,
2194
+ sourceRecords,
2195
+ }
2196
+ }
2197
+ case 'APPLY_DIRECT_WRITE': {
2198
+ const primaryRecord = state.directOperations.find(
2199
+ (candidate) =>
2200
+ candidate.directOperationId === request.directOperationId &&
2201
+ candidate.directOperationEpoch === request.directOperationEpoch,
2202
+ )
2203
+ if (primaryRecord === undefined) return missingColdRelaySourceRecord()
2204
+ const commandAuthority: UiColdRelayCommandAuthority = {
2205
+ workClass: 'direct-write',
2206
+ destinationRecordId: request.destinationRecordId,
2207
+ directOperationId: request.directOperationId,
2208
+ directOperationEpoch: request.directOperationEpoch,
2209
+ }
2210
+ const sourceRecords = Object.freeze({
2211
+ [uiColdRelaySourceRecordsBrand]: true as const,
2212
+ workClass: 'direct-write' as const,
2213
+ primaryRecord,
2214
+ callbackRegistrations: [] as const,
2215
+ mailboxRecord: requireMailboxRecord(state, primaryRecord.mailboxDrainId),
2216
+ hostSinkRecords: requireHostSinkRecords(state, primaryRecord.hostSinkRecordIds),
2217
+ })
2218
+ return {
2219
+ [uiColdRelayProducerReceiptBrand]: true,
2220
+ state,
2221
+ commandAuthority,
2222
+ sourceRecords,
2223
+ }
2224
+ }
2225
+ case 'QUEUE_TRANSITION_END_CARRIER': {
2226
+ const primaryRecord = state.carrierControllers.find(
2227
+ (
2228
+ candidate,
2229
+ ): candidate is Extract<
2230
+ UiCarrierControllerRecord,
2231
+ { readonly workClass: 'transition-end-carrier' }
2232
+ > =>
2233
+ candidate.workClass === 'transition-end-carrier' &&
2234
+ candidate.carrierControllerId === request.carrierControllerId &&
2235
+ candidate.entry.taskId === request.taskId,
2236
+ )
2237
+ if (primaryRecord === undefined) return missingColdRelaySourceRecord()
2238
+ const commandAuthority: UiColdRelayCommandAuthority = {
2239
+ workClass: 'transition-end-carrier',
2240
+ destinationRecordId: request.destinationRecordId,
2241
+ carrierControllerId: request.carrierControllerId,
2242
+ taskId: request.taskId,
2243
+ }
2244
+ const sourceRecords = Object.freeze({
2245
+ [uiColdRelaySourceRecordsBrand]: true as const,
2246
+ workClass: 'transition-end-carrier' as const,
2247
+ primaryRecord,
2248
+ callbackRegistrations: [] as const,
2249
+ mailboxRecord: requireMailboxRecord(state, primaryRecord.mailboxDrainId),
2250
+ hostSinkRecords: requireHostSinkRecords(state, primaryRecord.hostSinkRecordIds),
2251
+ })
2252
+ return {
2253
+ [uiColdRelayProducerReceiptBrand]: true,
2254
+ state,
2255
+ commandAuthority,
2256
+ sourceRecords,
2257
+ }
2258
+ }
2259
+ case 'QUEUE_EXIT_CARRIER': {
2260
+ const primaryRecord = state.carrierControllers.find(
2261
+ (
2262
+ candidate,
2263
+ ): candidate is Extract<
2264
+ UiCarrierControllerRecord,
2265
+ { readonly workClass: 'exit-carrier' }
2266
+ > =>
2267
+ candidate.workClass === 'exit-carrier' &&
2268
+ candidate.carrierControllerId === request.carrierControllerId &&
2269
+ candidate.entry.taskId === request.taskId,
2270
+ )
2271
+ if (primaryRecord === undefined) return missingColdRelaySourceRecord()
2272
+ const commandAuthority: UiColdRelayCommandAuthority = {
2273
+ workClass: 'exit-carrier',
2274
+ destinationRecordId: request.destinationRecordId,
2275
+ carrierControllerId: request.carrierControllerId,
2276
+ taskId: request.taskId,
2277
+ }
2278
+ const sourceRecords = Object.freeze({
2279
+ [uiColdRelaySourceRecordsBrand]: true as const,
2280
+ workClass: 'exit-carrier' as const,
2281
+ primaryRecord,
2282
+ callbackRegistrations: [] as const,
2283
+ mailboxRecord: requireMailboxRecord(state, primaryRecord.mailboxDrainId),
2284
+ hostSinkRecords: requireHostSinkRecords(state, primaryRecord.hostSinkRecordIds),
2285
+ })
2286
+ return {
2287
+ [uiColdRelayProducerReceiptBrand]: true,
2288
+ state,
2289
+ commandAuthority,
2290
+ sourceRecords,
2291
+ }
2292
+ }
2293
+ case 'QUEUE_PACKET_B_CARRIER': {
2294
+ const primaryRecord = state.carrierControllers.find(
2295
+ (
2296
+ candidate,
2297
+ ): candidate is Extract<
2298
+ UiCarrierControllerRecord,
2299
+ { readonly workClass: 'packet-b-carrier' }
2300
+ > =>
2301
+ candidate.workClass === 'packet-b-carrier' &&
2302
+ candidate.carrierControllerId === request.carrierControllerId &&
2303
+ candidate.entry.taskId === request.taskId,
2304
+ )
2305
+ if (primaryRecord === undefined) return missingColdRelaySourceRecord()
2306
+ const commandAuthority: UiColdRelayCommandAuthority = {
2307
+ workClass: 'packet-b-carrier',
2308
+ destinationRecordId: request.destinationRecordId,
2309
+ carrierControllerId: request.carrierControllerId,
2310
+ taskId: request.taskId,
2311
+ }
2312
+ const sourceRecords = Object.freeze({
2313
+ [uiColdRelaySourceRecordsBrand]: true as const,
2314
+ workClass: 'packet-b-carrier' as const,
2315
+ primaryRecord,
2316
+ callbackRegistrations: [] as const,
2317
+ mailboxRecord: requireMailboxRecord(state, primaryRecord.mailboxDrainId),
2318
+ hostSinkRecords: requireHostSinkRecords(state, primaryRecord.hostSinkRecordIds),
2319
+ })
2320
+ return {
2321
+ [uiColdRelayProducerReceiptBrand]: true,
2322
+ state,
2323
+ commandAuthority,
2324
+ sourceRecords,
2325
+ }
2326
+ }
2327
+ default: {
2328
+ const exhaustive: never = request
2329
+ void exhaustive
2330
+ throw new UiValueChannelInvariantError('cold-relay-command-kind-unrecognized')
2331
+ }
2332
+ }
2333
+ }
2334
+
2335
+ // ——— Shared UI destination COMMIT canonical validator ———
2336
+
2337
+ export function validateUiDestinationCommitWithCanonicalAuthority(
2338
+ request: UiDestinationCommitCanonicalValidationRequest,
2339
+ ): UiDestinationCommitCanonicalValidationOutcome {
2340
+ const { commit, preparedDestinationRecords } = request
2341
+ // The runtime keys prepared records by its own destination record id; a commit naming an
2342
+ // unknown destination id for a known channel still resolves the channel's authority so the
2343
+ // exact mismatched tuple field is diagnosed instead of a bare missing record.
2344
+ const record =
2345
+ preparedDestinationRecords.find(
2346
+ (candidate) => candidate.destinationRecordId === commit.destinationRecordId,
2347
+ ) ?? preparedDestinationRecords.find((candidate) => candidate.channelId === commit.channelId)
2348
+ if (record === undefined) {
2349
+ return { kind: 'REFUSED', authority: null, reason: 'missing-prepared-destination-record' }
2350
+ }
2351
+ const reason = validateUiCommitAgainstPreparedRecord(record, commit)
2352
+ if (reason !== null) {
2353
+ return { kind: 'REFUSED', authority: record, reason }
2354
+ }
2355
+ return { kind: 'VALID', authority: record }
2356
+ }
2357
+
2358
+ function validateUiCommitAgainstPreparedRecord(
2359
+ record: UiPreparedDestinationRecordState,
2360
+ commit: ImmutableDestinationCommit,
2361
+ ): UiDestinationCommitCanonicalRefusalReason | null {
2362
+ if (commit.channelId !== record.channelId) return 'wrong-channel'
2363
+ if (commit.sourceRecordId !== record.sourceRecordId) return 'wrong-source-record'
2364
+ if (commit.destinationRecordId !== record.destinationRecordId) return 'wrong-destination-record'
2365
+ // The UI destination root only ever consumes JS→UI commits; a self-consistent UI→JS authority
2366
+ // is as refused here as a tuple mismatch.
2367
+ if (commit.direction !== record.direction || commit.direction !== 'JS_TO_UI') {
2368
+ return 'wrong-direction'
2369
+ }
2370
+ if (commit.transferLease !== record.transferLease) return 'wrong-transfer-lease'
2371
+ if (commit.releaseFenceSequence !== record.releaseFenceSequence) return 'wrong-release-fence'
2372
+ if (
2373
+ commit.includedPostFencePrefix.some(
2374
+ (entry) => entry.authoritativeSequence > commit.sentThroughAuthoritativeSequence,
2375
+ )
2376
+ ) {
2377
+ return 'ahead-of-sent-watermark'
2378
+ }
2379
+ if (commit.sentThroughAuthoritativeSequence < record.appliedThroughAuthoritativeSequence) {
2380
+ return 'sent-watermark-regressed'
2381
+ }
2382
+ const newEntries = commit.includedPostFencePrefix.filter(
2383
+ (entry) => entry.authoritativeSequence > record.appliedThroughAuthoritativeSequence,
2384
+ )
2385
+ for (let index = 0; index < newEntries.length; index += 1) {
2386
+ const entry = newEntries[index]
2387
+ if (entry === undefined) break
2388
+ if (entry.authoritativeSequence !== record.appliedThroughAuthoritativeSequence + index + 1) {
2389
+ return 'prefix-not-contiguous'
2390
+ }
2391
+ }
2392
+ return null
2393
+ }
2394
+
2395
+ export const uiDestinationCommitCanonicalValidator: UiDestinationCommitCanonicalValidatorCapability =
2396
+ Object.freeze({
2397
+ [uiDestinationCommitCanonicalValidatorCapabilityBrand]: true as const,
2398
+ validate: validateUiDestinationCommitWithCanonicalAuthority,
2399
+ })
2400
+
2401
+ // ——— Destination ledger application (in-place at the commit consumption edge) ———
2402
+
2403
+ function createUiLedgerSlot(
2404
+ entry: NormalizedRetainedWorkEntry,
2405
+ ): ValueHandoffDestinationLedgerState['slots'][number] {
2406
+ return {
2407
+ ...entry.destinationSlot,
2408
+ entries: [entry],
2409
+ } as ValueHandoffDestinationLedgerState['slots'][number]
2410
+ }
2411
+
2412
+ function appendUiLedgerEntry(
2413
+ slot: ValueHandoffDestinationLedgerState['slots'][number],
2414
+ entry: NormalizedRetainedWorkEntry,
2415
+ ): ValueHandoffDestinationLedgerState['slots'][number] {
2416
+ if (slot.ledger !== entry.destinationSlot.ledger) return slot
2417
+ return {
2418
+ ...slot,
2419
+ entries: [...slot.entries, entry],
2420
+ } as ValueHandoffDestinationLedgerState['slots'][number]
2421
+ }
2422
+
2423
+ function applyEntriesToUiLedgers(
2424
+ ledgers: ValueHandoffDestinationLedgerState,
2425
+ entries: readonly NormalizedRetainedWorkEntry[],
2426
+ ): ValueHandoffDestinationLedgerState {
2427
+ let slots = ledgers.slots
2428
+ for (const entry of entries) {
2429
+ const index = slots.findIndex(
2430
+ (slot) =>
2431
+ slot.ledger === entry.destinationSlot.ledger &&
2432
+ slot.slotId === entry.destinationSlot.slotId,
2433
+ )
2434
+ if (index < 0) {
2435
+ slots = [...slots, createUiLedgerSlot(entry)]
2436
+ continue
2437
+ }
2438
+ const slot = slots[index]
2439
+ if (slot === undefined) continue
2440
+ slots = [...slots.slice(0, index), appendUiLedgerEntry(slot, entry), ...slots.slice(index + 1)]
2441
+ }
2442
+ return { slots }
2443
+ }
2444
+
2445
+ // ——— Coordinator transition helpers ———
2446
+
2447
+ function uiTransition(
2448
+ state: UiValueChannelCoordinatorState,
2449
+ orderedEffects: readonly UiValueChannelEffect[],
2450
+ refusal: UiManualFrameRefusal | null = null,
2451
+ ): UiValueChannelTransition {
2452
+ return { state, observation: observeUiValueChannel(state), orderedEffects, refusal }
2453
+ }
2454
+
2455
+ function requireCallback(
2456
+ state: UiValueChannelCoordinatorState,
2457
+ driverId: number,
2458
+ operation: UiValueChannelOperation,
2459
+ ): UiCallbackRegistrationState {
2460
+ const callback = state.callbacks.find((candidate) => candidate.driverId === driverId)
2461
+ if (callback === undefined) {
2462
+ throw new UiValueChannelInvariantError('callback-registration-missing', operation)
2463
+ }
2464
+ return callback
2465
+ }
2466
+
2467
+ function replaceCallback(
2468
+ state: UiValueChannelCoordinatorState,
2469
+ replacement: UiCallbackRegistrationState,
2470
+ ): UiValueChannelCoordinatorState {
2471
+ return {
2472
+ ...state,
2473
+ callbacks: state.callbacks.map((candidate) =>
2474
+ candidate.driverId === replacement.driverId ? replacement : candidate,
2475
+ ),
2476
+ }
2477
+ }
2478
+
2479
+ function requireManualGroup(
2480
+ state: UiValueChannelCoordinatorState,
2481
+ groupId: number,
2482
+ operation: UiValueChannelOperation,
2483
+ ): ManualFrameGroupState {
2484
+ const group = state.manualGroups.find((candidate) => candidate.groupId === groupId)
2485
+ if (group === undefined) {
2486
+ throw new UiValueChannelInvariantError('manual-frame-group-missing', operation)
2487
+ }
2488
+ return group
2489
+ }
2490
+
2491
+ function replaceManualGroup(
2492
+ state: UiValueChannelCoordinatorState,
2493
+ replacement: ManualFrameGroupState,
2494
+ ): UiValueChannelCoordinatorState {
2495
+ return {
2496
+ ...state,
2497
+ manualGroups: state.manualGroups.map((candidate) =>
2498
+ candidate.groupId === replacement.groupId ? replacement : candidate,
2499
+ ),
2500
+ }
2501
+ }
2502
+
2503
+ // ——— Frame transaction stepping ———
2504
+
2505
+ function stepIdentitiesOnce(
2506
+ state: UiValueChannelCoordinatorState,
2507
+ absoluteTimestampMs: number,
2508
+ effects: UiValueChannelEffect[],
2509
+ ): UiValueChannelCoordinatorState {
2510
+ const steppedChannelIds: number[] = []
2511
+ const identities = state.identities.map((identity) => {
2512
+ steppedChannelIds.push(identity.channelId)
2513
+ const deltaMs =
2514
+ identity.lastAbsoluteTimestampMs === null
2515
+ ? 0
2516
+ : absoluteTimestampMs - identity.lastAbsoluteTimestampMs
2517
+ effects.push({
2518
+ kind: 'step-shared-identity-once',
2519
+ channelId: identity.channelId,
2520
+ absoluteTimestampMs,
2521
+ deltaMs,
2522
+ })
2523
+ return {
2524
+ ...identity,
2525
+ lastAbsoluteTimestampMs: absoluteTimestampMs,
2526
+ stepCount: identity.stepCount + 1,
2527
+ }
2528
+ })
2529
+ const transaction = state.transaction
2530
+ if (transaction.kind !== 'OPEN') {
2531
+ throw new UiValueChannelInvariantError('frame-transaction-conflict', 'invoke-live-callback')
2532
+ }
2533
+ return {
2534
+ ...state,
2535
+ identities,
2536
+ transaction: { ...transaction, steppedChannelIds },
2537
+ }
2538
+ }
2539
+
2540
+ function recordFrameAttendance(
2541
+ state: UiValueChannelCoordinatorState,
2542
+ driverId: number,
2543
+ effects: UiValueChannelEffect[],
2544
+ ): UiValueChannelCoordinatorState {
2545
+ const transaction = state.transaction
2546
+ if (transaction.kind !== 'OPEN') {
2547
+ throw new UiValueChannelInvariantError('frame-transaction-conflict', 'invoke-live-callback')
2548
+ }
2549
+ effects.push({ kind: 'record-attendance', driverId })
2550
+ let next: UiValueChannelCoordinatorState = {
2551
+ ...state,
2552
+ transaction: {
2553
+ ...transaction,
2554
+ visitedAttendeeDriverIds: [...transaction.visitedAttendeeDriverIds, driverId],
2555
+ },
2556
+ callbacks: state.callbacks.map((candidate) =>
2557
+ candidate.driverId === driverId
2558
+ ? { ...candidate, lastInvocationTimestampMs: transaction.absoluteTimestampMs }
2559
+ : candidate,
2560
+ ),
2561
+ }
2562
+ if (transaction.steppedChannelIds.length === 0) {
2563
+ next = stepIdentitiesOnce(next, transaction.absoluteTimestampMs, effects)
2564
+ }
2565
+ return next
2566
+ }
2567
+
2568
+ function commitFrameIfAttendanceComplete(
2569
+ state: UiValueChannelCoordinatorState,
2570
+ effects: UiValueChannelEffect[],
2571
+ ): UiValueChannelCoordinatorState {
2572
+ const transaction = state.transaction
2573
+ if (transaction.kind !== 'OPEN') return state
2574
+ const complete = transaction.expectedAttendeeDriverIds.every(
2575
+ (driverId) =>
2576
+ transaction.visitedAttendeeDriverIds.includes(driverId) ||
2577
+ transaction.revokedAttendeeDriverIds.includes(driverId),
2578
+ )
2579
+ if (!complete) return state
2580
+ effects.push({
2581
+ kind: 'commit-frame-once',
2582
+ absoluteTimestampMs: transaction.absoluteTimestampMs,
2583
+ })
2584
+ return {
2585
+ ...state,
2586
+ identities: state.identities.map((identity) => ({
2587
+ ...identity,
2588
+ hostCommitCount: identity.hostCommitCount + 1,
2589
+ })),
2590
+ transaction: {
2591
+ kind: 'CLOSED',
2592
+ lastCommittedTimestampMs: transaction.absoluteTimestampMs,
2593
+ committedFrameCount: transaction.committedFrameCount + 1,
2594
+ },
2595
+ }
2596
+ }
2597
+
2598
+ // ——— Cold-work relay stepping ———
2599
+
2600
+ function freezeSlotArrayInPlace<Slot>(slots: readonly Slot[]): readonly Slot[] {
2601
+ return Object.freeze(slots)
2602
+ }
2603
+
2604
+ function buildDeliverySlots(sourceRecords: UiColdRelaySourceRecords): UiColdRelayDeliverySlots {
2605
+ const envelope = sourceRecords.mailboxRecord.envelope
2606
+ const hostSlots = Object.freeze(
2607
+ sourceRecords.hostSinkRecords.map((record) => record.slot),
2608
+ ) as readonly [UiColdRelayHostCommitResultSlot]
2609
+ switch (sourceRecords.workClass) {
2610
+ case 'channel-ordinary-first-sample':
2611
+ case 'private-ordinary-first-sample': {
2612
+ const primary = sourceRecords.primaryRecord
2613
+ return Object.freeze({
2614
+ workClass: sourceRecords.workClass,
2615
+ envelope,
2616
+ writeSlots: Object.freeze([primary.writeSlot] as const),
2617
+ callbackSlots: freezeSlotArrayInPlace(primary.callbackSlots),
2618
+ carrierSlots: Object.freeze([] as const),
2619
+ hostSlots,
2620
+ }) as UiColdRelayDeliverySlots
2621
+ }
2622
+ case 'instant-target':
2623
+ case 'equal-target-reassertion':
2624
+ case 'idle-write': {
2625
+ const primary = sourceRecords.primaryRecord
2626
+ // The preallocated task callback buffer is compacted in place at this single command-edge
2627
+ // fill: instant/equal deliveries keep only the tokenless transition-on-update slots (the
2628
+ // animation-complete delivery belongs to the value-completion controller), while an idle
2629
+ // direct write delivers no task callbacks at all.
2630
+ const callbackSlots = primary.callbackSlots as Extract<
2631
+ UiColdRelayCallbackResultSlot,
2632
+ { readonly kind: 'TASK_CALLBACK' }
2633
+ >[]
2634
+ let retainedCount = 0
2635
+ if (sourceRecords.workClass !== 'idle-write') {
2636
+ for (const slot of callbackSlots) {
2637
+ if (slot.callback.callbackKind !== 'transition-on-update') continue
2638
+ callbackSlots[retainedCount] = slot
2639
+ retainedCount += 1
2640
+ }
2641
+ }
2642
+ callbackSlots.length = retainedCount
2643
+ return Object.freeze({
2644
+ workClass: sourceRecords.workClass,
2645
+ envelope,
2646
+ writeSlots: Object.freeze([primary.writeSlot] as const),
2647
+ callbackSlots: Object.freeze(callbackSlots),
2648
+ carrierSlots: Object.freeze([] as const),
2649
+ hostSlots,
2650
+ }) as UiColdRelayDeliverySlots
2651
+ }
2652
+ case 'instant-completion': {
2653
+ const primary = sourceRecords.primaryRecord
2654
+ return Object.freeze({
2655
+ workClass: 'instant-completion' as const,
2656
+ envelope,
2657
+ writeSlots: Object.freeze([] as const),
2658
+ callbackSlots: Object.freeze([primary.callbackSlot] as const),
2659
+ carrierSlots: Object.freeze([] as const),
2660
+ hostSlots: Object.freeze([] as const),
2661
+ }) as UiColdRelayDeliverySlots
2662
+ }
2663
+ case 'direct-write': {
2664
+ const primary = sourceRecords.primaryRecord
2665
+ return Object.freeze({
2666
+ workClass: 'direct-write' as const,
2667
+ envelope,
2668
+ writeSlots: Object.freeze([primary.writeSlot] as const),
2669
+ callbackSlots: Object.freeze([] as const),
2670
+ carrierSlots: Object.freeze([] as const),
2671
+ hostSlots,
2672
+ }) as UiColdRelayDeliverySlots
2673
+ }
2674
+ case 'transition-end-carrier':
2675
+ case 'exit-carrier':
2676
+ case 'packet-b-carrier': {
2677
+ const primary = sourceRecords.primaryRecord
2678
+ return Object.freeze({
2679
+ workClass: sourceRecords.workClass,
2680
+ envelope,
2681
+ writeSlots: Object.freeze([] as const),
2682
+ callbackSlots: Object.freeze([] as const),
2683
+ carrierSlots: Object.freeze([primary.carrierSlot] as const),
2684
+ hostSlots,
2685
+ }) as UiColdRelayDeliverySlots
2686
+ }
2687
+ default: {
2688
+ const exhaustive: never = sourceRecords
2689
+ void exhaustive
2690
+ throw new UiValueChannelInvariantError('cold-relay-command-kind-unrecognized')
2691
+ }
2692
+ }
2693
+ }
2694
+
2695
+ interface UiRelayStepResult {
2696
+ readonly state: UiValueChannelCoordinatorState
2697
+ readonly relay: UiColdWorkRelayState
2698
+ }
2699
+
2700
+ /** Fill and apply the canonical record exactly once, forming the value-bearing prefix with it. */
2701
+ function fillAndApplyCanonicalRelayRecord(
2702
+ state: UiValueChannelCoordinatorState,
2703
+ relay: UiColdWorkRelayState,
2704
+ effects: UiValueChannelEffect[],
2705
+ ): UiRelayStepResult {
2706
+ const entry = requireCanonicalRecordEntry(relay.canonicalRecord, 'invoke-live-callback')
2707
+ let nextRelay = relay
2708
+ if (entry.fillState === 'EMPTY') {
2709
+ const sourceRecords = relay.commandReceipt.sourceRecords
2710
+ entry.sourceRecords = sourceRecords
2711
+ entry.deliverySlots = buildDeliverySlots(sourceRecords)
2712
+ entry.fillState = 'FILLED_FROM_LIVE_RECORDS'
2713
+ effects.push({
2714
+ kind: 'fill-canonical-cold-relay-record-from-live-records',
2715
+ relayId: relay.relayId,
2716
+ canonicalRecord: relay.canonicalRecord,
2717
+ sourceRecords,
2718
+ })
2719
+ effects.push({
2720
+ kind: 'apply-canonical-cold-relay-record',
2721
+ relayId: relay.relayId,
2722
+ targetDriverId: relay.targetDriverId,
2723
+ canonicalRecord: relay.canonicalRecord,
2724
+ })
2725
+ const primaryRecord = sourceRecords.primaryRecord
2726
+ if (sourceRecords.workClass === 'channel-ordinary-first-sample') {
2727
+ const valueBearingEntry = (
2728
+ primaryRecord as Extract<
2729
+ UiGeneratorExecutionRecord,
2730
+ { readonly workClass: 'channel-ordinary-first-sample' }
2731
+ >
2732
+ ).valueBearingEntry
2733
+ nextRelay = { ...nextRelay, pendingValueBearingEntry: valueBearingEntry }
2734
+ const mailboxDrainId = state.nextMailboxDrainId
2735
+ const valueWriteEntry = Object.freeze({
2736
+ kind: 'VALUE_WRITE' as const,
2737
+ entryId: valueBearingEntry.valueWriteEntryId,
2738
+ index: 0,
2739
+ channelId: valueBearingEntry.channelId,
2740
+ sample: Object.freeze({
2741
+ kind: 'generator-sample' as const,
2742
+ origin: 'ui-frame' as const,
2743
+ channelId: valueBearingEntry.channelId,
2744
+ authoritativeSequence: valueBearingEntry.authoritativeSequence,
2745
+ executionId: valueBearingEntry.executionId,
2746
+ directOperationEpoch: valueBearingEntry.directOperationEpoch,
2747
+ executionLease: valueBearingEntry.executionLease,
2748
+ writeSequence: valueBearingEntry.writeSequence,
2749
+ history: valueBearingEntry.candidateHistory,
2750
+ completion: valueBearingEntry.completion,
2751
+ }),
2752
+ })
2753
+ const transitionCallbackEntry = Object.freeze({
2754
+ kind: 'TRANSITION_CALLBACK' as const,
2755
+ entryId: valueBearingEntry.transitionCallbackEntryId,
2756
+ index: 1,
2757
+ channelId: valueBearingEntry.channelId,
2758
+ callbackId: valueBearingEntry.transitionCallbackId,
2759
+ event: Object.freeze({
2760
+ kind: 'transition-on-update' as const,
2761
+ channelId: valueBearingEntry.channelId,
2762
+ executionId: valueBearingEntry.executionId,
2763
+ directOperationEpoch: valueBearingEntry.directOperationEpoch,
2764
+ executionLease: valueBearingEntry.executionLease,
2765
+ writeSequence: valueBearingEntry.writeSequence,
2766
+ eventSequence: valueBearingEntry.eventSequence,
2767
+ history: valueBearingEntry.candidateHistory,
2768
+ }),
2769
+ })
2770
+ const openTurn = Object.freeze({
2771
+ mailboxOrigin: 'UI' as const,
2772
+ mailboxDrainId,
2773
+ stagedEntries: Object.freeze([valueWriteEntry, transitionCallbackEntry] as const),
2774
+ sealed: false as const,
2775
+ })
2776
+ effects.push({
2777
+ kind: 'form-cold-work-relay-value-bearing-mailbox-prefix',
2778
+ relayId: relay.relayId,
2779
+ canonicalRecord: relay.canonicalRecord,
2780
+ sourceEntry: valueBearingEntry,
2781
+ openTurn,
2782
+ })
2783
+ nextRelay = {
2784
+ ...nextRelay,
2785
+ pendingValueBearingEntry: null,
2786
+ stagedValueBearingPrefix: {
2787
+ mailboxDrainId,
2788
+ valueWriteEntryId: valueBearingEntry.valueWriteEntryId,
2789
+ transitionCallbackEntryId: valueBearingEntry.transitionCallbackEntryId,
2790
+ transitionCallbackId: valueBearingEntry.transitionCallbackId,
2791
+ authoritativeSequence: valueBearingEntry.authoritativeSequence,
2792
+ writeSequence: valueBearingEntry.writeSequence,
2793
+ eventSequence: valueBearingEntry.eventSequence,
2794
+ },
2795
+ }
2796
+ }
2797
+ }
2798
+ return { state, relay: nextRelay }
2799
+ }
2800
+
2801
+ function retainRelay(
2802
+ state: UiValueChannelCoordinatorState,
2803
+ relay: UiColdWorkRelayState,
2804
+ ): UiValueChannelCoordinatorState {
2805
+ return {
2806
+ ...state,
2807
+ relays: state.relays.map((candidate) =>
2808
+ candidate.relayId === relay.relayId ? relay : candidate,
2809
+ ),
2810
+ }
2811
+ }
2812
+
2813
+ /** A relay is claimable by its target while armed, or while an ongoing execution awaits claim. */
2814
+ function relayClaimableByTarget(relay: UiColdWorkRelayState): boolean {
2815
+ if (relay.leaseState === 'ARMED') return true
2816
+ return relay.leaseState === 'RELAYED_BY_INCUMBENT' && relay.lifetime === 'ONGOING_EXECUTION'
2817
+ }
2818
+
2819
+ /** A relay is steppable by an admitted incumbent while armed or while it retains an ongoing one. */
2820
+ function relaySteppableByIncumbent(relay: UiColdWorkRelayState): boolean {
2821
+ if (relay.leaseState === 'ARMED') return true
2822
+ return relay.leaseState === 'RELAYED_BY_INCUMBENT' && relay.lifetime === 'ONGOING_EXECUTION'
2823
+ }
2824
+
2825
+ function claimColdWorkRelay(
2826
+ state: UiValueChannelCoordinatorState,
2827
+ relay: UiColdWorkRelayState,
2828
+ driverId: number,
2829
+ absoluteTimestampMs: number,
2830
+ effects: UiValueChannelEffect[],
2831
+ ): UiValueChannelCoordinatorState {
2832
+ effects.push({ kind: 'claim-cold-work-relay', relayId: relay.relayId, driverId })
2833
+ let next: UiValueChannelCoordinatorState = state
2834
+ let stepped = relay
2835
+ if (relay.leaseState === 'ARMED') {
2836
+ effects.push({
2837
+ kind: 'step-cold-work-relay',
2838
+ relayId: relay.relayId,
2839
+ targetDriverId: relay.targetDriverId,
2840
+ absoluteTimestampMs,
2841
+ })
2842
+ const result = fillAndApplyCanonicalRelayRecord(next, relay, effects)
2843
+ next = result.state
2844
+ stepped = result.relay
2845
+ }
2846
+ const claimed: UiColdWorkRelayState = {
2847
+ ...stepped,
2848
+ leaseState: relay.lifetime === 'ONGOING_EXECUTION' ? 'RELEASED' : 'CLAIMED_BY_TARGET',
2849
+ claimedAtTimestampMs: absoluteTimestampMs,
2850
+ claimedByDriverId: driverId,
2851
+ lastRelayedStepTimestampMs:
2852
+ relay.leaseState === 'ARMED' ? absoluteTimestampMs : relay.lastRelayedStepTimestampMs,
2853
+ }
2854
+ if (relay.lifetime === 'ONGOING_EXECUTION') {
2855
+ effects.push({ kind: 'release-claimed-relay', relayId: relay.relayId })
2856
+ }
2857
+ return retainRelay(next, claimed)
2858
+ }
2859
+
2860
+ function stepColdWorkRelayAsIncumbent(
2861
+ state: UiValueChannelCoordinatorState,
2862
+ relay: UiColdWorkRelayState,
2863
+ absoluteTimestampMs: number,
2864
+ effects: UiValueChannelEffect[],
2865
+ ): UiValueChannelCoordinatorState {
2866
+ effects.push({
2867
+ kind: 'peek-relayed-driver-state',
2868
+ relayId: relay.relayId,
2869
+ targetDriverId: relay.targetDriverId,
2870
+ })
2871
+ effects.push({
2872
+ kind: 'step-cold-work-relay',
2873
+ relayId: relay.relayId,
2874
+ targetDriverId: relay.targetDriverId,
2875
+ absoluteTimestampMs,
2876
+ })
2877
+ const result = fillAndApplyCanonicalRelayRecord(state, relay, effects)
2878
+ if (relay.lifetime === 'ONGOING_EXECUTION') {
2879
+ effects.push({ kind: 'retain-ongoing-relay-until-target-claim', relayId: relay.relayId })
2880
+ }
2881
+ return retainRelay(result.state, {
2882
+ ...result.relay,
2883
+ leaseState: 'RELAYED_BY_INCUMBENT',
2884
+ lastRelayedStepTimestampMs: absoluteTimestampMs,
2885
+ })
2886
+ }
2887
+
2888
+ // ——— Live callback invocation ———
2889
+
2890
+ function invokeLiveCallback(
2891
+ state: UiValueChannelCoordinatorState,
2892
+ event: Extract<UiCoordinatorEvent, { readonly kind: 'invoke-live-callback' }>,
2893
+ ): UiValueChannelTransition {
2894
+ const operation: UiValueChannelOperation = 'invoke-live-callback'
2895
+ const callback = requireCallback(state, event.driverId, operation)
2896
+ if (
2897
+ callback.callbackRegistrationGeneration !== event.callbackRegistrationGeneration ||
2898
+ callback.callbackLeaseEpoch !== event.callbackLeaseEpoch
2899
+ ) {
2900
+ throw new UiValueChannelInvariantError('callback-registration-conflict', operation)
2901
+ }
2902
+ if (callback.state === 'RETIRING' || callback.state === 'REVOKED') {
2903
+ throw new UiValueChannelInvariantError('callback-registration-conflict', operation)
2904
+ }
2905
+ const absoluteTimestampMs = event.frame.timestamp
2906
+ const effects: UiValueChannelEffect[] = []
2907
+ let next = state
2908
+
2909
+ // A pending runner candidate publishes admission only on its first actual invocation; the
2910
+ // runner lease itself transfers only after the later acknowledgement.
2911
+ const admissionRequest = next.runnerAdmissionRequest
2912
+ if (
2913
+ admissionRequest !== null &&
2914
+ admissionRequest.candidateDriverId === event.driverId &&
2915
+ admissionRequest.callbackRegistrationGeneration === event.callbackRegistrationGeneration &&
2916
+ !admissionRequest.actualInvocationObserved
2917
+ ) {
2918
+ effects.push({
2919
+ kind: 'publish-actual-callback-invocation-admission',
2920
+ driverId: event.driverId,
2921
+ callbackRegistrationGeneration: event.callbackRegistrationGeneration,
2922
+ callbackLeaseEpoch: event.callbackLeaseEpoch,
2923
+ })
2924
+ next = {
2925
+ ...next,
2926
+ runnerAdmissionRequest: { ...admissionRequest, actualInvocationObserved: true },
2927
+ }
2928
+ }
2929
+
2930
+ const transaction = next.transaction
2931
+ if (transaction.kind === 'OPEN') {
2932
+ if (transaction.absoluteTimestampMs !== absoluteTimestampMs) {
2933
+ throw new UiValueChannelInvariantError('frame-transaction-conflict', operation)
2934
+ }
2935
+ if (
2936
+ transaction.visitedAttendeeDriverIds.includes(event.driverId) ||
2937
+ transaction.revokedAttendeeDriverIds.includes(event.driverId)
2938
+ ) {
2939
+ throw new UiValueChannelInvariantError('frame-attendance-conflict', operation)
2940
+ }
2941
+ next = recordFrameAttendance(next, event.driverId, effects)
2942
+ next = commitFrameIfAttendanceComplete(next, effects)
2943
+ return uiTransition(next, effects)
2944
+ }
2945
+
2946
+ const lastCommittedTimestampMs = transaction.lastCommittedTimestampMs
2947
+ if (lastCommittedTimestampMs !== null && absoluteTimestampMs <= lastCommittedTimestampMs) {
2948
+ if (callback.state === 'ADMITTED') {
2949
+ effects.push({ kind: 'already-committed-no-op', absoluteTimestampMs })
2950
+ } else {
2951
+ effects.push({
2952
+ kind: 'defer-callback-admission-to-next-timestamp',
2953
+ driverId: event.driverId,
2954
+ afterTimestampMs: absoluteTimestampMs,
2955
+ })
2956
+ }
2957
+ return uiTransition(next, effects)
2958
+ }
2959
+
2960
+ // A cold target claims its own relay at a timestamp that is not already committed and performs
2961
+ // the relayed command-edge work in this same invocation.
2962
+ for (const relay of next.relays) {
2963
+ if (relay.targetDriverId !== event.driverId || !relayClaimableByTarget(relay)) continue
2964
+ next = claimColdWorkRelay(next, relay, event.driverId, absoluteTimestampMs, effects)
2965
+ }
2966
+
2967
+ let admittedCallback = callback
2968
+ if (callback.state !== 'ADMITTED') {
2969
+ effects.push({
2970
+ kind: 'admit-callback-lease',
2971
+ driverId: event.driverId,
2972
+ callbackLeaseEpoch: event.callbackLeaseEpoch,
2973
+ absoluteTimestampMs,
2974
+ })
2975
+ admittedCallback = {
2976
+ ...callback,
2977
+ state: 'ADMITTED',
2978
+ admittedFromTimestampMs: absoluteTimestampMs,
2979
+ reanimatedCallbackActive: true,
2980
+ }
2981
+ next = replaceCallback(next, admittedCallback)
2982
+ }
2983
+
2984
+ // The attendee batch freezes when the transaction opens: admitted, active callbacks that have
2985
+ // already produced an invocation (plus the invoking driver itself).
2986
+ const expectedAttendeeDriverIds = next.callbacks
2987
+ .filter(
2988
+ (candidate) =>
2989
+ candidate.state === 'ADMITTED' &&
2990
+ candidate.reanimatedCallbackActive &&
2991
+ (candidate.lastInvocationTimestampMs !== null || candidate.driverId === event.driverId),
2992
+ )
2993
+ .map((candidate) => candidate.driverId)
2994
+ next = {
2995
+ ...next,
2996
+ transaction: {
2997
+ kind: 'OPEN',
2998
+ mode: 'LIVE',
2999
+ absoluteTimestampMs,
3000
+ mailboxDrainId: next.nextMailboxDrainId,
3001
+ expectedAttendeeDriverIds,
3002
+ visitedAttendeeDriverIds: [],
3003
+ revokedAttendeeDriverIds: [],
3004
+ steppedChannelIds: [],
3005
+ frozenInvocationOrder: expectedAttendeeDriverIds,
3006
+ lastCommittedTimestampMs,
3007
+ committedFrameCount: transaction.committedFrameCount,
3008
+ },
3009
+ }
3010
+
3011
+ // An admitted incumbent relays every armed/ongoing cold relay targeted at other drivers before
3012
+ // its own attendance and commit, so no pinned next-update task waits an extra frame.
3013
+ for (const relay of next.relays) {
3014
+ if (relay.targetDriverId === event.driverId || !relaySteppableByIncumbent(relay)) continue
3015
+ next = stepColdWorkRelayAsIncumbent(next, relay, absoluteTimestampMs, effects)
3016
+ }
3017
+
3018
+ next = recordFrameAttendance(next, event.driverId, effects)
3019
+ next = commitFrameIfAttendanceComplete(next, effects)
3020
+ return uiTransition(next, effects)
3021
+ }
3022
+
3023
+ // ——— Coordinator reducer ———
3024
+
3025
+ export function advanceUiCoordinator(
3026
+ state: UiValueChannelCoordinatorState,
3027
+ event: UiCoordinatorEvent,
3028
+ activators: UiRetainedFrameCallbackActivatorRegistry,
3029
+ ): UiValueChannelTransition {
3030
+ switch (event.kind) {
3031
+ case 'arm-cold-work-relay-at-command-edge': {
3032
+ const canonicalRecord = allocateCanonicalRecord(event.commandReceipt.commandAuthority)
3033
+ activators.setActive(event.targetDriverId, event.targetCallbackRegistrationGeneration, true)
3034
+ const relay: UiColdWorkRelayState = {
3035
+ relayId: event.relayId,
3036
+ targetDriverId: event.targetDriverId,
3037
+ commandReceipt: event.commandReceipt,
3038
+ canonicalRecord,
3039
+ commandSequence: event.commandSequence,
3040
+ targetCallbackRegistrationGeneration: event.targetCallbackRegistrationGeneration,
3041
+ relayLeaseEpoch: event.relayLeaseEpoch,
3042
+ leaseState: 'ARMED',
3043
+ lifetime: event.lifetime,
3044
+ armedAtTimestampMs: event.armedAtTimestampMs,
3045
+ lastRelayedStepTimestampMs: null,
3046
+ claimedAtTimestampMs: null,
3047
+ claimedByDriverId: null,
3048
+ pendingValueBearingEntry: null,
3049
+ stagedValueBearingPrefix: null,
3050
+ }
3051
+ return uiTransition({ ...state, relays: [...state.relays, relay] }, [
3052
+ {
3053
+ kind: 'allocate-empty-canonical-cold-relay-record',
3054
+ relayId: event.relayId,
3055
+ canonicalRecord,
3056
+ },
3057
+ {
3058
+ kind: 'arm-cold-relay-lease-at-command-edge',
3059
+ relayId: event.relayId,
3060
+ targetDriverId: event.targetDriverId,
3061
+ targetCallbackRegistrationGeneration: event.targetCallbackRegistrationGeneration,
3062
+ relayLeaseEpoch: event.relayLeaseEpoch,
3063
+ commandReceipt: event.commandReceipt,
3064
+ canonicalRecord,
3065
+ },
3066
+ {
3067
+ kind: 'activate-cold-relay-target-after-command-arm',
3068
+ relayId: event.relayId,
3069
+ targetDriverId: event.targetDriverId,
3070
+ targetCallbackRegistrationGeneration: event.targetCallbackRegistrationGeneration,
3071
+ },
3072
+ ])
3073
+ }
3074
+ case 'refresh-callback-observer': {
3075
+ const callback = requireCallback(state, event.driverId, event.kind)
3076
+ if (callback.callbackRegistrationGeneration !== event.callbackRegistrationGeneration) {
3077
+ throw new UiValueChannelInvariantError('callback-registration-conflict', event.kind)
3078
+ }
3079
+ const refreshed: UiCallbackRegistrationState = {
3080
+ ...callback,
3081
+ observerRevision: event.observerRevision,
3082
+ }
3083
+ return uiTransition(replaceCallback(state, refreshed), [
3084
+ {
3085
+ kind: 'retain-stable-callback-registration',
3086
+ driverId: event.driverId,
3087
+ callbackIdentityId: callback.callbackIdentityId,
3088
+ callbackRegistrationGeneration: event.callbackRegistrationGeneration,
3089
+ },
3090
+ ])
3091
+ }
3092
+ case 'request-callback-activation': {
3093
+ const callback = requireCallback(state, event.driverId, event.kind)
3094
+ if (callback.callbackRegistrationGeneration !== event.callbackRegistrationGeneration) {
3095
+ throw new UiValueChannelInvariantError('callback-registration-conflict', event.kind)
3096
+ }
3097
+ activators.setActive(event.driverId, event.callbackRegistrationGeneration, true)
3098
+ const requested: UiCallbackRegistrationState = {
3099
+ ...callback,
3100
+ state: 'ACTIVATION_REQUESTED',
3101
+ reanimatedCallbackActive: true,
3102
+ }
3103
+ const next: UiValueChannelCoordinatorState = {
3104
+ ...replaceCallback(state, requested),
3105
+ runnerAdmissionRequest: {
3106
+ requestedRunnerLeaseEpoch: event.requestedRunnerLeaseEpoch,
3107
+ candidateDriverId: event.driverId,
3108
+ callbackRegistrationGeneration: event.callbackRegistrationGeneration,
3109
+ admissionToken: event.admissionToken,
3110
+ absoluteDeadlineMs: event.absoluteDeadlineMs,
3111
+ actualInvocationObserved: false,
3112
+ },
3113
+ nextRunnerAdmissionToken: Math.max(
3114
+ state.nextRunnerAdmissionToken,
3115
+ event.admissionToken + 1,
3116
+ ),
3117
+ }
3118
+ return uiTransition(next, [
3119
+ {
3120
+ kind: 'start-runner-admission-timer',
3121
+ requestedRunnerLeaseEpoch: event.requestedRunnerLeaseEpoch,
3122
+ candidateDriverId: event.driverId,
3123
+ callbackRegistrationGeneration: event.callbackRegistrationGeneration,
3124
+ admissionToken: event.admissionToken,
3125
+ absoluteDeadlineMs: event.absoluteDeadlineMs,
3126
+ },
3127
+ ])
3128
+ }
3129
+ case 'invoke-live-callback':
3130
+ return invokeLiveCallback(state, event)
3131
+ case 'acknowledge-callback-admission': {
3132
+ const request = state.runnerAdmissionRequest
3133
+ if (
3134
+ request === null ||
3135
+ request.admissionToken !== event.admissionToken ||
3136
+ request.candidateDriverId !== event.candidateDriverId ||
3137
+ request.callbackRegistrationGeneration !== event.callbackRegistrationGeneration ||
3138
+ request.requestedRunnerLeaseEpoch !== event.requestedRunnerLeaseEpoch ||
3139
+ !request.actualInvocationObserved
3140
+ ) {
3141
+ throw new UiValueChannelInvariantError('runner-admission-request-conflict', event.kind)
3142
+ }
3143
+ const effects: UiValueChannelEffect[] = [
3144
+ { kind: 'cancel-runner-admission-timer', admissionToken: event.admissionToken },
3145
+ {
3146
+ kind: 'transfer-runner-lease-after-admission-acknowledgement',
3147
+ fromDriverId: state.runnerDriverId,
3148
+ toDriverId: event.candidateDriverId,
3149
+ runnerLeaseEpoch: request.requestedRunnerLeaseEpoch,
3150
+ },
3151
+ ]
3152
+ let callbacks = state.callbacks
3153
+ const previousRunner = state.callbacks.find(
3154
+ (candidate) => candidate.driverId === state.runnerDriverId,
3155
+ )
3156
+ if (previousRunner !== undefined && previousRunner.driverId !== event.candidateDriverId) {
3157
+ activators.setActive(
3158
+ previousRunner.driverId,
3159
+ previousRunner.callbackRegistrationGeneration,
3160
+ false,
3161
+ )
3162
+ callbacks = callbacks.map((candidate) =>
3163
+ candidate.driverId === previousRunner.driverId
3164
+ ? { ...candidate, reanimatedCallbackActive: false }
3165
+ : candidate,
3166
+ )
3167
+ }
3168
+ callbacks = callbacks.map((candidate) =>
3169
+ candidate.driverId === event.candidateDriverId
3170
+ ? { ...candidate, state: 'ADMITTED', reanimatedCallbackActive: true }
3171
+ : candidate,
3172
+ )
3173
+ return uiTransition(
3174
+ {
3175
+ ...state,
3176
+ callbacks,
3177
+ runnerDriverId: event.candidateDriverId,
3178
+ runnerLeaseEpoch: request.requestedRunnerLeaseEpoch,
3179
+ runnerAdmissionRequest: null,
3180
+ },
3181
+ effects,
3182
+ )
3183
+ }
3184
+ case 'runner-admission-timeout': {
3185
+ const request = state.runnerAdmissionRequest
3186
+ if (
3187
+ request === null ||
3188
+ request.admissionToken !== event.admissionToken ||
3189
+ request.candidateDriverId !== event.candidateDriverId ||
3190
+ request.callbackRegistrationGeneration !== event.callbackRegistrationGeneration ||
3191
+ request.requestedRunnerLeaseEpoch !== event.requestedRunnerLeaseEpoch
3192
+ ) {
3193
+ throw new UiValueChannelInvariantError('runner-admission-request-conflict', event.kind)
3194
+ }
3195
+ const effects: UiValueChannelEffect[] = [
3196
+ { kind: 'cancel-runner-admission-timer', admissionToken: event.admissionToken },
3197
+ {
3198
+ kind: 'invalidate-runner-admission-candidate',
3199
+ driverId: event.candidateDriverId,
3200
+ admissionToken: event.admissionToken,
3201
+ },
3202
+ ]
3203
+ activators.setActive(event.candidateDriverId, event.callbackRegistrationGeneration, false)
3204
+ const callbacksAfterInvalidation = state.callbacks.map((candidate) =>
3205
+ candidate.driverId === event.candidateDriverId
3206
+ ? { ...candidate, state: 'REGISTERED_INACTIVE' as const, reanimatedCallbackActive: false }
3207
+ : candidate,
3208
+ )
3209
+ const successor = callbacksAfterInvalidation.find(
3210
+ (candidate) =>
3211
+ candidate.driverId !== event.candidateDriverId &&
3212
+ candidate.state === 'REGISTERED_INACTIVE',
3213
+ )
3214
+ if (successor === undefined) {
3215
+ return uiTransition(
3216
+ { ...state, callbacks: callbacksAfterInvalidation, runnerAdmissionRequest: null },
3217
+ effects,
3218
+ )
3219
+ }
3220
+ activators.setActive(successor.driverId, successor.callbackRegistrationGeneration, true)
3221
+ const admissionToken = state.nextRunnerAdmissionToken
3222
+ const absoluteDeadlineMs = event.nowMs + UI_RUNNER_ADMISSION_WINDOW_MS
3223
+ effects.push({
3224
+ kind: 'select-next-live-runner-candidate',
3225
+ excludedDriverIds: [event.candidateDriverId],
3226
+ selectedDriverId: successor.driverId,
3227
+ })
3228
+ effects.push({
3229
+ kind: 'start-runner-admission-timer',
3230
+ requestedRunnerLeaseEpoch: request.requestedRunnerLeaseEpoch,
3231
+ candidateDriverId: successor.driverId,
3232
+ callbackRegistrationGeneration: successor.callbackRegistrationGeneration,
3233
+ admissionToken,
3234
+ absoluteDeadlineMs,
3235
+ })
3236
+ return uiTransition(
3237
+ {
3238
+ ...state,
3239
+ callbacks: callbacksAfterInvalidation.map((candidate) =>
3240
+ candidate.driverId === successor.driverId
3241
+ ? {
3242
+ ...candidate,
3243
+ state: 'ACTIVATION_REQUESTED' as const,
3244
+ reanimatedCallbackActive: true,
3245
+ }
3246
+ : candidate,
3247
+ ),
3248
+ runnerAdmissionRequest: {
3249
+ requestedRunnerLeaseEpoch: request.requestedRunnerLeaseEpoch,
3250
+ candidateDriverId: successor.driverId,
3251
+ callbackRegistrationGeneration: successor.callbackRegistrationGeneration,
3252
+ admissionToken,
3253
+ absoluteDeadlineMs,
3254
+ actualInvocationObserved: false,
3255
+ },
3256
+ nextRunnerAdmissionToken: admissionToken + 1,
3257
+ },
3258
+ effects,
3259
+ )
3260
+ }
3261
+ case 'retire-callback': {
3262
+ const callback = requireCallback(state, event.driverId, event.kind)
3263
+ if (callback.callbackRegistrationGeneration !== event.callbackRegistrationGeneration) {
3264
+ throw new UiValueChannelInvariantError('callback-registration-conflict', event.kind)
3265
+ }
3266
+ const retiring: UiCallbackRegistrationState = { ...callback, state: 'RETIRING' }
3267
+ return uiTransition(replaceCallback(state, retiring), [
3268
+ { kind: 'retire-callback-effective-next-timestamp', driverId: event.driverId },
3269
+ ])
3270
+ }
3271
+ case 'dispose-callback': {
3272
+ const callback = requireCallback(state, event.driverId, event.kind)
3273
+ if (callback.callbackRegistrationGeneration !== event.callbackRegistrationGeneration) {
3274
+ throw new UiValueChannelInvariantError('callback-registration-conflict', event.kind)
3275
+ }
3276
+ const effects: UiValueChannelEffect[] = []
3277
+ let next = state
3278
+ const transaction = state.transaction
3279
+ if (
3280
+ transaction.kind === 'OPEN' &&
3281
+ transaction.expectedAttendeeDriverIds.includes(event.driverId) &&
3282
+ !transaction.visitedAttendeeDriverIds.includes(event.driverId) &&
3283
+ !transaction.revokedAttendeeDriverIds.includes(event.driverId)
3284
+ ) {
3285
+ effects.push({ kind: 'record-synthetic-revocation-attendance', driverId: event.driverId })
3286
+ next = {
3287
+ ...next,
3288
+ transaction: {
3289
+ ...transaction,
3290
+ revokedAttendeeDriverIds: [...transaction.revokedAttendeeDriverIds, event.driverId],
3291
+ },
3292
+ }
3293
+ next = commitFrameIfAttendanceComplete(next, effects)
3294
+ }
3295
+ effects.push({ kind: 'delete-disposed-callback-after-attendance', driverId: event.driverId })
3296
+ next = {
3297
+ ...next,
3298
+ callbacks: next.callbacks.filter((candidate) => candidate.driverId !== event.driverId),
3299
+ }
3300
+ return uiTransition(next, effects)
3301
+ }
3302
+ default: {
3303
+ const exhaustive: never = event
3304
+ void exhaustive
3305
+ throw new UiValueChannelInvariantError('coordinator-event-kind-unrecognized')
3306
+ }
3307
+ }
3308
+ }
3309
+
3310
+ // ——— Manual frame transaction ———
3311
+
3312
+ export function uiBeginManualFrame(
3313
+ state: UiValueChannelCoordinatorState,
3314
+ crossing: UiManualFrameCrossing,
3315
+ ): UiValueChannelTransition {
3316
+ const transaction = state.transaction
3317
+ if (transaction.kind === 'OPEN') {
3318
+ throw new UiValueChannelInvariantError('frame-transaction-conflict', 'ui-begin-manual-frame')
3319
+ }
3320
+ const lastCommittedTimestampMs = transaction.lastCommittedTimestampMs
3321
+ if (
3322
+ lastCommittedTimestampMs !== null &&
3323
+ crossing.absoluteTimestampMs <= lastCommittedTimestampMs
3324
+ ) {
3325
+ throw new UiValueChannelInvariantError('frame-transaction-conflict', 'ui-begin-manual-frame')
3326
+ }
3327
+ return uiTransition(
3328
+ {
3329
+ ...state,
3330
+ transaction: {
3331
+ kind: 'OPEN',
3332
+ mode: 'MANUAL',
3333
+ absoluteTimestampMs: crossing.absoluteTimestampMs,
3334
+ mailboxDrainId: state.nextMailboxDrainId,
3335
+ expectedAttendeeDriverIds: crossing.orderedAttendeeDriverIds,
3336
+ visitedAttendeeDriverIds: [],
3337
+ revokedAttendeeDriverIds: [],
3338
+ steppedChannelIds: [],
3339
+ frozenInvocationOrder: crossing.orderedAttendeeDriverIds,
3340
+ lastCommittedTimestampMs,
3341
+ committedFrameCount: transaction.committedFrameCount,
3342
+ },
3343
+ },
3344
+ [
3345
+ {
3346
+ kind: 'open-frame-transaction',
3347
+ mode: 'MANUAL',
3348
+ absoluteTimestampMs: crossing.absoluteTimestampMs,
3349
+ },
3350
+ ],
3351
+ )
3352
+ }
3353
+
3354
+ export function uiInvokeManualParticipant(
3355
+ state: UiValueChannelCoordinatorState,
3356
+ invocation: UiManualParticipantInvocation,
3357
+ ): UiValueChannelTransition {
3358
+ const transaction = state.transaction
3359
+ if (transaction.kind !== 'OPEN') {
3360
+ if (
3361
+ transaction.lastCommittedTimestampMs !== null &&
3362
+ invocation.absoluteTimestampMs <= transaction.lastCommittedTimestampMs
3363
+ ) {
3364
+ return uiTransition(state, [], {
3365
+ kind: 'LATE_ATTENDANCE',
3366
+ driverId: invocation.driverId,
3367
+ alreadyCommittedTimestampMs: transaction.lastCommittedTimestampMs,
3368
+ })
3369
+ }
3370
+ throw new UiValueChannelInvariantError(
3371
+ 'frame-transaction-conflict',
3372
+ 'ui-invoke-manual-participant',
3373
+ )
3374
+ }
3375
+ if (
3376
+ transaction.mode !== 'MANUAL' ||
3377
+ transaction.absoluteTimestampMs !== invocation.absoluteTimestampMs
3378
+ ) {
3379
+ throw new UiValueChannelInvariantError(
3380
+ 'frame-transaction-conflict',
3381
+ 'ui-invoke-manual-participant',
3382
+ )
3383
+ }
3384
+ if (!transaction.expectedAttendeeDriverIds.includes(invocation.driverId)) {
3385
+ throw new UiValueChannelInvariantError(
3386
+ 'frame-attendance-conflict',
3387
+ 'ui-invoke-manual-participant',
3388
+ )
3389
+ }
3390
+ if (
3391
+ transaction.visitedAttendeeDriverIds.includes(invocation.driverId) ||
3392
+ transaction.revokedAttendeeDriverIds.includes(invocation.driverId)
3393
+ ) {
3394
+ throw new UiValueChannelInvariantError(
3395
+ 'frame-attendance-conflict',
3396
+ 'ui-invoke-manual-participant',
3397
+ )
3398
+ }
3399
+ const effects: UiValueChannelEffect[] = []
3400
+ let next = recordFrameAttendance(state, invocation.driverId, effects)
3401
+ next = commitFrameIfAttendanceComplete(next, effects)
3402
+ return uiTransition(next, effects)
3403
+ }
3404
+
3405
+ export function uiRevokeManualParticipant(
3406
+ state: UiValueChannelCoordinatorState,
3407
+ revocation: UiManualParticipantRevocation,
3408
+ ): UiValueChannelTransition {
3409
+ const transaction = state.transaction
3410
+ if (
3411
+ transaction.kind !== 'OPEN' ||
3412
+ transaction.mode !== 'MANUAL' ||
3413
+ transaction.absoluteTimestampMs !== revocation.absoluteTimestampMs
3414
+ ) {
3415
+ throw new UiValueChannelInvariantError(
3416
+ 'frame-transaction-conflict',
3417
+ 'ui-revoke-manual-participant',
3418
+ )
3419
+ }
3420
+ if (!transaction.expectedAttendeeDriverIds.includes(revocation.driverId)) {
3421
+ throw new UiValueChannelInvariantError(
3422
+ 'frame-attendance-conflict',
3423
+ 'ui-revoke-manual-participant',
3424
+ )
3425
+ }
3426
+ if (
3427
+ transaction.visitedAttendeeDriverIds.includes(revocation.driverId) ||
3428
+ transaction.revokedAttendeeDriverIds.includes(revocation.driverId)
3429
+ ) {
3430
+ throw new UiValueChannelInvariantError(
3431
+ 'frame-attendance-conflict',
3432
+ 'ui-revoke-manual-participant',
3433
+ )
3434
+ }
3435
+ const effects: UiValueChannelEffect[] = [
3436
+ { kind: 'record-synthetic-revocation-attendance', driverId: revocation.driverId },
3437
+ ]
3438
+ let next: UiValueChannelCoordinatorState = {
3439
+ ...state,
3440
+ transaction: {
3441
+ ...transaction,
3442
+ revokedAttendeeDriverIds: [...transaction.revokedAttendeeDriverIds, revocation.driverId],
3443
+ },
3444
+ }
3445
+ next = commitFrameIfAttendanceComplete(next, effects)
3446
+ return uiTransition(next, effects)
3447
+ }
3448
+
3449
+ export function uiCommitManualFrame(
3450
+ state: UiValueChannelCoordinatorState,
3451
+ request: UiManualFrameCommitRequest,
3452
+ ): UiValueChannelTransition {
3453
+ const transaction = state.transaction
3454
+ if (transaction.kind !== 'OPEN') {
3455
+ if (transaction.lastCommittedTimestampMs === request.absoluteTimestampMs) {
3456
+ return uiTransition(state, [
3457
+ { kind: 'already-committed-no-op', absoluteTimestampMs: request.absoluteTimestampMs },
3458
+ ])
3459
+ }
3460
+ throw new UiValueChannelInvariantError('frame-transaction-conflict', 'ui-commit-manual-frame')
3461
+ }
3462
+ if (
3463
+ transaction.mode !== 'MANUAL' ||
3464
+ transaction.absoluteTimestampMs !== request.absoluteTimestampMs
3465
+ ) {
3466
+ throw new UiValueChannelInvariantError('frame-transaction-conflict', 'ui-commit-manual-frame')
3467
+ }
3468
+ const missingDriverIds = transaction.expectedAttendeeDriverIds.filter(
3469
+ (driverId) =>
3470
+ !transaction.visitedAttendeeDriverIds.includes(driverId) &&
3471
+ !transaction.revokedAttendeeDriverIds.includes(driverId),
3472
+ )
3473
+ if (missingDriverIds.length > 0) {
3474
+ return uiTransition(state, [], { kind: 'MISSING_ATTENDEES', missingDriverIds })
3475
+ }
3476
+ const effects: UiValueChannelEffect[] = []
3477
+ const next = commitFrameIfAttendanceComplete(state, effects)
3478
+ return uiTransition(next, effects)
3479
+ }
3480
+
3481
+ export function armManualDestinationCommit(
3482
+ state: UiValueChannelCoordinatorState,
3483
+ groupId: number,
3484
+ commit: UiManualDestinationCommitSlot,
3485
+ ): UiValueChannelTransition {
3486
+ const group = requireManualGroup(state, groupId, 'arm-manual-destination-commit')
3487
+ return uiTransition(
3488
+ replaceManualGroup(state, {
3489
+ ...group,
3490
+ pendingDestinationCommits: [...group.pendingDestinationCommits, commit],
3491
+ armedForExplicitStep: true,
3492
+ }),
3493
+ [
3494
+ {
3495
+ kind: 'arm-manual-group-for-destination-commit',
3496
+ groupId,
3497
+ commitSlotId: commit.commitSlotId,
3498
+ },
3499
+ ],
3500
+ )
3501
+ }
3502
+
3503
+ interface UiManualCommitConsumption {
3504
+ readonly state: UiValueChannelCoordinatorState
3505
+ readonly group: ManualFrameGroupState
3506
+ }
3507
+
3508
+ function consumeManualDestinationCommit(
3509
+ state: UiValueChannelCoordinatorState,
3510
+ group: ManualFrameGroupState,
3511
+ commit: UiManualDestinationCommitSlot,
3512
+ authority: UiPreparedDestinationRecordState,
3513
+ validator: UiDestinationCommitCanonicalValidatorCapability,
3514
+ effects: UiValueChannelEffect[],
3515
+ ): UiManualCommitConsumption {
3516
+ effects.push({
3517
+ kind: 'lookup-prepared-destination-record',
3518
+ groupId: group.groupId,
3519
+ destinationRecordId: commit.destinationRecordId,
3520
+ })
3521
+ effects.push({
3522
+ kind: 'validate-ui-destination-commit-with-canonical-authority',
3523
+ root: 'MANUAL',
3524
+ groupId: group.groupId,
3525
+ commitSlotId: commit.commitSlotId,
3526
+ authority,
3527
+ validator,
3528
+ })
3529
+ const newEntries = commit.includedPostFencePrefix.filter(
3530
+ (entry) => entry.authoritativeSequence > authority.appliedThroughAuthoritativeSequence,
3531
+ )
3532
+ const appliedThroughAuthoritativeSequence =
3533
+ newEntries.at(-1)?.authoritativeSequence ?? authority.appliedThroughAuthoritativeSequence
3534
+ let next = state
3535
+ if (newEntries.length > 0) {
3536
+ effects.push({
3537
+ kind: 'adopt-immutable-destination-commit',
3538
+ groupId: group.groupId,
3539
+ commitSlotId: commit.commitSlotId,
3540
+ })
3541
+ for (const entry of newEntries) {
3542
+ effects.push({
3543
+ kind: 'apply-included-post-fence-ledger-entry-in-place',
3544
+ groupId: group.groupId,
3545
+ commitSlotId: commit.commitSlotId,
3546
+ prefixIndex: commit.includedPostFencePrefix.indexOf(entry),
3547
+ destinationSlot: entry.destinationSlot,
3548
+ entry,
3549
+ })
3550
+ }
3551
+ next = {
3552
+ ...next,
3553
+ preparedDestinationRecords: next.preparedDestinationRecords.map((candidate) =>
3554
+ candidate === authority
3555
+ ? {
3556
+ ...candidate,
3557
+ adoptedCommitSlotId: commit.commitSlotId,
3558
+ appliedThroughAuthoritativeSequence,
3559
+ ledgers: applyEntriesToUiLedgers(candidate.ledgers, newEntries),
3560
+ }
3561
+ : candidate,
3562
+ ),
3563
+ }
3564
+ }
3565
+ const acknowledgement: DestinationCommitAcknowledgement = {
3566
+ kind: 'DESTINATION_COMMIT_ACKNOWLEDGEMENT',
3567
+ channelId: commit.channelId,
3568
+ sourceRecordId: commit.sourceRecordId,
3569
+ destinationRecordId: commit.destinationRecordId,
3570
+ direction: commit.direction,
3571
+ transferLease: commit.transferLease,
3572
+ releaseFenceSequence: commit.releaseFenceSequence,
3573
+ drainedThroughAuthoritativeSequence: appliedThroughAuthoritativeSequence,
3574
+ }
3575
+ effects.push({
3576
+ kind: 'fill-prefilled-destination-acknowledgement-slot',
3577
+ groupId: group.groupId,
3578
+ commitSlotId: commit.commitSlotId,
3579
+ acknowledgementSlotId: commit.acknowledgementSlotId,
3580
+ })
3581
+ effects.push({
3582
+ kind: 'stage-destination-acknowledgement-in-current-envelope',
3583
+ groupId: group.groupId,
3584
+ acknowledgementSlotId: commit.acknowledgementSlotId,
3585
+ mailboxDrainId: next.nextMailboxDrainId,
3586
+ })
3587
+ next = {
3588
+ ...next,
3589
+ destinationCommitAcknowledgementSlots: next.destinationCommitAcknowledgementSlots.map(
3590
+ (candidate) =>
3591
+ candidate.acknowledgementSlotId === commit.acknowledgementSlotId
3592
+ ? { ...candidate, state: 'STAGED_IN_CURRENT_ENVELOPE', acknowledgement }
3593
+ : candidate,
3594
+ ),
3595
+ }
3596
+ effects.push({
3597
+ kind: 'consume-manual-destination-commit-on-explicit-step',
3598
+ groupId: group.groupId,
3599
+ commitSlotId: commit.commitSlotId,
3600
+ })
3601
+ const pendingDestinationCommits = group.pendingDestinationCommits.filter(
3602
+ (candidate) => candidate.commitSlotId !== commit.commitSlotId,
3603
+ )
3604
+ return {
3605
+ state: next,
3606
+ group: {
3607
+ ...group,
3608
+ pendingDestinationCommits,
3609
+ consumedCommitSlotIds: [...group.consumedCommitSlotIds, commit.commitSlotId],
3610
+ armedForExplicitStep: pendingDestinationCommits.length > 0,
3611
+ },
3612
+ }
3613
+ }
3614
+
3615
+ export function stepManualFrameGroup(
3616
+ state: UiValueChannelCoordinatorState,
3617
+ request: ManualFrameGroupStepRequest,
3618
+ validator: UiDestinationCommitCanonicalValidatorCapability,
3619
+ ): UiValueChannelTransition {
3620
+ const group = requireManualGroup(state, request.groupId, 'step-manual-frame-group')
3621
+ if (state.transaction.kind === 'OPEN') {
3622
+ throw new UiValueChannelInvariantError('frame-transaction-conflict', 'step-manual-frame-group')
3623
+ }
3624
+ const pendingCommit = group.pendingDestinationCommits[0]
3625
+ let authority: UiPreparedDestinationRecordState | null = null
3626
+ if (pendingCommit !== undefined) {
3627
+ const outcome = validator.validate({
3628
+ commit: pendingCommit,
3629
+ preparedDestinationRecords: state.preparedDestinationRecords,
3630
+ })
3631
+ if (outcome.kind === 'REFUSED') {
3632
+ return uiTransition(
3633
+ state,
3634
+ [
3635
+ {
3636
+ kind: 'report-ui-destination-commit-refusal',
3637
+ root: 'MANUAL',
3638
+ groupId: request.groupId,
3639
+ commitSlotId: pendingCommit.commitSlotId,
3640
+ authority: outcome.authority,
3641
+ reason: outcome.reason,
3642
+ },
3643
+ ],
3644
+ {
3645
+ kind: 'DESTINATION_COMMIT_REFUSED',
3646
+ groupId: request.groupId,
3647
+ commitSlotId: pendingCommit.commitSlotId,
3648
+ authority: outcome.authority,
3649
+ reason: outcome.reason,
3650
+ },
3651
+ )
3652
+ }
3653
+ authority = outcome.authority
3654
+ const acknowledgementSlot = state.destinationCommitAcknowledgementSlots.find(
3655
+ (candidate) => candidate.acknowledgementSlotId === pendingCommit.acknowledgementSlotId,
3656
+ )
3657
+ if (acknowledgementSlot === undefined) {
3658
+ return uiTransition(
3659
+ state,
3660
+ [
3661
+ {
3662
+ kind: 'report-ui-destination-commit-refusal',
3663
+ root: 'MANUAL',
3664
+ groupId: request.groupId,
3665
+ commitSlotId: pendingCommit.commitSlotId,
3666
+ authority,
3667
+ reason: 'missing-acknowledgement-slot',
3668
+ },
3669
+ ],
3670
+ {
3671
+ kind: 'DESTINATION_COMMIT_REFUSED',
3672
+ groupId: request.groupId,
3673
+ commitSlotId: pendingCommit.commitSlotId,
3674
+ authority,
3675
+ reason: 'missing-acknowledgement-slot',
3676
+ },
3677
+ )
3678
+ }
3679
+ }
3680
+
3681
+ const absoluteTimestampMs = group.currentAbsoluteTimestampMs + request.elapsedMs
3682
+ const orderedAttendeeDriverIds = request.invocationOrder ?? group.participantDriverIds
3683
+ const effects: UiValueChannelEffect[] = [
3684
+ { kind: 'advance-manual-group-clock-once', groupId: request.groupId, absoluteTimestampMs },
3685
+ {
3686
+ kind: 'freeze-manual-attendee-batch',
3687
+ groupId: request.groupId,
3688
+ orderedAttendeeDriverIds,
3689
+ },
3690
+ ]
3691
+ let next = state
3692
+ let steppedGroup = group
3693
+ if (pendingCommit !== undefined && authority !== null) {
3694
+ const consumption = consumeManualDestinationCommit(
3695
+ next,
3696
+ steppedGroup,
3697
+ pendingCommit,
3698
+ authority,
3699
+ validator,
3700
+ effects,
3701
+ )
3702
+ next = consumption.state
3703
+ steppedGroup = consumption.group
3704
+ }
3705
+ const identities = next.identities.map((identity) => {
3706
+ const deltaMs =
3707
+ identity.lastAbsoluteTimestampMs === null
3708
+ ? 0
3709
+ : absoluteTimestampMs - identity.lastAbsoluteTimestampMs
3710
+ effects.push({
3711
+ kind: 'step-shared-identity-once',
3712
+ channelId: identity.channelId,
3713
+ absoluteTimestampMs,
3714
+ deltaMs,
3715
+ })
3716
+ return {
3717
+ ...identity,
3718
+ lastAbsoluteTimestampMs: absoluteTimestampMs,
3719
+ stepCount: identity.stepCount + 1,
3720
+ hostCommitCount: identity.hostCommitCount + 1,
3721
+ }
3722
+ })
3723
+ effects.push({ kind: 'commit-frame-once', absoluteTimestampMs })
3724
+ const transaction = next.transaction
3725
+ if (transaction.kind !== 'CLOSED') {
3726
+ throw new UiValueChannelInvariantError('frame-transaction-conflict', 'step-manual-frame-group')
3727
+ }
3728
+ next = {
3729
+ ...next,
3730
+ identities,
3731
+ transaction: {
3732
+ kind: 'CLOSED',
3733
+ lastCommittedTimestampMs: absoluteTimestampMs,
3734
+ committedFrameCount: transaction.committedFrameCount + 1,
3735
+ },
3736
+ }
3737
+ next = replaceManualGroup(next, {
3738
+ ...steppedGroup,
3739
+ currentAbsoluteTimestampMs: absoluteTimestampMs,
3740
+ explicitStepCount: steppedGroup.explicitStepCount + 1,
3741
+ })
3742
+ return uiTransition(next, effects)
3743
+ }
3744
+
3745
+ // ——— Live UI destination COMMIT consumption ———
3746
+
3747
+ function refuseLiveUiDestinationCommit(
3748
+ state: UiLiveDestinationCommitConsumeState,
3749
+ commitSlotId: number,
3750
+ authority: UiPreparedDestinationRecordState | null,
3751
+ reason: UiLiveDestinationCommitRefusalReason,
3752
+ ): UiLiveDestinationCommitTransition {
3753
+ return {
3754
+ state,
3755
+ outcome: { kind: 'REFUSED', commitSlotId, reason },
3756
+ orderedEffects: [
3757
+ {
3758
+ kind: 'report-ui-destination-commit-refusal',
3759
+ root: 'LIVE',
3760
+ commitSlotId,
3761
+ authority,
3762
+ reason,
3763
+ },
3764
+ ],
3765
+ }
3766
+ }
3767
+
3768
+ export function consumeLiveUiDestinationCommit(
3769
+ state: UiLiveDestinationCommitConsumeState,
3770
+ request: UiLiveDestinationCommitConsumeRequest,
3771
+ validator: UiDestinationCommitCanonicalValidatorCapability,
3772
+ ): UiLiveDestinationCommitTransition {
3773
+ const envelope = state.envelope
3774
+ const commit = request.commit
3775
+ if (envelope.state !== 'OPEN') {
3776
+ return refuseLiveUiDestinationCommit(state, commit.commitSlotId, null, 'envelope-not-open')
3777
+ }
3778
+ const outcome = validator.validate({
3779
+ commit,
3780
+ preparedDestinationRecords: state.coordinator.preparedDestinationRecords,
3781
+ })
3782
+ if (outcome.kind === 'REFUSED') {
3783
+ return refuseLiveUiDestinationCommit(
3784
+ state,
3785
+ commit.commitSlotId,
3786
+ outcome.authority,
3787
+ outcome.reason,
3788
+ )
3789
+ }
3790
+ const authority = outcome.authority
3791
+ const acknowledgementSlot = state.coordinator.destinationCommitAcknowledgementSlots.find(
3792
+ (candidate) => candidate.acknowledgementSlotId === commit.acknowledgementSlotId,
3793
+ )
3794
+ if (acknowledgementSlot === undefined) {
3795
+ return refuseLiveUiDestinationCommit(
3796
+ state,
3797
+ commit.commitSlotId,
3798
+ authority,
3799
+ 'missing-acknowledgement-slot',
3800
+ )
3801
+ }
3802
+
3803
+ const effects: UiLiveDestinationCommitEffect[] = [
3804
+ {
3805
+ kind: 'lookup-live-prepared-destination-record',
3806
+ destinationRecordId: commit.destinationRecordId,
3807
+ },
3808
+ {
3809
+ kind: 'validate-ui-destination-commit-with-canonical-authority',
3810
+ root: 'LIVE',
3811
+ commitSlotId: commit.commitSlotId,
3812
+ authority,
3813
+ validator,
3814
+ },
3815
+ ]
3816
+ const newEntries = commit.includedPostFencePrefix.filter(
3817
+ (entry) => entry.authoritativeSequence > authority.appliedThroughAuthoritativeSequence,
3818
+ )
3819
+ const appliedThroughAuthoritativeSequence =
3820
+ newEntries.at(-1)?.authoritativeSequence ?? authority.appliedThroughAuthoritativeSequence
3821
+ const duplicate = newEntries.length === 0
3822
+ let preparedDestinationRecords = state.coordinator.preparedDestinationRecords
3823
+ if (!duplicate) {
3824
+ effects.push({
3825
+ kind: 'adopt-live-immutable-destination-commit',
3826
+ commitSlotId: commit.commitSlotId,
3827
+ })
3828
+ for (const entry of newEntries) {
3829
+ effects.push({
3830
+ kind: 'apply-live-included-post-fence-ledger-entry-in-place',
3831
+ commitSlotId: commit.commitSlotId,
3832
+ prefixIndex: commit.includedPostFencePrefix.indexOf(entry),
3833
+ destinationSlot: entry.destinationSlot,
3834
+ entry,
3835
+ })
3836
+ }
3837
+ preparedDestinationRecords = preparedDestinationRecords.map((candidate) =>
3838
+ candidate === authority
3839
+ ? {
3840
+ ...candidate,
3841
+ adoptedCommitSlotId: commit.commitSlotId,
3842
+ appliedThroughAuthoritativeSequence,
3843
+ ledgers: applyEntriesToUiLedgers(candidate.ledgers, newEntries),
3844
+ }
3845
+ : candidate,
3846
+ )
3847
+ }
3848
+ const acknowledgement: DestinationCommitAcknowledgement = {
3849
+ kind: 'DESTINATION_COMMIT_ACKNOWLEDGEMENT',
3850
+ channelId: commit.channelId,
3851
+ sourceRecordId: commit.sourceRecordId,
3852
+ destinationRecordId: commit.destinationRecordId,
3853
+ direction: commit.direction,
3854
+ transferLease: commit.transferLease,
3855
+ releaseFenceSequence: commit.releaseFenceSequence,
3856
+ drainedThroughAuthoritativeSequence: appliedThroughAuthoritativeSequence,
3857
+ }
3858
+ effects.push({
3859
+ kind: 'fill-live-destination-acknowledgement-slot',
3860
+ commitSlotId: commit.commitSlotId,
3861
+ acknowledgementSlotId: commit.acknowledgementSlotId,
3862
+ })
3863
+ effects.push({
3864
+ kind: 'stage-live-destination-acknowledgement-in-current-envelope',
3865
+ acknowledgementSlotId: commit.acknowledgementSlotId,
3866
+ mailboxDrainId: envelope.mailboxDrainId,
3867
+ })
3868
+ const entries: UiLiveDestinationEnvelopeEntry[] = [
3869
+ {
3870
+ kind: 'DESTINATION_COMMIT_ACKNOWLEDGEMENT',
3871
+ acknowledgementSlotId: commit.acknowledgementSlotId,
3872
+ drainedThroughAuthoritativeSequence: appliedThroughAuthoritativeSequence,
3873
+ },
3874
+ ]
3875
+ for (const sibling of request.siblingEmissions) {
3876
+ effects.push({
3877
+ kind: 'emit-live-ui-sibling',
3878
+ emissionSequence: sibling.emissionSequence,
3879
+ emissionKind: sibling.emissionKind,
3880
+ })
3881
+ entries.push({
3882
+ kind: 'SIBLING_EMISSION',
3883
+ emissionSequence: sibling.emissionSequence,
3884
+ emissionKind: sibling.emissionKind,
3885
+ })
3886
+ }
3887
+ effects.push({
3888
+ kind: 'seal-live-ui-envelope-once',
3889
+ mailboxDrainId: envelope.mailboxDrainId,
3890
+ entryCount: entries.length,
3891
+ })
3892
+ const sealedEnvelope: UiLiveDestinationEnvelopeState = {
3893
+ ...envelope,
3894
+ state: 'SEALED',
3895
+ entries,
3896
+ sealCount: envelope.sealCount + 1,
3897
+ }
3898
+ return {
3899
+ state: {
3900
+ coordinator: {
3901
+ ...state.coordinator,
3902
+ preparedDestinationRecords,
3903
+ destinationCommitAcknowledgementSlots:
3904
+ state.coordinator.destinationCommitAcknowledgementSlots.map((candidate) =>
3905
+ candidate.acknowledgementSlotId === commit.acknowledgementSlotId
3906
+ ? { ...candidate, state: 'STAGED_IN_CURRENT_ENVELOPE', acknowledgement }
3907
+ : candidate,
3908
+ ),
3909
+ },
3910
+ envelope: sealedEnvelope,
3911
+ },
3912
+ outcome: duplicate
3913
+ ? { kind: 'DUPLICATE_REACKNOWLEDGED', commitSlotId: commit.commitSlotId, acknowledgement }
3914
+ : { kind: 'APPLIED', commitSlotId: commit.commitSlotId, acknowledgement },
3915
+ orderedEffects: effects,
3916
+ }
3917
+ }
3918
+
3919
+ // ——— Shared manual identity transfer gap ———
3920
+
3921
+ export function stepSharedManualIdentityTransferGap(
3922
+ state: UiValueChannelCoordinatorState,
3923
+ request: UiSharedManualIdentityTransferGapRequest,
3924
+ ): UiSharedManualIdentityTransferGapTransition {
3925
+ const identity = state.identities.find((candidate) => candidate.channelId === request.channelId)
3926
+ if (identity === undefined) {
3927
+ throw new UiValueChannelInvariantError(
3928
+ 'shared-transfer-identity-missing',
3929
+ 'step-shared-manual-identity-transfer-gap',
3930
+ )
3931
+ }
3932
+ const firstDriverId = request.orderedAttendeeDriverIds[0]
3933
+ const secondDriverId = request.orderedAttendeeDriverIds[1]
3934
+ const firstGeneration = request.callbackRegistrationGenerations[0]
3935
+ const secondGeneration = request.callbackRegistrationGenerations[1]
3936
+ const orderedEffects: UiSharedManualIdentityTransferGapEffect[] = [
3937
+ {
3938
+ kind: 'begin-shared-manual-transfer-transaction',
3939
+ groupId: request.groupId,
3940
+ channelId: request.channelId,
3941
+ absoluteTimestampMs: request.absoluteTimestampMs,
3942
+ orderedAttendeeDriverIds: request.orderedAttendeeDriverIds,
3943
+ callbackRegistrationGenerations: request.callbackRegistrationGenerations,
3944
+ },
3945
+ {
3946
+ kind: 'invoke-shared-manual-transfer-participant',
3947
+ groupId: request.groupId,
3948
+ driverId: firstDriverId,
3949
+ callbackRegistrationGeneration: firstGeneration,
3950
+ invocationIndex: 0,
3951
+ absoluteTimestampMs: request.absoluteTimestampMs,
3952
+ },
3953
+ {
3954
+ kind: 'bridge-shared-identity-transfer-gap',
3955
+ channelId: request.channelId,
3956
+ direction: request.direction,
3957
+ transferLease: request.transferLease,
3958
+ sourceRecordId: request.sourceRecordId,
3959
+ destinationRecordId: request.destinationRecordId,
3960
+ absoluteTimestampMs: request.absoluteTimestampMs,
3961
+ },
3962
+ {
3963
+ kind: 'invoke-shared-manual-transfer-participant',
3964
+ groupId: request.groupId,
3965
+ driverId: secondDriverId,
3966
+ callbackRegistrationGeneration: secondGeneration,
3967
+ invocationIndex: 1,
3968
+ absoluteTimestampMs: request.absoluteTimestampMs,
3969
+ },
3970
+ {
3971
+ kind: 'step-shared-manual-transfer-identity-once',
3972
+ channelId: request.channelId,
3973
+ absoluteTimestampMs: request.absoluteTimestampMs,
3974
+ },
3975
+ {
3976
+ kind: 'commit-shared-manual-transfer-transaction-once',
3977
+ groupId: request.groupId,
3978
+ absoluteTimestampMs: request.absoluteTimestampMs,
3979
+ },
3980
+ ]
3981
+ const transaction = state.transaction
3982
+ const next: UiValueChannelCoordinatorState = {
3983
+ ...state,
3984
+ identities: state.identities.map((candidate) =>
3985
+ candidate.channelId === request.channelId
3986
+ ? {
3987
+ ...candidate,
3988
+ lastAbsoluteTimestampMs: request.absoluteTimestampMs,
3989
+ stepCount: candidate.stepCount + 1,
3990
+ hostCommitCount: candidate.hostCommitCount + 1,
3991
+ }
3992
+ : candidate,
3993
+ ),
3994
+ transaction: {
3995
+ kind: 'CLOSED',
3996
+ lastCommittedTimestampMs: request.absoluteTimestampMs,
3997
+ committedFrameCount: transaction.committedFrameCount + 1,
3998
+ },
3999
+ }
4000
+ return { state: next, observation: observeUiValueChannel(next), orderedEffects }
4001
+ }
4002
+
4003
+ // ——— UI-owned identity sink fanout ———
4004
+
4005
+ export function fanoutUiOwnedIdentitySample(
4006
+ state: UiOwnedIdentitySampleFanoutState,
4007
+ request: UiOwnedIdentitySampleFanoutRequest,
4008
+ ): UiOwnedIdentitySampleFanoutTransition {
4009
+ if (request.channelId !== state.channelId) {
4010
+ throw new UiValueChannelInvariantError(
4011
+ 'owned-identity-channel-conflict',
4012
+ 'fanout-ui-owned-identity-sample',
4013
+ )
4014
+ }
4015
+ const orderedEffects: UiOwnedIdentitySampleFanoutEffect[] = [
4016
+ {
4017
+ kind: 'adopt-ui-owned-identity-sample',
4018
+ channelId: request.channelId,
4019
+ executionId: request.executionId,
4020
+ value: request.value,
4021
+ writeSequence: request.writeSequence,
4022
+ absoluteTimestampMs: request.absoluteTimestampMs,
4023
+ },
4024
+ ]
4025
+ const sinks = state.sinks.map((sink) => {
4026
+ orderedEffects.push({
4027
+ kind: 'fanout-ui-owned-identity-sample-to-sink',
4028
+ sinkId: sink.sinkId,
4029
+ driverId: sink.driverId,
4030
+ handle: sink.handle,
4031
+ key: sink.key,
4032
+ bindingGeneration: sink.bindingGeneration,
4033
+ value: request.value,
4034
+ writeSequence: request.writeSequence,
4035
+ })
4036
+ return {
4037
+ ...sink,
4038
+ lastCommittedValue: request.value,
4039
+ lastCommittedWriteSequence: request.writeSequence,
4040
+ commitCount: sink.commitCount + 1,
4041
+ }
4042
+ })
4043
+ orderedEffects.push({
4044
+ kind: 'commit-ui-owned-identity-sinks-once',
4045
+ channelId: request.channelId,
4046
+ sinkIds: sinks.map((sink) => sink.sinkId),
4047
+ absoluteTimestampMs: request.absoluteTimestampMs,
4048
+ })
4049
+ const next: UiOwnedIdentitySampleFanoutState = {
4050
+ ...state,
4051
+ lastAcceptedAbsoluteTimestampMs: request.absoluteTimestampMs,
4052
+ sinks,
4053
+ uiSinkCommitCount: state.uiSinkCommitCount + 1,
4054
+ }
4055
+ return {
4056
+ state: next,
4057
+ observation: {
4058
+ channelId: next.channelId,
4059
+ sinkCount: next.sinks.length,
4060
+ committedSinkCount: next.sinks.length,
4061
+ committedSinkIds: next.sinks.map((sink) => sink.sinkId),
4062
+ uiSinkCommitCount: next.uiSinkCommitCount,
4063
+ jsToUiWriteLaneInvocationCount: next.jsToUiWriteLaneInvocationCount,
4064
+ },
4065
+ orderedEffects,
4066
+ }
4067
+ }
4068
+
4069
+ // ——— Legacy manual driver.step compatibility ———
4070
+
4071
+ export function stepLegacyManualDriver(
4072
+ state: UiValueChannelCoordinatorState,
4073
+ request: LegacyManualDriverStepRequest,
4074
+ ): UiValueChannelTransition {
4075
+ const group = requireManualGroup(state, request.groupId, 'step-legacy-manual-driver')
4076
+ if (
4077
+ group.participantDriverIds.length !== 1 ||
4078
+ group.participantDriverIds[0] !== request.driverId
4079
+ ) {
4080
+ return uiTransition(state, [], {
4081
+ kind: 'MULTI_MEMBER_GROUP_REQUIRES_GROUP_STEP',
4082
+ groupId: request.groupId,
4083
+ participantCount: group.participantDriverIds.length,
4084
+ })
4085
+ }
4086
+ const absoluteTimestampMs = group.currentAbsoluteTimestampMs + request.elapsedMs
4087
+ const effects: UiValueChannelEffect[] = [
4088
+ {
4089
+ kind: 'delegate-legacy-step-to-private-single-member-group',
4090
+ groupId: request.groupId,
4091
+ driverId: request.driverId,
4092
+ },
4093
+ { kind: 'advance-manual-group-clock-once', groupId: request.groupId, absoluteTimestampMs },
4094
+ {
4095
+ kind: 'freeze-manual-attendee-batch',
4096
+ groupId: request.groupId,
4097
+ orderedAttendeeDriverIds: [request.driverId],
4098
+ },
4099
+ ]
4100
+ const identities = state.identities.map((identity) => {
4101
+ const deltaMs =
4102
+ identity.lastAbsoluteTimestampMs === null
4103
+ ? 0
4104
+ : absoluteTimestampMs - identity.lastAbsoluteTimestampMs
4105
+ effects.push({
4106
+ kind: 'step-shared-identity-once',
4107
+ channelId: identity.channelId,
4108
+ absoluteTimestampMs,
4109
+ deltaMs,
4110
+ })
4111
+ return {
4112
+ ...identity,
4113
+ lastAbsoluteTimestampMs: absoluteTimestampMs,
4114
+ stepCount: identity.stepCount + 1,
4115
+ hostCommitCount: identity.hostCommitCount + 1,
4116
+ }
4117
+ })
4118
+ effects.push({ kind: 'commit-frame-once', absoluteTimestampMs })
4119
+ const transaction = state.transaction
4120
+ if (transaction.kind !== 'CLOSED') {
4121
+ throw new UiValueChannelInvariantError(
4122
+ 'frame-transaction-conflict',
4123
+ 'step-legacy-manual-driver',
4124
+ )
4125
+ }
4126
+ const next = replaceManualGroup(
4127
+ {
4128
+ ...state,
4129
+ identities,
4130
+ transaction: {
4131
+ kind: 'CLOSED',
4132
+ lastCommittedTimestampMs: absoluteTimestampMs,
4133
+ committedFrameCount: transaction.committedFrameCount + 1,
4134
+ },
4135
+ },
4136
+ {
4137
+ ...group,
4138
+ currentAbsoluteTimestampMs: absoluteTimestampMs,
4139
+ explicitStepCount: group.explicitStepCount + 1,
4140
+ },
4141
+ )
4142
+ return uiTransition(next, effects)
4143
+ }
4144
+
4145
+ // ——— UI-owned private target-batch dependency events ———
4146
+
4147
+ export function stageUiPrivateTargetBatchDependencyEvent(
4148
+ coordinator: UiValueChannelCoordinatorState,
4149
+ adapter: UiPrivateTargetBatchAdapterState,
4150
+ request: UiPrivateTargetBatchDependencyEventRequest,
4151
+ ): UiPrivateTargetBatchDependencyEventTransition {
4152
+ if (
4153
+ request.controlId !== adapter.controlId ||
4154
+ request.batchId !== adapter.batchId ||
4155
+ request.dependencyId !== adapter.dependencyId
4156
+ ) {
4157
+ throw new UiValueChannelInvariantError(
4158
+ 'private-target-batch-adapter-conflict',
4159
+ 'stage-private-target-batch-dependency-event',
4160
+ )
4161
+ }
4162
+ const transaction = coordinator.transaction
4163
+ if (transaction.kind !== 'OPEN') {
4164
+ throw new UiValueChannelInvariantError(
4165
+ 'private-target-batch-transaction-closed',
4166
+ 'stage-private-target-batch-dependency-event',
4167
+ )
4168
+ }
4169
+ const eventSequence = adapter.nextDependencyEventSequence
4170
+ return {
4171
+ adapter: {
4172
+ ...adapter,
4173
+ nextDependencyEventSequence: eventSequence + 1,
4174
+ stagedDependencyEventCount: adapter.stagedDependencyEventCount + 1,
4175
+ },
4176
+ orderedEffects: [
4177
+ {
4178
+ kind: 'PREFILL_PRIVATE_TARGET_BATCH_DEPENDENCY_EVENT',
4179
+ transactionMode: transaction.mode,
4180
+ event: {
4181
+ kind: 'TARGET_BATCH_DEPENDENCY_EVENT',
4182
+ batchId: adapter.batchId,
4183
+ dependencyId: adapter.dependencyId,
4184
+ dependencyEventKind: request.kind,
4185
+ eventSequence,
4186
+ ownerControlId: adapter.controlId,
4187
+ },
4188
+ },
4189
+ {
4190
+ kind: 'ADVANCE_PRIVATE_TARGET_BATCH_EVENT_SEQUENCE',
4191
+ controlId: adapter.controlId,
4192
+ eventSequence,
4193
+ },
4194
+ ],
4195
+ }
4196
+ }
4197
+
4198
+ // ——— Runner admission timeout and reselection ———
4199
+
4200
+ function staleRunnerEvent(
4201
+ state: UiRunnerAdmissionState,
4202
+ driverId: number,
4203
+ ): UiRunnerAdmissionTransition {
4204
+ return { state, orderedEffects: [{ kind: 'IGNORE_STALE_RUNNER_EVENT', driverId }] }
4205
+ }
4206
+
4207
+ function requireCurrentRunnerCandidate(
4208
+ state: UiRunnerAdmissionState,
4209
+ event: UiRunnerAdmissionEvent,
4210
+ ): UiRunnerAdmissionCandidateState | null {
4211
+ const candidate = state.candidates.find(
4212
+ (registration) => registration.driverId === event.driverId,
4213
+ )
4214
+ if (
4215
+ candidate === undefined ||
4216
+ candidate.state !== 'RUNNER_CANDIDATE' ||
4217
+ candidate.callbackRegistrationGeneration !== event.callbackRegistrationGeneration ||
4218
+ candidate.callbackLeaseEpoch !== event.callbackLeaseEpoch
4219
+ ) {
4220
+ return null
4221
+ }
4222
+ return candidate
4223
+ }
4224
+
4225
+ function transferRetainedChannels(
4226
+ state: UiRunnerAdmissionState,
4227
+ effects: UiRunnerAdmissionEffect[],
4228
+ retainedWorkRuntime: UiRunnerRetainedWorkRuntime,
4229
+ ): UiRunnerAdmissionState {
4230
+ let retainedWorkTransferRequestCount = state.retainedWorkTransferRequestCount
4231
+ for (const channel of state.retainedChannels) {
4232
+ retainedWorkRuntime.transferRetainedChannelWork(channel)
4233
+ effects.push({ kind: 'TRANSFER_RETAINED_CHANNEL_WORK', channel })
4234
+ retainedWorkTransferRequestCount += 1
4235
+ }
4236
+ return { ...state, retainedWorkTransferRequestCount }
4237
+ }
4238
+
4239
+ export function advanceUiRunnerAdmission(
4240
+ state: UiRunnerAdmissionState,
4241
+ event: UiRunnerAdmissionEvent,
4242
+ activators: UiRetainedFrameCallbackActivatorRegistry,
4243
+ retainedWorkRuntime: UiRunnerRetainedWorkRuntime,
4244
+ ): UiRunnerAdmissionTransition {
4245
+ switch (event.kind) {
4246
+ case 'runner-candidate-timeout': {
4247
+ const candidate = requireCurrentRunnerCandidate(state, event)
4248
+ if (candidate === null) return staleRunnerEvent(state, event.driverId)
4249
+ const effects: UiRunnerAdmissionEffect[] = [
4250
+ { kind: 'EXPIRE_RUNNER_CANDIDATE', driverId: event.driverId },
4251
+ ]
4252
+ activators.setActive(event.driverId, event.callbackRegistrationGeneration, false)
4253
+ const candidates = state.candidates.map((registration) =>
4254
+ registration.driverId === event.driverId
4255
+ ? { ...registration, state: 'EXPIRED' as const }
4256
+ : registration,
4257
+ )
4258
+ const successor = candidates.find(
4259
+ (registration) =>
4260
+ registration.driverId !== event.driverId && registration.state === 'RUNNER_CANDIDATE',
4261
+ )
4262
+ if (successor !== undefined) {
4263
+ activators.setActive(successor.driverId, successor.callbackRegistrationGeneration, true)
4264
+ effects.push({
4265
+ kind: 'SELECT_SUCCESSOR_RUNNER_CANDIDATE',
4266
+ driverId: successor.driverId,
4267
+ callbackLeaseEpoch: successor.callbackLeaseEpoch,
4268
+ })
4269
+ return {
4270
+ state: {
4271
+ ...state,
4272
+ candidates,
4273
+ runnerDriverId: successor.driverId,
4274
+ runnerLeaseEpoch: successor.callbackLeaseEpoch,
4275
+ },
4276
+ orderedEffects: effects,
4277
+ }
4278
+ }
4279
+ const channelIds = state.retainedChannels.map((channel) => channel.channelId)
4280
+ retainedWorkRuntime.reportFinalRunnerTimeoutRefusal(channelIds)
4281
+ effects.push({ kind: 'REPORT_FINAL_RUNNER_TIMEOUT_REFUSAL', channelIds })
4282
+ for (const channel of state.retainedChannels) {
4283
+ if (channel.installedPreArmControlSlot !== null) {
4284
+ retainedWorkRuntime.stopInstalledPreArmSlot(
4285
+ channel.channelId,
4286
+ channel.installedPreArmControlSlot,
4287
+ )
4288
+ effects.push({
4289
+ kind: 'STOP_INSTALLED_PRE_ARM_SLOT_ONLY',
4290
+ channelId: channel.channelId,
4291
+ slot: channel.installedPreArmControlSlot,
4292
+ })
4293
+ }
4294
+ }
4295
+ const transferred = transferRetainedChannels(
4296
+ {
4297
+ ...state,
4298
+ candidates,
4299
+ runnerDriverId: null,
4300
+ runnerLeaseEpoch: 0,
4301
+ timeoutRefusalCount: state.timeoutRefusalCount + 1,
4302
+ },
4303
+ effects,
4304
+ retainedWorkRuntime,
4305
+ )
4306
+ return { state: transferred, orderedEffects: effects }
4307
+ }
4308
+ case 'invoke-runner-candidate': {
4309
+ const candidate = requireCurrentRunnerCandidate(state, event)
4310
+ if (candidate === null) return staleRunnerEvent(state, event.driverId)
4311
+ const effects: UiRunnerAdmissionEffect[] = [
4312
+ {
4313
+ kind: 'ADMIT_INVOKED_RUNNER_CANDIDATE',
4314
+ driverId: event.driverId,
4315
+ callbackLeaseEpoch: candidate.callbackLeaseEpoch,
4316
+ },
4317
+ ]
4318
+ const admitted: UiRunnerAdmissionState = {
4319
+ ...state,
4320
+ candidates: state.candidates.map((registration) =>
4321
+ registration.driverId === event.driverId
4322
+ ? { ...registration, state: 'ADMITTED' as const, invocationObserved: true }
4323
+ : registration,
4324
+ ),
4325
+ runnerDriverId: event.driverId,
4326
+ runnerLeaseEpoch: candidate.callbackLeaseEpoch,
4327
+ }
4328
+ const transferred = transferRetainedChannels(admitted, effects, retainedWorkRuntime)
4329
+ return { state: transferred, orderedEffects: effects }
4330
+ }
4331
+ case 'dispose-runner-candidate': {
4332
+ const candidate = requireCurrentRunnerCandidate(state, event)
4333
+ if (candidate === null) return staleRunnerEvent(state, event.driverId)
4334
+ const effects: UiRunnerAdmissionEffect[] = [
4335
+ { kind: 'DISPOSE_RUNNER_CANDIDATE', driverId: event.driverId },
4336
+ ]
4337
+ activators.setActive(event.driverId, event.callbackRegistrationGeneration, false)
4338
+ const candidates = state.candidates.map((registration) =>
4339
+ registration.driverId === event.driverId
4340
+ ? { ...registration, state: 'DISPOSED' as const }
4341
+ : registration,
4342
+ )
4343
+ const successor = candidates.find(
4344
+ (registration) =>
4345
+ registration.driverId !== event.driverId && registration.state === 'RUNNER_CANDIDATE',
4346
+ )
4347
+ if (successor !== undefined) {
4348
+ activators.setActive(successor.driverId, successor.callbackRegistrationGeneration, true)
4349
+ effects.push({
4350
+ kind: 'SELECT_SUCCESSOR_RUNNER_CANDIDATE',
4351
+ driverId: successor.driverId,
4352
+ callbackLeaseEpoch: successor.callbackLeaseEpoch,
4353
+ })
4354
+ return {
4355
+ state: {
4356
+ ...state,
4357
+ candidates,
4358
+ runnerDriverId: successor.driverId,
4359
+ runnerLeaseEpoch: successor.callbackLeaseEpoch,
4360
+ },
4361
+ orderedEffects: effects,
4362
+ }
4363
+ }
4364
+ return {
4365
+ state: { ...state, candidates, runnerDriverId: null, runnerLeaseEpoch: 0 },
4366
+ orderedEffects: effects,
4367
+ }
4368
+ }
4369
+ default: {
4370
+ const exhaustive: never = event
4371
+ void exhaustive
4372
+ throw new UiValueChannelInvariantError('runner-admission-event-kind-unrecognized')
4373
+ }
4374
+ }
4375
+ }
4376
+
4377
+ // ——— Primitive listener-recursion reducer ———
4378
+
4379
+ /** Mutable working copy of one execution record; returned to the immutable state at the end. */
4380
+ interface UiRecursionWorkingExecution {
4381
+ executionId: number
4382
+ targetValue: number
4383
+ firstSampleValue: number
4384
+ commandSequence: number
4385
+ completionSequence: number
4386
+ updateSequence: number
4387
+ stopCount: number
4388
+ phase: UiRecursionExecutionPhase
4389
+ orphaned: boolean
4390
+ }
4391
+
4392
+ interface UiRecursionWorkingCancelListener {
4393
+ listenerId: number
4394
+ hasStartedSuccessor: boolean
4395
+ successor: UiRecursionExecutionSeed
4396
+ }
4397
+
4398
+ interface UiRecursionWorkingState {
4399
+ channelId: number
4400
+ currentValue: number
4401
+ publicControlSlotExecutionId: number | null
4402
+ executions: UiRecursionWorkingExecution[]
4403
+ queuedInstantCompletions: readonly UiQueuedInstantCompletionRecursionEntry[]
4404
+ guardedCancelListeners: UiRecursionWorkingCancelListener[]
4405
+ nextUpdateSequence: number
4406
+ cancelDeliveryOrdinal: number
4407
+ }
4408
+
4409
+ function installRecursionSuccessor(
4410
+ working: UiRecursionWorkingState,
4411
+ successor: UiRecursionExecutionSeed,
4412
+ role: Extract<
4413
+ UiValueChannelRecursionEffect,
4414
+ { readonly kind: 'INSTALL_RECURSION_EXECUTION' }
4415
+ >['role'],
4416
+ effects: UiValueChannelRecursionEffect[],
4417
+ ): void {
4418
+ if (working.publicControlSlotExecutionId !== null) {
4419
+ stopRecursionControl(working, working.publicControlSlotExecutionId, 'REENTRANT_START', effects)
4420
+ }
4421
+ const updateSequence = working.nextUpdateSequence
4422
+ working.nextUpdateSequence += 1
4423
+ effects.push({
4424
+ kind: 'INSTALL_RECURSION_EXECUTION',
4425
+ executionId: successor.executionId,
4426
+ commandSequence: successor.commandSequence,
4427
+ updateSequence,
4428
+ role,
4429
+ })
4430
+ working.executions.push({
4431
+ ...successor,
4432
+ updateSequence,
4433
+ stopCount: 0,
4434
+ phase: 'RUNNING',
4435
+ orphaned: false,
4436
+ })
4437
+ working.publicControlSlotExecutionId = successor.executionId
4438
+ }
4439
+
4440
+ function clearRecursionPublicSlotTokenBlind(
4441
+ working: UiRecursionWorkingState,
4442
+ source: 'INSTANT_COMPLETION' | 'STOP_CONTINUATION' | 'VALUE_COMPLETION',
4443
+ sourceId: number,
4444
+ effects: UiValueChannelRecursionEffect[],
4445
+ ): void {
4446
+ const clearedExecutionId = working.publicControlSlotExecutionId
4447
+ effects.push({
4448
+ kind: 'CLEAR_PUBLIC_CONTROL_SLOT_TOKEN_BLIND',
4449
+ source,
4450
+ sourceId,
4451
+ clearedExecutionId,
4452
+ })
4453
+ if (clearedExecutionId !== null) {
4454
+ const cleared = working.executions.find(
4455
+ (candidate) => candidate.executionId === clearedExecutionId,
4456
+ )
4457
+ if (cleared !== undefined) cleared.orphaned = true
4458
+ }
4459
+ working.publicControlSlotExecutionId = null
4460
+ }
4461
+
4462
+ function stopRecursionControl(
4463
+ working: UiRecursionWorkingState,
4464
+ controlExecutionId: number,
4465
+ source: 'OUTER_OPERATION' | 'REENTRANT_START',
4466
+ effects: UiValueChannelRecursionEffect[],
4467
+ ): void {
4468
+ const control = working.executions.find(
4469
+ (candidate) => candidate.executionId === controlExecutionId,
4470
+ )
4471
+ if (control !== undefined) {
4472
+ control.stopCount += 1
4473
+ control.phase = 'STOPPED'
4474
+ effects.push({
4475
+ kind: 'STOP_EXECUTION_IDEMPOTENT',
4476
+ executionId: controlExecutionId,
4477
+ stopOrdinal: control.stopCount,
4478
+ source,
4479
+ })
4480
+ }
4481
+ for (const listener of working.guardedCancelListeners) {
4482
+ if (listener.hasStartedSuccessor) continue
4483
+ listener.hasStartedSuccessor = true
4484
+ working.cancelDeliveryOrdinal += 1
4485
+ effects.push({
4486
+ kind: 'DELIVER_GUARDED_CANCEL_LISTENER',
4487
+ listenerId: listener.listenerId,
4488
+ cancelDeliveryOrdinal: working.cancelDeliveryOrdinal,
4489
+ })
4490
+ effects.push({
4491
+ kind: 'ISSUE_REENTRANT_START_COMMAND',
4492
+ executionId: listener.successor.executionId,
4493
+ commandSequence: listener.successor.commandSequence,
4494
+ source: 'GUARDED_CANCEL_LISTENER',
4495
+ sourceId: listener.listenerId,
4496
+ })
4497
+ installRecursionSuccessor(working, listener.successor, 'CANCEL_LISTENER_SUCCESSOR', effects)
4498
+ }
4499
+ clearRecursionPublicSlotTokenBlind(working, 'STOP_CONTINUATION', controlExecutionId, effects)
4500
+ }
4501
+
4502
+ export function advanceUiValueChannelRecursion(
4503
+ state: UiValueChannelRecursionState,
4504
+ event: UiValueChannelRecursionEvent,
4505
+ ): UiValueChannelRecursionTransition {
4506
+ const working: UiRecursionWorkingState = {
4507
+ channelId: state.channelId,
4508
+ currentValue: state.currentValue,
4509
+ publicControlSlotExecutionId: state.publicControlSlotExecutionId,
4510
+ executions: state.executions.map((execution) => ({ ...execution })),
4511
+ queuedInstantCompletions: state.queuedInstantCompletions,
4512
+ guardedCancelListeners: state.guardedCancelListeners.map((listener) => ({ ...listener })),
4513
+ nextUpdateSequence: state.nextUpdateSequence,
4514
+ cancelDeliveryOrdinal: 0,
4515
+ }
4516
+ const effects: UiValueChannelRecursionEffect[] = []
4517
+ switch (event.kind) {
4518
+ case 'drain-queued-instant-completions': {
4519
+ for (const queued of working.queuedInstantCompletions) {
4520
+ effects.push({
4521
+ kind: 'DELIVER_QUEUED_INSTANT_COMPLETION',
4522
+ completionId: queued.completionId,
4523
+ completionSequence: queued.completionSequence,
4524
+ })
4525
+ effects.push({
4526
+ kind: 'ISSUE_REENTRANT_START_COMMAND',
4527
+ executionId: queued.callbackSuccessor.executionId,
4528
+ commandSequence: queued.callbackSuccessor.commandSequence,
4529
+ source: 'INSTANT_COMPLETION',
4530
+ sourceId: queued.completionId,
4531
+ })
4532
+ installRecursionSuccessor(
4533
+ working,
4534
+ queued.callbackSuccessor,
4535
+ 'COMPLETION_SUCCESSOR',
4536
+ effects,
4537
+ )
4538
+ clearRecursionPublicSlotTokenBlind(
4539
+ working,
4540
+ 'INSTANT_COMPLETION',
4541
+ queued.completionId,
4542
+ effects,
4543
+ )
4544
+ }
4545
+ working.queuedInstantCompletions = []
4546
+ break
4547
+ }
4548
+ case 'apply-recursive-outer-stop': {
4549
+ if (working.publicControlSlotExecutionId !== null) {
4550
+ stopRecursionControl(
4551
+ working,
4552
+ working.publicControlSlotExecutionId,
4553
+ 'OUTER_OPERATION',
4554
+ effects,
4555
+ )
4556
+ }
4557
+ break
4558
+ }
4559
+ case 'apply-recursive-outer-jump': {
4560
+ if (working.publicControlSlotExecutionId !== null) {
4561
+ stopRecursionControl(
4562
+ working,
4563
+ working.publicControlSlotExecutionId,
4564
+ 'OUTER_OPERATION',
4565
+ effects,
4566
+ )
4567
+ }
4568
+ effects.push({ kind: 'APPLY_OUTER_JUMP', value: event.value })
4569
+ working.currentValue = event.value
4570
+ break
4571
+ }
4572
+ case 'apply-recursive-interrupting-start': {
4573
+ if (working.publicControlSlotExecutionId !== null) {
4574
+ stopRecursionControl(
4575
+ working,
4576
+ working.publicControlSlotExecutionId,
4577
+ 'OUTER_OPERATION',
4578
+ effects,
4579
+ )
4580
+ }
4581
+ installRecursionSuccessor(working, event.successor, 'INTERRUPTING_SUCCESSOR', effects)
4582
+ break
4583
+ }
4584
+ case 'install-recursion-successor': {
4585
+ installRecursionSuccessor(working, event.successor, 'LATER_LIVE_SUCCESSOR', effects)
4586
+ break
4587
+ }
4588
+ case 'sample-runnable-recursion-executions': {
4589
+ for (const execution of working.executions) {
4590
+ if (execution.phase !== 'RUNNING') continue
4591
+ effects.push({
4592
+ kind: 'SAMPLE_RECURSION_EXECUTION',
4593
+ executionId: execution.executionId,
4594
+ updateSequence: execution.updateSequence,
4595
+ value: execution.firstSampleValue,
4596
+ absoluteTimestampMs: event.absoluteTimestampMs,
4597
+ orphaned: execution.orphaned,
4598
+ })
4599
+ working.currentValue = execution.firstSampleValue
4600
+ }
4601
+ break
4602
+ }
4603
+ case 'complete-recursion-execution': {
4604
+ const execution = working.executions.find(
4605
+ (candidate) => candidate.executionId === event.executionId,
4606
+ )
4607
+ if (execution === undefined) {
4608
+ throw new UiValueChannelInvariantError(
4609
+ 'recursion-event-kind-unrecognized',
4610
+ 'complete-recursion-execution',
4611
+ )
4612
+ }
4613
+ execution.phase = 'COMPLETED'
4614
+ effects.push({
4615
+ kind: 'COMPLETE_RECURSION_EXECUTION',
4616
+ executionId: event.executionId,
4617
+ completionSequence: event.completionSequence,
4618
+ })
4619
+ clearRecursionPublicSlotTokenBlind(working, 'VALUE_COMPLETION', event.executionId, effects)
4620
+ break
4621
+ }
4622
+ default: {
4623
+ const exhaustive: never = event
4624
+ void exhaustive
4625
+ throw new UiValueChannelInvariantError('recursion-event-kind-unrecognized')
4626
+ }
4627
+ }
4628
+ return {
4629
+ state: {
4630
+ channelId: working.channelId,
4631
+ currentValue: working.currentValue,
4632
+ publicControlSlotExecutionId: working.publicControlSlotExecutionId,
4633
+ executions: working.executions,
4634
+ queuedInstantCompletions: working.queuedInstantCompletions,
4635
+ guardedCancelListeners: working.guardedCancelListeners,
4636
+ nextUpdateSequence: working.nextUpdateSequence,
4637
+ },
4638
+ orderedEffects: effects,
4639
+ }
4640
+ }