deepline 0.3.128 → 0.3.129

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 (128) hide show
  1. package/dist/bundling-sources/sdk/src/client.ts +34 -9
  2. package/dist/bundling-sources/sdk/src/http.ts +22 -0
  3. package/dist/bundling-sources/sdk/src/release.ts +1 -1
  4. package/dist/bundling-sources/shared_libs/play-data-plane/r2.ts +22 -0
  5. package/dist/bundling-sources/shared_libs/play-runtime/app-runtime-api.ts +265 -2
  6. package/dist/bundling-sources/shared_libs/play-runtime/bounded-batch-function.ts +682 -0
  7. package/dist/bundling-sources/shared_libs/play-runtime/child-execution-strategy.ts +21 -5
  8. package/dist/bundling-sources/shared_libs/play-runtime/context.ts +5390 -1732
  9. package/dist/bundling-sources/shared_libs/play-runtime/ctx-types.ts +107 -1
  10. package/dist/bundling-sources/shared_libs/play-runtime/deployment/commands/roll-execution-relay.ts +7 -0
  11. package/dist/bundling-sources/shared_libs/play-runtime/deployment/fly-machines.ts +229 -7
  12. package/dist/bundling-sources/shared_libs/play-runtime/deployment/fly-registry.ts +25 -4
  13. package/dist/bundling-sources/shared_libs/play-runtime/deployment/runtime-gateway-capacity.ts +71 -0
  14. package/dist/bundling-sources/shared_libs/play-runtime/deployment/runtime-gateway-drain.ts +1 -1
  15. package/dist/bundling-sources/shared_libs/play-runtime/deployment/runtime-topology.ts +4 -1
  16. package/dist/bundling-sources/shared_libs/play-runtime/durable-receipt-execution.ts +694 -28
  17. package/dist/bundling-sources/shared_libs/play-runtime/egress-bandwidth-probe.ts +167 -0
  18. package/dist/bundling-sources/shared_libs/play-runtime/execute-server-timing.ts +103 -0
  19. package/dist/bundling-sources/shared_libs/play-runtime/execution-gateway-receipt-output-reference.ts +34 -0
  20. package/dist/bundling-sources/shared_libs/play-runtime/execution-gateway-response-size.ts +27 -0
  21. package/dist/bundling-sources/shared_libs/play-runtime/gateway-postgres-admission.ts +66 -1
  22. package/dist/bundling-sources/shared_libs/play-runtime/governor/app-runtime-rate-state-backend.ts +425 -71
  23. package/dist/bundling-sources/shared_libs/play-runtime/governor/governor.ts +210 -32
  24. package/dist/bundling-sources/shared_libs/play-runtime/governor/in-memory-rate-state-backend.ts +27 -13
  25. package/dist/bundling-sources/shared_libs/play-runtime/governor/policy.ts +19 -6
  26. package/dist/bundling-sources/shared_libs/play-runtime/governor/rate-state-backend.ts +61 -2
  27. package/dist/bundling-sources/shared_libs/play-runtime/integration-operation-reader-fence/contracts.ts +33 -1
  28. package/dist/bundling-sources/shared_libs/play-runtime/integration-operation-reader-fence/job.ts +42 -1
  29. package/dist/bundling-sources/shared_libs/play-runtime/launch-source-policy.ts +11 -11
  30. package/dist/bundling-sources/shared_libs/play-runtime/ledger-safe-payload.ts +49 -16
  31. package/dist/bundling-sources/shared_libs/play-runtime/map-memory-limits.ts +1653 -98
  32. package/dist/bundling-sources/shared_libs/play-runtime/memory-ledger.ts +807 -0
  33. package/dist/bundling-sources/shared_libs/play-runtime/memory-pressure-signal.ts +138 -0
  34. package/dist/bundling-sources/shared_libs/play-runtime/output-size-limits.ts +85 -3
  35. package/dist/bundling-sources/shared_libs/play-runtime/persistence-latch.ts +60 -2
  36. package/dist/bundling-sources/shared_libs/play-runtime/play-run-recovery-policy.ts +46 -1
  37. package/dist/bundling-sources/shared_libs/play-runtime/play-runs/terminal/contracts.ts +2 -0
  38. package/dist/bundling-sources/shared_libs/play-runtime/play-runs/terminal/job.ts +1 -0
  39. package/dist/bundling-sources/shared_libs/play-runtime/play-runs/terminal/ports.ts +1 -0
  40. package/dist/bundling-sources/shared_libs/play-runtime/play-runs/terminal/postgres-adapter.ts +1 -0
  41. package/dist/bundling-sources/shared_libs/play-runtime/play-runtime-semantics.ts +70 -27
  42. package/dist/bundling-sources/shared_libs/play-runtime/protocol.ts +56 -0
  43. package/dist/bundling-sources/shared_libs/play-runtime/provider-capacity/adaptive-provider-capacity-controller.ts +192 -0
  44. package/dist/bundling-sources/shared_libs/play-runtime/provider-capacity/epoch-aimd-rate-controller.ts +194 -0
  45. package/dist/bundling-sources/shared_libs/play-runtime/provider-capacity/fixture-capacity-simulator.ts +220 -0
  46. package/dist/bundling-sources/shared_libs/play-runtime/provider-capacity/gradient2-concurrency-controller.ts +214 -0
  47. package/dist/bundling-sources/shared_libs/play-runtime/provider-capacity/provider-capacity-policy.ts +43 -0
  48. package/dist/bundling-sources/shared_libs/play-runtime/provider-capacity/provider-concurrency-policy.ts +30 -0
  49. package/dist/bundling-sources/shared_libs/play-runtime/provider-capacity/provider-rate-policy.ts +95 -0
  50. package/dist/bundling-sources/shared_libs/play-runtime/provider-capacity/provider-throttle-classifier.ts +40 -0
  51. package/dist/bundling-sources/shared_libs/play-runtime/resource-governor.ts +1535 -11
  52. package/dist/bundling-sources/shared_libs/play-runtime/run-failure.ts +49 -2
  53. package/dist/bundling-sources/shared_libs/play-runtime/run-ledger.ts +6 -1
  54. package/dist/bundling-sources/shared_libs/play-runtime/run-log-buffer.ts +55 -0
  55. package/dist/bundling-sources/shared_libs/play-runtime/runner-app/egress-probe.ts +221 -0
  56. package/dist/bundling-sources/shared_libs/play-runtime/runner-app/index.ts +339 -29
  57. package/dist/bundling-sources/shared_libs/play-runtime/runner-app/runtime-deadline.ts +28 -1
  58. package/dist/bundling-sources/shared_libs/play-runtime/runner-app/runtime-progress-push.ts +192 -165
  59. package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona-lifecycle.ts +6 -0
  60. package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona-payload-transport.ts +90 -5
  61. package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona-runtime-watchdog.ts +281 -6
  62. package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona.ts +27 -1
  63. package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/local-process.ts +19 -0
  64. package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/modal.ts +108 -0
  65. package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/runtime-sandbox-reconciliation.ts +40 -0
  66. package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/types.ts +11 -5
  67. package/dist/bundling-sources/shared_libs/play-runtime/runtime-actions.ts +30 -0
  68. package/dist/bundling-sources/shared_libs/play-runtime/runtime-api-compression.ts +276 -0
  69. package/dist/bundling-sources/shared_libs/play-runtime/runtime-api.ts +723 -115
  70. package/dist/bundling-sources/shared_libs/play-runtime/runtime-capacity-policy.ts +98 -2
  71. package/dist/bundling-sources/shared_libs/play-runtime/runtime-contract.ts +3 -2
  72. package/dist/bundling-sources/shared_libs/play-runtime/runtime-environment.ts +41 -4
  73. package/dist/bundling-sources/shared_libs/play-runtime/runtime-flow.ts +448 -0
  74. package/dist/bundling-sources/shared_libs/play-runtime/runtime-map-row-feed.ts +215 -0
  75. package/dist/bundling-sources/shared_libs/play-runtime/runtime-operation-contract.ts +11 -0
  76. package/dist/bundling-sources/shared_libs/play-runtime/runtime-receipt-store-adapter.ts +161 -14
  77. package/dist/bundling-sources/shared_libs/play-runtime/runtime-receipt-value.ts +184 -0
  78. package/dist/bundling-sources/shared_libs/play-runtime/runtime-receipt-writer.ts +607 -121
  79. package/dist/bundling-sources/shared_libs/play-runtime/runtime-sandbox-placement-policy.ts +4 -0
  80. package/dist/bundling-sources/shared_libs/play-runtime/runtime-sheet-row-writer.ts +21 -0
  81. package/dist/bundling-sources/shared_libs/play-runtime/sandbox-runs/contract.ts +15 -2
  82. package/dist/bundling-sources/shared_libs/play-runtime/sandbox-runs/runner-backend-adapter.ts +71 -14
  83. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/absurd-play-deploy-task.ts +2 -2
  84. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/absurd-runtime-worker.ts +288 -119
  85. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/absurd-shared.ts +8 -6
  86. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/absurd-worker-required-env.ts +28 -3
  87. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/canonical-integration-operation-store.ts +179 -0
  88. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/gateway-heavy-request-admission.ts +80 -2
  89. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/gateway-progress-registry.ts +31 -2
  90. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/integration-operation-store-contract.ts +104 -0
  91. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/integration-operation-value-reference.ts +47 -0
  92. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/integration-operation-value-retirement.ts +193 -0
  93. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/integration-operation-value-storage.ts +420 -0
  94. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/postgres-pool.ts +41 -0
  95. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/postgres-progress.ts +134 -3
  96. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/postgres-rate-state.ts +1657 -95
  97. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/postgres.ts +885 -73
  98. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/receipt-completion-coalescer.ts +452 -0
  99. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/receipt-gateway.ts +601 -42
  100. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/run-terminal-transition.ts +1 -0
  101. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/runtime-receipt-value-storage.ts +371 -0
  102. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/worker-resource-metrics.ts +86 -7
  103. package/dist/bundling-sources/shared_libs/play-runtime/secret-redaction.ts +153 -22
  104. package/dist/bundling-sources/shared_libs/play-runtime/tool-call/index.ts +1 -0
  105. package/dist/bundling-sources/shared_libs/play-runtime/tool-call/receipt-cohort.ts +188 -38
  106. package/dist/bundling-sources/shared_libs/play-runtime/tool-call/runtime-step-receipts-adapter.ts +28 -13
  107. package/dist/bundling-sources/shared_libs/play-runtime/tool-execute-retry-policy.ts +44 -1
  108. package/dist/bundling-sources/shared_libs/play-runtime/tool-result.ts +56 -4
  109. package/dist/bundling-sources/shared_libs/play-runtime/work-receipts.ts +2 -0
  110. package/dist/bundling-sources/shared_libs/plays/authoring-contract.ts +16 -10
  111. package/dist/bundling-sources/shared_libs/plays/dataset.ts +4 -1
  112. package/dist/cli/index.js +250 -38
  113. package/dist/cli/index.mjs +250 -38
  114. package/dist/{compiler-manifest-DfSnbCTW.d.mts → compiler-manifest-BIqRyj5m.d.mts} +1 -1
  115. package/dist/{compiler-manifest-DfSnbCTW.d.ts → compiler-manifest-BIqRyj5m.d.ts} +1 -1
  116. package/dist/index.d.mts +4 -2
  117. package/dist/index.d.ts +4 -2
  118. package/dist/index.js +231 -35
  119. package/dist/index.mjs +231 -35
  120. package/dist/install-integrity.json +31 -2
  121. package/dist/plays/bundle-play-file.d.mts +2 -2
  122. package/dist/plays/bundle-play-file.d.ts +2 -2
  123. package/dist/plays/bundle-play-file.mjs +65 -1
  124. package/dist/release.d.mts +1 -1
  125. package/dist/release.d.ts +1 -1
  126. package/dist/release.js +1 -1
  127. package/dist/release.mjs +1 -1
  128. package/package.json +1 -1
@@ -1,27 +1,346 @@
1
+ import type { RuntimeMapHeapAdmissionSnapshot } from './map-memory-limits';
2
+ import type {
3
+ RuntimeMemoryLedger,
4
+ RuntimeMemoryLedgerSnapshot,
5
+ } from './memory-ledger';
1
6
  import type {
2
7
  PlayExecutionGovernor,
8
+ ProviderPermit,
3
9
  WorkLease,
4
10
  } from './governor/governor';
11
+ import type {
12
+ ProviderConcurrencyGrant,
13
+ ProviderPacingGrant,
14
+ } from './governor/rate-state-backend';
15
+ import type { ExecuteServerTiming } from './execute-server-timing';
5
16
 
6
17
  export type RuntimeResourceLease = WorkLease;
18
+ export type RuntimeProviderPermit = ProviderPermit;
7
19
 
8
20
  export type RuntimeResourceObservation = {
9
21
  toolId?: string | null;
10
22
  providerResourceKey?: string | null;
23
+ /**
24
+ * Canonical pacing-provider bucket for fixture/report attribution. This is
25
+ * intentionally separate from `providerResourceKey`: the latter retains
26
+ * the tool-keyed physical-request facts that provenance-disabled fixtures
27
+ * need, while this joins admission and response residence under the bucket
28
+ * the shared controller actually permitted.
29
+ */
30
+ providerTelemetryKey?: string | null;
31
+ /**
32
+ * Read-only shared-controller state captured with the permit that admitted
33
+ * this physical request. Observation never adjusts rate or concurrency.
34
+ */
35
+ providerConcurrencyGrant?: ProviderConcurrencyGrant | null;
36
+ /** Effective shared-rate reading for every provider permit. */
37
+ providerPacingGrant?: ProviderPacingGrant | null;
38
+ /**
39
+ * Physical provider work already resident in this runtime when this request
40
+ * crossed the dispatch boundary. This is a bounded, run-local diagnostic;
41
+ * it never participates in provider admission or controller decisions.
42
+ */
43
+ providerRunInFlightAtDispatch?: number | null;
11
44
  rowEstimatedBytes?: number | null;
12
45
  rowAdmissionWaitMs?: number | null;
13
46
  toolAdmissionWaitMs?: number | null;
47
+ providerAdmissionWaitMs?: number | null;
48
+ externalExecutionWaitMs?: number | null;
14
49
  providerLatencyMs?: number | null;
50
+ /** Wait for the runner-to-app transport slot inside provider residence. */
51
+ transportSlotWaitMs?: number | null;
52
+ /** Fetch dispatch to response headers. */
53
+ fetchToHeadersMs?: number | null;
54
+ /** The execute route's own `Server-Timing` account of that same request. */
55
+ executeServerTiming?: ExecuteServerTiming | null;
56
+ /** Response headers to a fully read and parsed body. */
57
+ bodyReadMs?: number | null;
58
+ /** Sandbox-side simulated provider residence in fixture mode. */
59
+ fixtureDelayMs?: number | null;
15
60
  providerSuccess?: boolean;
16
61
  provider429?: boolean;
62
+ /**
63
+ * A Deepline relay/gateway concurrency shed (429 with the concurrency
64
+ * backpressure marker). Counted apart from provider 429s and never fed to
65
+ * provider pacing: the shed is our own admission, not the provider's.
66
+ */
67
+ concurrencyShedDelayMs?: number | null;
17
68
  retryAfterMs?: number | null;
18
69
  receiptLatencyMs?: number | null;
70
+ /** Per-dispatch-group receipt get+claim round trips in the hydration turn. */
71
+ receiptClaimMs?: number | null;
72
+ /**
73
+ * What a hydration turn queued for a slot on the bounded completed-receipt
74
+ * hydration lane, before the claim round trip inside the turn started
75
+ * counting. Observed once per call the turn is blocking, and an explicit
76
+ * zero for a turn that found the lane free, so the population is every call
77
+ * that took a turn rather than only the ones that queued.
78
+ */
79
+ receiptHydrationGateWaitMs?: number | null;
80
+ /**
81
+ * Time a provider response body waited for byte headroom before it was read.
82
+ * Headers have already arrived, so this is not provider residence.
83
+ */
84
+ providerBodyAdmissionWaitMs?: number | null;
85
+ /**
86
+ * A queued tool call's enqueue to the launch of the dispatch group that
87
+ * carries it: coalescing window, group and lane caps, and dispatcher passes.
88
+ */
89
+ dispatchQueueWaitMs?: number | null;
90
+ /**
91
+ * Wall inside one map row between a tool call's result reaching the resolver
92
+ * and that resolver's next enqueue — or the resolver returning. This is the
93
+ * row's own time: user code, cell serialization, checkpoint work.
94
+ */
95
+ rowResolverGapMs?: number | null;
96
+ /** One logical tool call's enqueue to its result delivery. */
97
+ toolCallLogicalWallMs?: number | null;
98
+ /**
99
+ * One provider call's fully read and parsed response body to the moment that
100
+ * call's result is handed back to the row that asked for it: receipt
101
+ * completion, result wrapping, and whatever the dispatcher does in between.
102
+ * Recorded only for a call that made a provider request — a cache hit and a
103
+ * follower deliver a body they never read.
104
+ */
105
+ resultDeliveryMs?: number | null;
106
+ /**
107
+ * Sub-phases of `resultDelivery`, in the order one call walks them. With
108
+ * `receiptCompletionQueue` and `receiptCompletionFlight` between them they
109
+ * partition the delivery interval, so a delivery nobody can explain is a
110
+ * named gap between two of these rather than an unmeasured whole.
111
+ *
112
+ * All five are observed ONCE PER CALL, for exactly the calls `resultDelivery`
113
+ * is observed for. A stage a given path does not have is recorded as an
114
+ * explicit `0` at the point where it would otherwise close — an always-fresh
115
+ * call has no receipt to publish, so its publication stages are zero rather
116
+ * than absent. A zero therefore means "this stage is not on this path", and a
117
+ * missing observation would mean the per-call means were taken over different
118
+ * populations and could not be summed against the whole.
119
+ *
120
+ * `deliveryWrap`: parsed provider body to the wrapped result existing —
121
+ * result metadata lookup, dataset attach, and the rest of what the module
122
+ * dispatcher does before it hands the result to its Tool Call job.
123
+ */
124
+ deliveryWrapMs?: number | null;
125
+ /**
126
+ * Wrapped result to this call's completion reaching the completion writer:
127
+ * the Tool Call job's return path, and then either the cohort's one-turn
128
+ * publication coalescing or — off the cohort, for a fenced, uncacheable, or
129
+ * natively batched call — the resolve site's own re-wrap and completion
130
+ * serialization. Every receipt-backed path measures it; only a call with no
131
+ * receipt at all records the explicit zero.
132
+ */
133
+ deliveryPublishWaitMs?: number | null;
134
+ /**
135
+ * This call's own receipt write settling to the row's pending tool call
136
+ * resolving: cohort group resolution or per-member presentation, and the
137
+ * resolver hand-back. Taken from the per-receipt settlement, never from the
138
+ * batch that carried it — a row waits for its own receipt to be durable.
139
+ */
140
+ deliveryResolveMs?: number | null;
141
+ /**
142
+ * Sub-phases of `receiptCompletionFlight`, which is otherwise one opaque
143
+ * batch launch to response. `flightSerialize` is the batch's pre-transport
144
+ * work — the queue and egress accounting, completion validation, and wire
145
+ * record construction; `flightTransport` is the completion request itself,
146
+ * request body through parsed response, measured on completion requests only
147
+ * rather than borrowed from `gatewayRoundTrip`, which every runtime API
148
+ * action shares; and `flightDecode` is everything after it, including a
149
+ * `reconcileIncomplete` durable read-back.
150
+ *
151
+ * Like `receiptCompletionFlight` itself, each is recorded once per RECEIPT in
152
+ * the batch rather than once per coalesced statement: every receipt inherits
153
+ * the flight of the batch that carried it, so these stay per-call phases
154
+ * comparable with the rest of the delivery partition.
155
+ */
156
+ flightSerializeMs?: number | null;
157
+ flightTransportMs?: number | null;
158
+ flightDecodeMs?: number | null;
159
+ /** Receipt gateway `Server-Timing` entries for one runtime API response. */
160
+ gatewayAuthLaunchMs?: number | null;
161
+ gatewayAuthVerifyMs?: number | null;
162
+ gatewayBodyParseMs?: number | null;
163
+ /** Gunzip of a compressed request body, inside `gatewayBodyParseMs`. */
164
+ gatewayBodyInflateMs?: number | null;
165
+ gatewayPoolWaitMs?: number | null;
166
+ /** Inside gatewayCallback: bounded R2 receipt-value persistence wall. */
167
+ gatewayReceiptValuePersistMs?: number | null;
168
+ gatewayCallbackMs?: number | null;
169
+ /** Client-measured wall of that same request, for the client/server split. */
170
+ gatewayRoundTripMs?: number | null;
171
+ /** Runner CPU-path wall before the request starts: JSON serialization once. */
172
+ gatewayRequestSerializeMs?: number | null;
173
+ /** Runner CPU-path wall before the request starts: request wire packing. */
174
+ gatewayRequestPackMs?: number | null;
175
+ /** The gateway's own account of its auth-session cache for that request. */
176
+ gatewayAuthSession?: 'hit' | 'miss' | 'coalesced' | 'unknown' | null;
177
+ /**
178
+ * Request body bytes for one runtime API request: what was serialized, and
179
+ * what actually went on the wire. Recorded for EVERY request, compressed or
180
+ * not, so the run-level ratio is taken over the whole population rather than
181
+ * the flattering subset. On a sandbox ~95 ms from the gateway it is the WIRE
182
+ * size, not the decoded size, that sets how many congestion-window round
183
+ * trips a request costs.
184
+ */
185
+ gatewayRequestRawBytes?: number | null;
186
+ gatewayRequestWireBytes?: number | null;
187
+ /** Completion enqueue to the launch of the batch that carries it. */
188
+ receiptCompletionQueueMs?: number | null;
189
+ /**
190
+ * Completion batch launch to its gateway response, recorded once per RECEIPT
191
+ * in that batch. Once per statement made it a mean over a different
192
+ * population than the per-call phases it partitions with, which on a 1000-row
193
+ * modal shape left most of `resultDelivery` owned by nothing.
194
+ */
195
+ receiptCompletionFlightMs?: number | null;
196
+ /**
197
+ * Completion responses that returned no stored receipt and had to be
198
+ * hydrated by a durable-store read-back.
199
+ */
200
+ receiptCompletionReadBacks?: number | null;
201
+ /** Wall for one batched durable receipt read-back after a compact ack. */
202
+ receiptCompletionReadBackMs?: number | null;
203
+ /** Compact `persisted` acknowledgements that reused the caller's live value. */
204
+ receiptCompletionLiveResultReuses?: number | null;
205
+ /** Cache-cohort completions that retained their already-live result. */
206
+ receiptCompletionLivePublicationResults?: number | null;
207
+ /** Compact `existing` acknowledgements naming an already-durable winner. */
208
+ receiptCompletionExistingWinners?: number | null;
209
+ /** Compact terminal acknowledgements from a gateway without a disposition. */
210
+ receiptCompletionLegacyAcknowledgements?: number | null;
211
+ /** Missing or malformed completion acknowledgement entries. */
212
+ receiptCompletionMissingAcknowledgements?: number | null;
213
+ /** A completion acknowledgement that was not terminal. */
214
+ receiptCompletionNonterminalAcknowledgements?: number | null;
215
+ /** Read-back entries that recovered a complete durable output. */
216
+ receiptCompletionReadBackRecovered?: number | null;
217
+ /** Read-back entries that still did not yield a complete durable output. */
218
+ receiptCompletionReadBackMissing?: number | null;
219
+ receiptEgressBatchSize?: number | null;
220
+ receiptEgressBytes?: number | null;
221
+ /** Bounded completion-writer state sampled at each state transition. */
222
+ receiptCompletionWriterInFlightBatches?: number | null;
223
+ receiptCompletionWriterQueued?: number | null;
224
+ receiptCompletionWriterBufferedItems?: number | null;
225
+ receiptCompletionWriterBufferedBytes?: number | null;
19
226
  sheetFlushLatencyMs?: number | null;
20
227
  sheetFlushBytes?: number | null;
21
- memoryBytes?: number | null;
22
228
  };
23
229
 
24
230
  export type RuntimeResourceSnapshot = {
231
+ /**
232
+ * Selected execute-route stages across every physical request that published
233
+ * the complete timing header. Kept once per run so mixed-provider fixtures
234
+ * cannot overflow the terminal metadata envelope.
235
+ */
236
+ executeRoute?: RuntimeExecuteRouteTiming;
237
+ phases: {
238
+ rowAdmission: RuntimePhaseDistribution;
239
+ providerAdmission: RuntimePhaseDistribution;
240
+ externalExecution: RuntimePhaseDistribution;
241
+ providerResidence: RuntimePhaseDistribution;
242
+ /**
243
+ * Sub-phases of providerResidence, so a slow call can be attributed:
244
+ * residence = fixtureDelay + transportSlotWait + fetchToHeaders + bodyRead
245
+ * + an unattributed remainder.
246
+ */
247
+ fixtureDelay: RuntimePhaseDistribution;
248
+ transportSlotWait: RuntimePhaseDistribution;
249
+ fetchToHeaders: RuntimePhaseDistribution;
250
+ bodyRead: RuntimePhaseDistribution;
251
+ /** Sampled setTimeout lateness, not a per-call phase. */
252
+ eventLoopLag: RuntimePhaseDistribution;
253
+ receiptSettlement: RuntimePhaseDistribution;
254
+ /**
255
+ * Sub-phases of receipt orchestration, which `receiptSettlement` alone
256
+ * cannot separate: the claim turn before provider work, the completion's
257
+ * wait for a batch, and that batch's own flight.
258
+ */
259
+ receiptClaim: RuntimePhaseDistribution;
260
+ /**
261
+ * The queue in front of `receiptClaim`. A bounded lane serializes
262
+ * completed-receipt payload expansion, so a shape whose receipts are large
263
+ * keeps the lane busy and its dispatch groups wait for a slot before their
264
+ * claim can start. That wall sits inside `toolCallLogicalWall` after
265
+ * `dispatchQueueWait` and before any provider work, and no other phase
266
+ * covers it, so a logical wall that residence and delivery cannot explain
267
+ * is read against this phase first.
268
+ *
269
+ * Charged to each call in the group whose turn it is — like
270
+ * `receiptCompletionFlight`, and unlike `receiptClaim`, which is recorded
271
+ * once per turn — so its per-call mean is over the same population as the
272
+ * wall it is subtracted from. The per-map `receipt_hydration_gate` log
273
+ * line still reports the turn-level view (turns, queued turns, and the
274
+ * lane's own total wait).
275
+ */
276
+ receiptHydrationGateWait: RuntimePhaseDistribution;
277
+ receiptCompletionQueue: RuntimePhaseDistribution;
278
+ receiptCompletionFlight: RuntimePhaseDistribution;
279
+ /** One durable read-back batch after a compact completion acknowledgement. */
280
+ receiptCompletionReadBack: RuntimePhaseDistribution;
281
+ rowPersistence: RuntimePhaseDistribution;
282
+ /**
283
+ * The three phases that account for a row's life OUTSIDE the per-call
284
+ * phases above. A modal shape whose measured per-call phases sum to a
285
+ * quarter of the wall a row spends per call is spending the rest either
286
+ * queued for a dispatch group (`dispatchQueueWait`) or inside its own
287
+ * resolver between calls (`rowResolverGap`); `toolCallLogicalWall` is the
288
+ * enqueue-to-delivery total those two must be checked against.
289
+ */
290
+ dispatchQueueWait: RuntimePhaseDistribution;
291
+ rowResolverGap: RuntimePhaseDistribution;
292
+ toolCallLogicalWall: RuntimePhaseDistribution;
293
+ /**
294
+ * The tail of `toolCallLogicalWall`: parsed provider body to the row's own
295
+ * result. `providerResidence` ends where this begins, so a logical wall
296
+ * that neither residence nor `dispatchQueueWait` explains is being spent
297
+ * here — receipt completion and delivery — rather than on the provider.
298
+ */
299
+ resultDelivery: RuntimePhaseDistribution;
300
+ /**
301
+ * The partition of `resultDelivery`, in call order:
302
+ * `deliveryWrap` + `deliveryPublishWait` + `receiptCompletionQueue` +
303
+ * `receiptCompletionFlight` + `deliveryResolve` = `resultDelivery`, and
304
+ * `flightSerialize` + `flightTransport` + `flightDecode` =
305
+ * `receiptCompletionFlight`. Every one of them is recorded for exactly the
306
+ * calls `resultDelivery` is — one that read a provider body of its own —
307
+ * counting the same population at the same per-call granularity: the
308
+ * publication phases are an explicit zero on a path without a receipt
309
+ * (always-fresh), they are measured at the resolve site on a receipt-backed
310
+ * path that does not reach the receipt cohort (fenced, uncacheable, or
311
+ * natively batched), and the flight and its three parts are recorded once
312
+ * per receipt rather than once per coalesced completion statement. The
313
+ * counts are therefore comparable on any shape, and a difference between
314
+ * the sum and the whole is a real gap rather than a sampling artifact.
315
+ */
316
+ deliveryWrap: RuntimePhaseDistribution;
317
+ deliveryPublishWait: RuntimePhaseDistribution;
318
+ deliveryResolve: RuntimePhaseDistribution;
319
+ flightSerialize: RuntimePhaseDistribution;
320
+ flightTransport: RuntimePhaseDistribution;
321
+ flightDecode: RuntimePhaseDistribution;
322
+ /**
323
+ * The receipt gateway's own `Server-Timing` account of a runtime API
324
+ * request, beside the client-measured wall of the same request
325
+ * (`gatewayRoundTrip`). The gateway's action duration starts AFTER
326
+ * authentication, so its logs cannot see `gatewayAuthLaunch`,
327
+ * `gatewayAuthVerify`, or `gatewayBodyParse`; a round trip far above the
328
+ * server-reported sum is network, and one that matches it is the gateway.
329
+ */
330
+ gatewayAuthLaunch: RuntimePhaseDistribution;
331
+ gatewayAuthVerify: RuntimePhaseDistribution;
332
+ gatewayBodyParse: RuntimePhaseDistribution;
333
+ /** Inside `gatewayBodyParse`, not beside it. Zero on uncompressed requests. */
334
+ gatewayBodyInflate: RuntimePhaseDistribution;
335
+ gatewayPoolWait: RuntimePhaseDistribution;
336
+ /** Inside `gatewayCallback`, never add it beside that total. */
337
+ gatewayReceiptValuePersist: RuntimePhaseDistribution;
338
+ gatewayCallback: RuntimePhaseDistribution;
339
+ gatewayRoundTrip: RuntimePhaseDistribution;
340
+ /** Runner-local work deliberately excluded from `gatewayRoundTrip`. */
341
+ gatewayRequestSerialize: RuntimePhaseDistribution;
342
+ gatewayRequestPack: RuntimePhaseDistribution;
343
+ };
25
344
  rows: {
26
345
  acquired: number;
27
346
  estimatedBytes: number;
@@ -36,16 +355,334 @@ export type RuntimeResourceSnapshot = {
36
355
  bytes: number;
37
356
  latencyMsEwma: number | null;
38
357
  };
358
+ resultEgress: {
359
+ batches: number;
360
+ receipts: number;
361
+ bytes: number;
362
+ maxBatchBytes: number | null;
363
+ /** High-water marks of the bounded completion writer for this run. */
364
+ writerPeakInFlightBatches: number;
365
+ writerPeakQueued: number;
366
+ writerPeakBufferedItems: number;
367
+ writerPeakBufferedBytes: number;
368
+ /**
369
+ * Receipts whose completion response carried no stored receipt and were
370
+ * hydrated by a second full read of the durable store.
371
+ */
372
+ readBacks: number;
373
+ /** Compact acknowledgements where this caller could reuse the live value. */
374
+ liveResultReuses: number;
375
+ /** Publish-only cache cohorts that retained their already-live value. */
376
+ livePublicationResults: number;
377
+ /** Compact acknowledgements naming an already-durable winner. */
378
+ existingWinners: number;
379
+ /** Compact acknowledgements from an older gateway without a disposition. */
380
+ legacyAcknowledgements: number;
381
+ /** Completion response entries that were absent or malformed. */
382
+ missingAcknowledgements: number;
383
+ /** Completion response entries that did not reach a terminal state. */
384
+ nonterminalAcknowledgements: number;
385
+ /** Read-back entries that did recover a complete durable output. */
386
+ readBackRecovered: number;
387
+ /** Read-back entries still missing a complete durable output. */
388
+ readBackMissing: number;
389
+ };
390
+ /** Relay concurrency sheds the runner paced on instead of failing rows. */
391
+ concurrencyShed: {
392
+ count: number;
393
+ delayMsEwma: number | null;
394
+ };
395
+ /**
396
+ * What the receipt gateway reported about itself, counted rather than timed.
397
+ * A miss rate near one means every runtime API request paid a fresh token
398
+ * verification, which the gateway's own action logs do not show.
399
+ */
400
+ gateway: {
401
+ authSession: {
402
+ hit: number;
403
+ miss: number;
404
+ coalesced: number;
405
+ unknown: number;
406
+ };
407
+ /**
408
+ * What the runtime API transport put on the wire across the run.
409
+ *
410
+ * `wireBytes / rawBytes` is the realized compression ratio, over every
411
+ * request rather than only the compressed ones. `count` is the denominator
412
+ * for both, so a readout can also state mean request size — the number the
413
+ * ~95 ms round trip is multiplied by.
414
+ */
415
+ requestBody: {
416
+ count: number;
417
+ rawBytes: number;
418
+ wireBytes: number;
419
+ };
420
+ };
39
421
  providers: Record<
40
422
  string,
41
423
  {
424
+ admission: RuntimePhaseTiming;
425
+ residence: RuntimePhaseTiming;
426
+ fetchToHeaders: RuntimePhaseTiming;
427
+ latencyMsEwma: number | null;
428
+ retryAfterMsEwma: number | null;
429
+ provider429Count: number;
430
+ }
431
+ >;
432
+ /**
433
+ * Capped, canonical-provider attribution. Unlike `providers`, each entry
434
+ * joins permit wait and provider residence for one controller bucket, so a
435
+ * fixture readout can show where external response time went without
436
+ * conflating an admission key with a tool id.
437
+ */
438
+ providerAttribution: Record<
439
+ string,
440
+ {
441
+ admission: RuntimePhaseTiming;
442
+ residence: RuntimePhaseTiming;
443
+ fixtureDelay: RuntimePhaseTiming;
444
+ transportSlotWait: RuntimePhaseTiming;
445
+ fetchToHeaders: RuntimePhaseTiming;
446
+ bodyRead: RuntimePhaseTiming;
447
+ /** Local response-body byte-admission total in milliseconds. */
448
+ gateMs: number;
449
+ controller: {
450
+ /** Physical requests whose permit carried shared-controller context. */
451
+ permits: number;
452
+ /** Bucket occupancy captured before the request joined it. */
453
+ inFlightAtPermit: RuntimeSampleTiming;
454
+ /**
455
+ * Run-local physical provider work already resident when dispatch
456
+ * began. Unlike `inFlightAtPermit`, this is available to pure-rate
457
+ * buckets that deliberately have no shared concurrency lease.
458
+ */
459
+ runInFlightAtDispatch: RuntimeSampleTiming;
460
+ /** Null when the active rate backend did not publish a reading. */
461
+ targetRequestsPerSecondEwma: number | null;
462
+ minimumRttMsEwma: number | null;
463
+ };
42
464
  latencyMsEwma: number | null;
43
465
  retryAfterMsEwma: number | null;
44
466
  provider429Count: number;
45
467
  }
46
468
  >;
469
+ /**
470
+ * Process-level cost at snapshot time. On a 1 vCPU sandbox, cpu user+system
471
+ * milliseconds divided by the map wall is the runtime's own CPU floor.
472
+ */
473
+ process: {
474
+ cpuUserMs: number;
475
+ cpuSystemMs: number;
476
+ rssBytes: number | null;
477
+ maxRssBytes: number | null;
478
+ heapUsedBytes: number | null;
479
+ externalBytes: number | null;
480
+ } | null;
481
+ /** Final heap-admission state of each map, keyed by table namespace. */
482
+ mapAdmission: Record<string, RuntimeMapHeapAdmissionSnapshot>;
483
+ /**
484
+ * The runtime's byte ledger: what it says it is holding, how that compares
485
+ * to what the process reports, and how often admission had to hold. Null
486
+ * when no ledger is attached to this governor.
487
+ */
488
+ memory: RuntimeMemorySnapshot | null;
489
+ };
490
+
491
+ /**
492
+ * The ledger plus the admission counters that say how often bytes actually
493
+ * constrained the map. `predictedLiveBytes` diverging from `observedLiveBytes`
494
+ * by more than the calibration factor explains is the signal that the runtime
495
+ * is retaining bytes nothing registered.
496
+ */
497
+ export type RuntimeMemorySnapshot = RuntimeMemoryLedgerSnapshot & {
498
+ /** Probes, across every map, that paused new row admission under pressure. */
499
+ admissionHolds: number;
500
+ /** Watchdog memory-pressure signals delivered to admission. */
501
+ externalPressureSignals: number;
502
+ /** Live-memory or RSS pressure episodes admission observed. */
503
+ memoryPressureEvents: number;
504
+ };
505
+
506
+ /** Aggregate phase timing from the runner's monotonic clock. */
507
+ export type RuntimePhaseTiming = {
508
+ count: number;
509
+ totalMs: number;
510
+ maxMs: number | null;
511
+ ewmaMs: number | null;
512
+ };
513
+
514
+ /**
515
+ * Selected execute-route stages for the same population as `fetchToHeaders`.
516
+ * These are nested because they partition handler work inside that wall; they
517
+ * must never be added to provider residence as independent phases.
518
+ */
519
+ export type RuntimeExecuteRouteTiming = {
520
+ /** Every selected stage was present for this many physical requests. */
521
+ count: number;
522
+ totalMs: number;
523
+ chargeOpenMs: number;
524
+ fixtureLoadMs: number;
525
+ executeMs: number;
526
+ /**
527
+ * Where `chargeOpenMs` went, nested rather than summed: these are disjoint
528
+ * slices of it, never independent phases. Present only when the deployed app
529
+ * publishes the complete substage set, so a rolling deploy cannot build this
530
+ * sum over a different request population than `chargeOpenMs` itself.
531
+ */
532
+ chargeOpen?: {
533
+ count: number;
534
+ eligibilityMs: number;
535
+ capPreflightMs: number;
536
+ openMutationMs: number;
537
+ /** Wall slept in admission retry backoff: same-org OCC contention. */
538
+ retryWaitMs: number;
539
+ };
540
+ /**
541
+ * The execution gateway's own response-path timing, nested beside the app
542
+ * handler rather than summed into it. `upstreamHeadersMs` contains the
543
+ * handler `total`, which exposes the bounded relay-to-app platform/transit
544
+ * residual without claiming it is all network time.
545
+ */
546
+ gateway?: {
547
+ count: number;
548
+ authLaunchMs: number;
549
+ authVerifyMs: number;
550
+ bodyParseMs: number;
551
+ dispatchPoolMs: number;
552
+ dispatchCallbackMs: number;
553
+ /** Relay fetch issuance -> app response headers; contains handler total. */
554
+ upstreamHeadersMs: number;
555
+ /** App headers -> relay's fully buffered upstream body. */
556
+ upstreamBodyMs: number;
557
+ };
558
+ };
559
+
560
+ /**
561
+ * A compact, unitless sample aggregate. Provider permits use it for bucket
562
+ * occupancy at admission, rather than mislabelling an in-flight count as ms.
563
+ */
564
+ export type RuntimeSampleTiming = {
565
+ count: number;
566
+ total: number;
567
+ max: number | null;
568
+ ewma: number | null;
569
+ };
570
+
571
+ /**
572
+ * A fixture can touch many tool ids, but it should never make terminal
573
+ * diagnostics grow with unbounded provider cardinality. Keep the canonical
574
+ * attribution view useful for a multi-provider Play while rolling additional
575
+ * named buckets into a named remainder.
576
+ */
577
+ // This record travels inside the fixed 32 KiB terminal metadata envelope.
578
+ // Eleven named controller buckets plus `other` exactly fill the twelve rows
579
+ // the fixture readout renders; the remainder preserves all physical work
580
+ // without allowing a mixed-provider run to drop every runtime diagnostic.
581
+ const MAX_PROVIDER_ATTRIBUTION_BUCKETS = 11;
582
+ const PROVIDER_ATTRIBUTION_OTHER_KEY = 'other';
583
+
584
+ /**
585
+ * One non-zero histogram bucket, as `[bucketIndex, count]`.
586
+ *
587
+ * Only non-zero buckets are emitted. A dense 18-entry array per phase would
588
+ * cost the terminal metadata record several kilobytes it does not have; a
589
+ * phase's durations in practice occupy a handful of adjacent buckets.
590
+ */
591
+ export type RuntimePhaseHistogramBucket = [bucketIndex: number, count: number];
592
+
593
+ /**
594
+ * A phase timing plus the shape of its durations.
595
+ *
596
+ * A mean is dragged by the tail: one 13 s stall inside a thousand 150 ms calls
597
+ * moves it as far as adding 13 ms to every call, and those two facts call for
598
+ * opposite fixes. The percentiles separate them. They are bucket-resolution
599
+ * estimates — the bucket that holds the rank, interpolated linearly across
600
+ * that bucket's width — so they place a value inside a power-of-two band and
601
+ * never claim millisecond accuracy. No estimate exceeds the observed `maxMs`.
602
+ */
603
+ export type RuntimePhaseDistribution = RuntimePhaseTiming & {
604
+ p50Ms: number | null;
605
+ p90Ms: number | null;
606
+ p99Ms: number | null;
607
+ /** Non-zero log2 buckets, ascending, as `[bucketIndex, count]` pairs. */
608
+ buckets: RuntimePhaseHistogramBucket[];
47
609
  };
48
610
 
611
+ /**
612
+ * The fixed log2 duration histogram every phase records into.
613
+ *
614
+ * Bucket 0 holds everything under 1 ms, bucket `i` in 1..16 holds
615
+ * `[2^(i-1), 2^i)` ms, and bucket 17 holds everything at or above 65,536 ms.
616
+ * The bounds never move with the data, so two runs' buckets are directly
617
+ * comparable and a readout can draw them without carrying a schema.
618
+ */
619
+ export const RUNTIME_PHASE_HISTOGRAM_BUCKET_COUNT = 18;
620
+ export const RUNTIME_PHASE_HISTOGRAM_OVERFLOW_LOWER_MS = 65_536;
621
+
622
+ /** The bucket a duration in milliseconds falls in. */
623
+ export function runtimePhaseHistogramBucketIndex(valueMs: number): number {
624
+ if (!(valueMs >= 1)) return 0;
625
+ const floored = Math.floor(valueMs);
626
+ if (floored >= RUNTIME_PHASE_HISTOGRAM_OVERFLOW_LOWER_MS) {
627
+ return RUNTIME_PHASE_HISTOGRAM_BUCKET_COUNT - 1;
628
+ }
629
+ // For a positive 32-bit integer, 32 - clz32(n) is floor(log2(n)) + 1, which
630
+ // is exact where Math.log2 would need a rounding argument at the bounds.
631
+ return 32 - Math.clz32(floored);
632
+ }
633
+
634
+ /** The half-open `[lowerMs, upperMs)` a bucket covers; the last is open-ended. */
635
+ export function runtimePhaseHistogramBucketBoundsMs(index: number): {
636
+ lowerMs: number;
637
+ upperMs: number | null;
638
+ } {
639
+ if (index <= 0) return { lowerMs: 0, upperMs: 1 };
640
+ if (index >= RUNTIME_PHASE_HISTOGRAM_BUCKET_COUNT - 1) {
641
+ return {
642
+ lowerMs: RUNTIME_PHASE_HISTOGRAM_OVERFLOW_LOWER_MS,
643
+ upperMs: null,
644
+ };
645
+ }
646
+ return { lowerMs: 2 ** (index - 1), upperMs: 2 ** index };
647
+ }
648
+
649
+ /**
650
+ * A bucket-resolution percentile estimate over a log2 histogram.
651
+ *
652
+ * Walks the buckets to the one holding rank `quantile * count`, then
653
+ * interpolates linearly across that bucket. The open-ended top bucket
654
+ * interpolates toward the observed maximum, and the estimate is capped at that
655
+ * maximum so a reader never sees a percentile above a value that happened.
656
+ */
657
+ export function runtimePhaseHistogramPercentileMs(input: {
658
+ buckets: readonly number[];
659
+ count: number;
660
+ maxMs: number | null;
661
+ quantile: number;
662
+ }): number | null {
663
+ if (input.count <= 0) return null;
664
+ const rank = input.quantile * input.count;
665
+ let cumulative = 0;
666
+ for (let index = 0; index < input.buckets.length; index += 1) {
667
+ const bucketCount = input.buckets[index] ?? 0;
668
+ if (bucketCount <= 0) continue;
669
+ if (cumulative + bucketCount < rank) {
670
+ cumulative += bucketCount;
671
+ continue;
672
+ }
673
+ const bounds = runtimePhaseHistogramBucketBoundsMs(index);
674
+ const upperMs =
675
+ bounds.upperMs ?? Math.max(bounds.lowerMs, input.maxMs ?? bounds.lowerMs);
676
+ const position = Math.min(
677
+ 1,
678
+ Math.max(0, (rank - cumulative) / bucketCount),
679
+ );
680
+ const estimate = bounds.lowerMs + (upperMs - bounds.lowerMs) * position;
681
+ return input.maxMs === null ? estimate : Math.min(estimate, input.maxMs);
682
+ }
683
+ return input.maxMs;
684
+ }
685
+
49
686
  export interface RuntimeResourceGovernor {
50
687
  acquireRow(input?: {
51
688
  estimatedBytes?: number | null;
@@ -58,10 +695,49 @@ export interface RuntimeResourceGovernor {
58
695
  estimatedCost?: number | null;
59
696
  signal?: AbortSignal;
60
697
  }): Promise<RuntimeResourceLease>;
698
+ /** Bound only the active provider execution; the caller owns its budget charge. */
699
+ acquireExternalExecutionSlot(input?: {
700
+ providerResourceKey?: string | null;
701
+ signal?: AbortSignal;
702
+ }): Promise<RuntimeResourceLease>;
703
+ /**
704
+ * Non-blocking external-capacity probe used at a due provider ticket. A
705
+ * caller that misses this probe must re-admit instead of dispatching late.
706
+ */
707
+ tryAcquireExternalExecutionSlot(input?: {
708
+ providerResourceKey?: string | null;
709
+ }): RuntimeResourceLease | null;
710
+ chargeToolCall(): Promise<void>;
61
711
  acquireProviderPermit(input: {
62
712
  toolId: string;
63
713
  signal?: AbortSignal;
64
- }): Promise<RuntimeResourceLease>;
714
+ }): Promise<RuntimeProviderPermit>;
715
+ /**
716
+ * Non-blocking provider admission from capacity this process already holds.
717
+ * Safe to probe while holding an external execution slot; null means the
718
+ * caller must release that slot and re-admit through the blocking path.
719
+ */
720
+ tryAcquireProviderPermit(input: {
721
+ toolId: string;
722
+ }): RuntimeProviderPermit | null;
723
+ /**
724
+ * Observe one physical provider request's run-local residence. This is not
725
+ * a permit: it cannot block, queue, or widen capacity. Callers must release
726
+ * it exactly when the response body is terminal.
727
+ */
728
+ beginProviderExecution(input: {
729
+ providerResourceKey?: string | null;
730
+ providerTelemetryKey?: string | null;
731
+ }): {
732
+ providerTelemetryKey: string;
733
+ inFlightAtDispatch: number;
734
+ release(): void;
735
+ };
736
+ /**
737
+ * Probe app transport capacity at the physical provider-dispatch edge. A
738
+ * caller that misses it must cancel and re-admit its provider ticket.
739
+ */
740
+ tryAcquireIntegrationRequestSlot(): RuntimeResourceLease | null;
65
741
  suggestedToolParallelism(toolId: string, fallback: number): Promise<number>;
66
742
  suggestedDirectToolParallelism(
67
743
  toolId: string,
@@ -72,9 +748,24 @@ export interface RuntimeResourceGovernor {
72
748
  provider: string;
73
749
  toolId?: string;
74
750
  retryAfterMs: number;
751
+ /** Provider residence for the rejected physical request, when observed. */
752
+ latencyMs?: number | null;
753
+ /** Server-authored context for attributing this physical provider 429. */
754
+ concurrencyGrant?: ProviderConcurrencyGrant | null;
75
755
  }): Promise<void>;
76
756
  observe(input: RuntimeResourceObservation): void;
77
757
  snapshot(): RuntimeResourceSnapshot;
758
+ /** Stop the event-loop lag sampler. The timer is unref'd either way. */
759
+ stopSampling(): void;
760
+ /** Smoothed event-loop lag from the sampler, or null before its first tick. */
761
+ eventLoopLagEwmaMs(): number | null;
762
+ /** Retain a closed map's admission snapshot for the terminal summary. */
763
+ recordMapAdmission(
764
+ mapName: string,
765
+ snapshot: RuntimeMapHeapAdmissionSnapshot,
766
+ ): void;
767
+ /** The byte ledger every retention site registers against, if attached. */
768
+ readonly memoryLedger: RuntimeMemoryLedger | null;
78
769
  }
79
770
 
80
771
  type Ewma = {
@@ -97,10 +788,121 @@ function createEwma(alpha = 0.2): Ewma {
97
788
  };
98
789
  }
99
790
 
791
+ function createPhaseTiming(): {
792
+ observe(value: number | null | undefined): void;
793
+ snapshot(): RuntimePhaseTiming;
794
+ distribution(): RuntimePhaseDistribution;
795
+ } {
796
+ const ewma = createEwma();
797
+ const buckets = new Array<number>(RUNTIME_PHASE_HISTOGRAM_BUCKET_COUNT).fill(
798
+ 0,
799
+ );
800
+ let count = 0;
801
+ let totalMs = 0;
802
+ let maxMs: number | null = null;
803
+ return {
804
+ observe(value) {
805
+ if (value == null || !Number.isFinite(value)) return;
806
+ const normalized = Math.max(0, value);
807
+ count += 1;
808
+ totalMs += normalized;
809
+ maxMs = maxMs === null ? normalized : Math.max(maxMs, normalized);
810
+ ewma.observe(normalized);
811
+ const bucket = runtimePhaseHistogramBucketIndex(normalized);
812
+ buckets[bucket] = (buckets[bucket] ?? 0) + 1;
813
+ },
814
+ snapshot() {
815
+ return { count, totalMs, maxMs, ewmaMs: ewma.value };
816
+ },
817
+ distribution() {
818
+ const percentile = (quantile: number) =>
819
+ runtimePhaseHistogramPercentileMs({
820
+ buckets,
821
+ count,
822
+ maxMs,
823
+ quantile,
824
+ });
825
+ return {
826
+ count,
827
+ totalMs,
828
+ maxMs,
829
+ ewmaMs: ewma.value,
830
+ p50Ms: percentile(0.5),
831
+ p90Ms: percentile(0.9),
832
+ p99Ms: percentile(0.99),
833
+ buckets: buckets.flatMap((bucketCount, index) =>
834
+ bucketCount > 0
835
+ ? [[index, bucketCount] as RuntimePhaseHistogramBucket]
836
+ : [],
837
+ ),
838
+ };
839
+ },
840
+ };
841
+ }
842
+
843
+ function createSampleTiming(): {
844
+ observe(value: number | null | undefined): void;
845
+ snapshot(): RuntimeSampleTiming;
846
+ } {
847
+ const ewma = createEwma();
848
+ let count = 0;
849
+ let total = 0;
850
+ let max: number | null = null;
851
+ return {
852
+ observe(value) {
853
+ if (value == null || !Number.isFinite(value)) return;
854
+ const normalized = Math.max(0, value);
855
+ count += 1;
856
+ total += normalized;
857
+ max = max === null ? normalized : Math.max(max, normalized);
858
+ ewma.observe(normalized);
859
+ },
860
+ snapshot() {
861
+ return { count, total, max, ewma: ewma.value };
862
+ },
863
+ };
864
+ }
865
+
866
+ /** Sampling cadence for runner event-loop lateness. */
867
+ const EVENT_LOOP_LAG_SAMPLE_INTERVAL_MS = 500;
868
+
100
869
  function elapsedSince(startedAt: number): number {
101
870
  return Math.max(0, Date.now() - startedAt);
102
871
  }
103
872
 
873
+ function readProcessUsage(): RuntimeResourceSnapshot['process'] {
874
+ try {
875
+ const cpu = process.cpuUsage();
876
+ const memory = process.memoryUsage();
877
+ const resources =
878
+ typeof process.resourceUsage === 'function'
879
+ ? process.resourceUsage()
880
+ : null;
881
+ const finite = (value: unknown): number | null =>
882
+ typeof value === 'number' && Number.isFinite(value) && value >= 0
883
+ ? value
884
+ : null;
885
+ // maxRSS is reported in kibibytes on Linux and bytes on macOS; the sandbox
886
+ // is Linux, and the snapshot names the unit it stores.
887
+ const maxRssRaw = finite(resources?.maxRSS);
888
+ return {
889
+ cpuUserMs: Math.round(cpu.user / 1_000),
890
+ cpuSystemMs: Math.round(cpu.system / 1_000),
891
+ rssBytes: finite(memory.rss),
892
+ maxRssBytes:
893
+ maxRssRaw === null
894
+ ? null
895
+ : process.platform === 'darwin'
896
+ ? maxRssRaw
897
+ : maxRssRaw * 1024,
898
+ heapUsedBytes: finite(memory.heapUsed),
899
+ externalBytes: finite(memory.external),
900
+ };
901
+ } catch {
902
+ return null;
903
+ }
904
+ }
905
+
104
906
  function resourceKey(input?: string | null): string {
105
907
  const trimmed = input?.trim();
106
908
  return trimmed || 'unknown';
@@ -108,13 +910,129 @@ function resourceKey(input?: string | null): string {
108
910
 
109
911
  export function createRuntimeResourceGovernor(input: {
110
912
  executionGovernor: PlayExecutionGovernor;
913
+ /**
914
+ * The runtime's byte ledger. Attached by the Play Context so the terminal
915
+ * summary carries what the runner was actually holding, not only what the
916
+ * process happened to report at snapshot time.
917
+ */
918
+ memoryLedger?: RuntimeMemoryLedger | null;
111
919
  }): RuntimeResourceGovernor {
112
920
  const rowAdmissionWait = createEwma();
113
921
  const toolAdmissionWait = createEwma();
114
922
  const sheetFlushLatency = createEwma();
923
+ const phases = {
924
+ rowAdmission: createPhaseTiming(),
925
+ providerAdmission: createPhaseTiming(),
926
+ externalExecution: createPhaseTiming(),
927
+ providerResidence: createPhaseTiming(),
928
+ fixtureDelay: createPhaseTiming(),
929
+ transportSlotWait: createPhaseTiming(),
930
+ fetchToHeaders: createPhaseTiming(),
931
+ bodyRead: createPhaseTiming(),
932
+ eventLoopLag: createPhaseTiming(),
933
+ receiptSettlement: createPhaseTiming(),
934
+ receiptClaim: createPhaseTiming(),
935
+ receiptHydrationGateWait: createPhaseTiming(),
936
+ receiptCompletionQueue: createPhaseTiming(),
937
+ receiptCompletionFlight: createPhaseTiming(),
938
+ receiptCompletionReadBack: createPhaseTiming(),
939
+ rowPersistence: createPhaseTiming(),
940
+ dispatchQueueWait: createPhaseTiming(),
941
+ rowResolverGap: createPhaseTiming(),
942
+ toolCallLogicalWall: createPhaseTiming(),
943
+ resultDelivery: createPhaseTiming(),
944
+ deliveryWrap: createPhaseTiming(),
945
+ deliveryPublishWait: createPhaseTiming(),
946
+ deliveryResolve: createPhaseTiming(),
947
+ flightSerialize: createPhaseTiming(),
948
+ flightTransport: createPhaseTiming(),
949
+ flightDecode: createPhaseTiming(),
950
+ gatewayAuthLaunch: createPhaseTiming(),
951
+ gatewayAuthVerify: createPhaseTiming(),
952
+ gatewayBodyParse: createPhaseTiming(),
953
+ gatewayBodyInflate: createPhaseTiming(),
954
+ gatewayPoolWait: createPhaseTiming(),
955
+ gatewayReceiptValuePersist: createPhaseTiming(),
956
+ gatewayCallback: createPhaseTiming(),
957
+ gatewayRoundTrip: createPhaseTiming(),
958
+ gatewayRequestSerialize: createPhaseTiming(),
959
+ gatewayRequestPack: createPhaseTiming(),
960
+ };
961
+ const executeRoute: RuntimeExecuteRouteTiming = {
962
+ count: 0,
963
+ totalMs: 0,
964
+ chargeOpenMs: 0,
965
+ fixtureLoadMs: 0,
966
+ executeMs: 0,
967
+ };
968
+ const executeChargeOpen = {
969
+ count: 0,
970
+ eligibilityMs: 0,
971
+ capPreflightMs: 0,
972
+ openMutationMs: 0,
973
+ retryWaitMs: 0,
974
+ };
975
+ const executeGateway = {
976
+ count: 0,
977
+ authLaunchMs: 0,
978
+ authVerifyMs: 0,
979
+ bodyParseMs: 0,
980
+ dispatchPoolMs: 0,
981
+ dispatchCallbackMs: 0,
982
+ upstreamHeadersMs: 0,
983
+ upstreamBodyMs: 0,
984
+ };
985
+ const gatewayAuthSessionCounters = {
986
+ hit: 0,
987
+ miss: 0,
988
+ coalesced: 0,
989
+ unknown: 0,
990
+ };
991
+ const gatewayRequestBodyCounters = {
992
+ count: 0,
993
+ rawBytes: 0,
994
+ wireBytes: 0,
995
+ };
115
996
  const providers = new Map<
116
997
  string,
117
998
  {
999
+ admission: ReturnType<typeof createPhaseTiming>;
1000
+ residence: ReturnType<typeof createPhaseTiming>;
1001
+ fixtureDelay: ReturnType<typeof createPhaseTiming>;
1002
+ transportSlotWait: ReturnType<typeof createPhaseTiming>;
1003
+ fetchToHeaders: ReturnType<typeof createPhaseTiming>;
1004
+ bodyRead: ReturnType<typeof createPhaseTiming>;
1005
+ bodyAdmissionWait: ReturnType<typeof createPhaseTiming>;
1006
+ controllerPermits: number;
1007
+ inFlightAtPermit: ReturnType<typeof createSampleTiming>;
1008
+ targetRequestsPerSecond: Ewma;
1009
+ minimumRttMs: Ewma;
1010
+ latency: Ewma;
1011
+ retryAfter: Ewma;
1012
+ provider429Count: number;
1013
+ }
1014
+ >();
1015
+ // This tracker mirrors the capped terminal attribution names. It is a
1016
+ // measurement of work that entered provider residence, not another
1017
+ // admission mechanism. Reservations prevent a burst of distinct providers
1018
+ // from making the tracker grow before their terminal observations arrive.
1019
+ const providerAttributionReservations = new Set<string>();
1020
+ const activeProviderExecutions = new Map<string, number>();
1021
+ const providerAttribution = new Map<
1022
+ string,
1023
+ {
1024
+ admission: ReturnType<typeof createPhaseTiming>;
1025
+ residence: ReturnType<typeof createPhaseTiming>;
1026
+ fixtureDelay: ReturnType<typeof createPhaseTiming>;
1027
+ transportSlotWait: ReturnType<typeof createPhaseTiming>;
1028
+ fetchToHeaders: ReturnType<typeof createPhaseTiming>;
1029
+ bodyRead: ReturnType<typeof createPhaseTiming>;
1030
+ bodyAdmissionWait: ReturnType<typeof createPhaseTiming>;
1031
+ controllerPermits: number;
1032
+ inFlightAtPermit: ReturnType<typeof createSampleTiming>;
1033
+ runInFlightAtDispatch: ReturnType<typeof createSampleTiming>;
1034
+ targetRequestsPerSecond: Ewma;
1035
+ minimumRttMs: Ewma;
118
1036
  latency: Ewma;
119
1037
  retryAfter: Ewma;
120
1038
  provider429Count: number;
@@ -131,12 +1049,64 @@ export function createRuntimeResourceGovernor(input: {
131
1049
  acquired: 0,
132
1050
  bytes: 0,
133
1051
  };
1052
+ const resultEgressCounters = {
1053
+ batches: 0,
1054
+ receipts: 0,
1055
+ bytes: 0,
1056
+ maxBatchBytes: null as number | null,
1057
+ writerPeakInFlightBatches: 0,
1058
+ writerPeakQueued: 0,
1059
+ writerPeakBufferedItems: 0,
1060
+ writerPeakBufferedBytes: 0,
1061
+ readBacks: 0,
1062
+ liveResultReuses: 0,
1063
+ livePublicationResults: 0,
1064
+ existingWinners: 0,
1065
+ legacyAcknowledgements: 0,
1066
+ missingAcknowledgements: 0,
1067
+ nonterminalAcknowledgements: 0,
1068
+ readBackRecovered: 0,
1069
+ readBackMissing: 0,
1070
+ };
1071
+ const concurrencyShedCounters = { count: 0 };
1072
+ const concurrencyShedDelay = createEwma();
1073
+ const mapAdmission: Record<string, RuntimeMapHeapAdmissionSnapshot> = {};
1074
+
1075
+ const readMemorySnapshot = (): RuntimeMemorySnapshot | null => {
1076
+ const ledger = input.memoryLedger?.snapshot();
1077
+ if (!ledger) return null;
1078
+ let admissionHolds = 0;
1079
+ let externalPressureSignals = 0;
1080
+ let memoryPressureEvents = 0;
1081
+ for (const admission of Object.values(mapAdmission)) {
1082
+ admissionHolds += admission.admissionHolds;
1083
+ externalPressureSignals += admission.externalPressureSignals;
1084
+ memoryPressureEvents += admission.memoryPressureEvents;
1085
+ }
1086
+ return {
1087
+ ...ledger,
1088
+ admissionHolds,
1089
+ externalPressureSignals,
1090
+ memoryPressureEvents,
1091
+ };
1092
+ };
134
1093
 
135
1094
  const providerStats = (key: string) => {
136
1095
  const normalized = resourceKey(key);
137
1096
  let stats = providers.get(normalized);
138
1097
  if (!stats) {
139
1098
  stats = {
1099
+ admission: createPhaseTiming(),
1100
+ residence: createPhaseTiming(),
1101
+ fixtureDelay: createPhaseTiming(),
1102
+ transportSlotWait: createPhaseTiming(),
1103
+ fetchToHeaders: createPhaseTiming(),
1104
+ bodyRead: createPhaseTiming(),
1105
+ bodyAdmissionWait: createPhaseTiming(),
1106
+ controllerPermits: 0,
1107
+ inFlightAtPermit: createSampleTiming(),
1108
+ targetRequestsPerSecond: createEwma(),
1109
+ minimumRttMs: createEwma(),
140
1110
  latency: createEwma(),
141
1111
  retryAfter: createEwma(),
142
1112
  provider429Count: 0,
@@ -146,10 +1116,314 @@ export function createRuntimeResourceGovernor(input: {
146
1116
  return stats;
147
1117
  };
148
1118
 
1119
+ const providerAttributionKey = (key: string): string => {
1120
+ const normalized = resourceKey(key);
1121
+ if (
1122
+ normalized === PROVIDER_ATTRIBUTION_OTHER_KEY ||
1123
+ providerAttribution.has(normalized) ||
1124
+ providerAttributionReservations.has(normalized)
1125
+ ) {
1126
+ return normalized;
1127
+ }
1128
+ const namedCount = new Set([
1129
+ ...[...providerAttribution.keys()].filter(
1130
+ (provider) => provider !== PROVIDER_ATTRIBUTION_OTHER_KEY,
1131
+ ),
1132
+ ...providerAttributionReservations,
1133
+ ]).size;
1134
+ if (namedCount >= MAX_PROVIDER_ATTRIBUTION_BUCKETS) {
1135
+ return PROVIDER_ATTRIBUTION_OTHER_KEY;
1136
+ }
1137
+ providerAttributionReservations.add(normalized);
1138
+ return normalized;
1139
+ };
1140
+
1141
+ const providerAttributionStats = (key: string) => {
1142
+ const attributionKey = providerAttributionKey(key);
1143
+ let stats = providerAttribution.get(attributionKey);
1144
+ if (!stats) {
1145
+ stats = {
1146
+ admission: createPhaseTiming(),
1147
+ residence: createPhaseTiming(),
1148
+ fixtureDelay: createPhaseTiming(),
1149
+ transportSlotWait: createPhaseTiming(),
1150
+ fetchToHeaders: createPhaseTiming(),
1151
+ bodyRead: createPhaseTiming(),
1152
+ bodyAdmissionWait: createPhaseTiming(),
1153
+ controllerPermits: 0,
1154
+ inFlightAtPermit: createSampleTiming(),
1155
+ runInFlightAtDispatch: createSampleTiming(),
1156
+ targetRequestsPerSecond: createEwma(),
1157
+ minimumRttMs: createEwma(),
1158
+ latency: createEwma(),
1159
+ retryAfter: createEwma(),
1160
+ provider429Count: 0,
1161
+ };
1162
+ providerAttribution.set(attributionKey, stats);
1163
+ }
1164
+ return stats;
1165
+ };
1166
+
1167
+ const observeProviderStats = (
1168
+ stats: {
1169
+ admission: ReturnType<typeof createPhaseTiming>;
1170
+ residence: ReturnType<typeof createPhaseTiming>;
1171
+ fixtureDelay: ReturnType<typeof createPhaseTiming>;
1172
+ transportSlotWait: ReturnType<typeof createPhaseTiming>;
1173
+ fetchToHeaders: ReturnType<typeof createPhaseTiming>;
1174
+ bodyRead: ReturnType<typeof createPhaseTiming>;
1175
+ bodyAdmissionWait: ReturnType<typeof createPhaseTiming>;
1176
+ controllerPermits: number;
1177
+ inFlightAtPermit: ReturnType<typeof createSampleTiming>;
1178
+ runInFlightAtDispatch?: ReturnType<typeof createSampleTiming>;
1179
+ targetRequestsPerSecond: Ewma;
1180
+ minimumRttMs: Ewma;
1181
+ latency: Ewma;
1182
+ retryAfter: Ewma;
1183
+ provider429Count: number;
1184
+ },
1185
+ observation: RuntimeResourceObservation,
1186
+ ) => {
1187
+ stats.admission.observe(observation.providerAdmissionWaitMs);
1188
+ stats.residence.observe(observation.providerLatencyMs);
1189
+ stats.fixtureDelay.observe(observation.fixtureDelayMs);
1190
+ stats.transportSlotWait.observe(observation.transportSlotWaitMs);
1191
+ stats.fetchToHeaders.observe(observation.fetchToHeadersMs);
1192
+ stats.bodyRead.observe(observation.bodyReadMs);
1193
+ stats.bodyAdmissionWait.observe(observation.providerBodyAdmissionWaitMs);
1194
+ const pacingGrant =
1195
+ observation.providerPacingGrant ?? observation.providerConcurrencyGrant;
1196
+ if (pacingGrant) {
1197
+ stats.controllerPermits += 1;
1198
+ stats.targetRequestsPerSecond.observe(
1199
+ pacingGrant.targetRequestsPerSecond,
1200
+ );
1201
+ }
1202
+ const concurrencyGrant = observation.providerConcurrencyGrant;
1203
+ if (concurrencyGrant) {
1204
+ stats.inFlightAtPermit.observe(concurrencyGrant.inFlightAtStart);
1205
+ stats.minimumRttMs.observe(concurrencyGrant.minimumRttMs);
1206
+ }
1207
+ stats.runInFlightAtDispatch?.observe(
1208
+ observation.providerRunInFlightAtDispatch,
1209
+ );
1210
+ stats.latency.observe(observation.providerLatencyMs);
1211
+ stats.retryAfter.observe(observation.retryAfterMs);
1212
+ if (observation.provider429) {
1213
+ stats.provider429Count += 1;
1214
+ }
1215
+ };
1216
+
1217
+ let eventLoopLagTimer: ReturnType<typeof setInterval> | null = null;
1218
+ let eventLoopLagTickedAt: number | null = null;
1219
+ const startEventLoopLagSampler = (): void => {
1220
+ if (eventLoopLagTimer !== null) return;
1221
+ eventLoopLagTickedAt = Date.now();
1222
+ eventLoopLagTimer = setInterval(() => {
1223
+ const now = Date.now();
1224
+ const dueAt =
1225
+ (eventLoopLagTickedAt ?? now) + EVENT_LOOP_LAG_SAMPLE_INTERVAL_MS;
1226
+ eventLoopLagTickedAt = now;
1227
+ phases.eventLoopLag.observe(Math.max(0, now - dueAt));
1228
+ }, EVENT_LOOP_LAG_SAMPLE_INTERVAL_MS);
1229
+ // Measurement must never hold a runner open past its work.
1230
+ const handle = eventLoopLagTimer as { unref?: () => void };
1231
+ if (typeof handle.unref === 'function') {
1232
+ handle.unref();
1233
+ }
1234
+ };
1235
+ const stopEventLoopLagSampler = (): void => {
1236
+ if (eventLoopLagTimer === null) return;
1237
+ clearInterval(eventLoopLagTimer);
1238
+ eventLoopLagTimer = null;
1239
+ eventLoopLagTickedAt = null;
1240
+ };
1241
+
149
1242
  const observe = (observation: RuntimeResourceObservation): void => {
1243
+ startEventLoopLagSampler();
150
1244
  rowAdmissionWait.observe(observation.rowAdmissionWaitMs);
151
1245
  toolAdmissionWait.observe(observation.toolAdmissionWaitMs);
152
1246
  sheetFlushLatency.observe(observation.sheetFlushLatencyMs);
1247
+ phases.rowAdmission.observe(observation.rowAdmissionWaitMs);
1248
+ phases.providerAdmission.observe(observation.providerAdmissionWaitMs);
1249
+ phases.externalExecution.observe(observation.externalExecutionWaitMs);
1250
+ phases.providerResidence.observe(observation.providerLatencyMs);
1251
+ phases.fixtureDelay.observe(observation.fixtureDelayMs);
1252
+ phases.transportSlotWait.observe(observation.transportSlotWaitMs);
1253
+ phases.fetchToHeaders.observe(observation.fetchToHeadersMs);
1254
+ const executeRouteTiming = observation.executeServerTiming;
1255
+ // The response writer emits every named stage. Refuse a partial header so
1256
+ // this compact run aggregate has one honest denominator rather than four
1257
+ // incomparable ones from a rolling app/runtime skew.
1258
+ if (
1259
+ executeRouteTiming != null &&
1260
+ typeof executeRouteTiming.total === 'number' &&
1261
+ typeof executeRouteTiming.charge_open === 'number' &&
1262
+ typeof executeRouteTiming.fixture_load === 'number' &&
1263
+ typeof executeRouteTiming.execute === 'number'
1264
+ ) {
1265
+ executeRoute.count += 1;
1266
+ executeRoute.totalMs += executeRouteTiming.total;
1267
+ executeRoute.chargeOpenMs += executeRouteTiming.charge_open;
1268
+ executeRoute.fixtureLoadMs += executeRouteTiming.fixture_load;
1269
+ executeRoute.executeMs += executeRouteTiming.execute;
1270
+ // Same rule as the gateway block below: require the complete substage
1271
+ // set this app version emits, so an older build that reports only
1272
+ // `charge_open` does not silently contribute a partial split.
1273
+ if (
1274
+ typeof executeRouteTiming.charge_eligibility === 'number' &&
1275
+ typeof executeRouteTiming.charge_cap_preflight === 'number' &&
1276
+ typeof executeRouteTiming.charge_open_mutation === 'number' &&
1277
+ typeof executeRouteTiming.charge_retry_wait === 'number'
1278
+ ) {
1279
+ executeChargeOpen.count += 1;
1280
+ executeChargeOpen.eligibilityMs +=
1281
+ executeRouteTiming.charge_eligibility;
1282
+ executeChargeOpen.capPreflightMs +=
1283
+ executeRouteTiming.charge_cap_preflight;
1284
+ executeChargeOpen.openMutationMs +=
1285
+ executeRouteTiming.charge_open_mutation;
1286
+ executeChargeOpen.retryWaitMs += executeRouteTiming.charge_retry_wait;
1287
+ }
1288
+ // Gateway timing is a separate request-owner clock, but it is retained
1289
+ // only for the exact handler population above. Some routed tools have
1290
+ // the relay header but no app execute split; mixing them would make
1291
+ // `upstream_headers - handler.total` mathematically meaningless.
1292
+ // Require the complete set that this gateway version emits too, so a
1293
+ // rolling deploy cannot create a misleading sum over a different
1294
+ // population.
1295
+ if (
1296
+ typeof executeRouteTiming.auth_launch === 'number' &&
1297
+ typeof executeRouteTiming.auth_verify === 'number' &&
1298
+ typeof executeRouteTiming.body_parse === 'number' &&
1299
+ typeof executeRouteTiming.dispatch_pool === 'number' &&
1300
+ typeof executeRouteTiming.dispatch_callback === 'number' &&
1301
+ typeof executeRouteTiming.upstream_headers === 'number' &&
1302
+ typeof executeRouteTiming.upstream_body === 'number'
1303
+ ) {
1304
+ executeGateway.count += 1;
1305
+ executeGateway.authLaunchMs += executeRouteTiming.auth_launch;
1306
+ executeGateway.authVerifyMs += executeRouteTiming.auth_verify;
1307
+ executeGateway.bodyParseMs += executeRouteTiming.body_parse;
1308
+ executeGateway.dispatchPoolMs += executeRouteTiming.dispatch_pool;
1309
+ executeGateway.dispatchCallbackMs +=
1310
+ executeRouteTiming.dispatch_callback;
1311
+ executeGateway.upstreamHeadersMs += executeRouteTiming.upstream_headers;
1312
+ executeGateway.upstreamBodyMs += executeRouteTiming.upstream_body;
1313
+ }
1314
+ }
1315
+ phases.bodyRead.observe(observation.bodyReadMs);
1316
+ phases.receiptSettlement.observe(observation.receiptLatencyMs);
1317
+ phases.receiptClaim.observe(observation.receiptClaimMs);
1318
+ phases.receiptHydrationGateWait.observe(
1319
+ observation.receiptHydrationGateWaitMs,
1320
+ );
1321
+ phases.receiptCompletionQueue.observe(observation.receiptCompletionQueueMs);
1322
+ phases.receiptCompletionFlight.observe(
1323
+ observation.receiptCompletionFlightMs,
1324
+ );
1325
+ phases.receiptCompletionReadBack.observe(
1326
+ observation.receiptCompletionReadBackMs,
1327
+ );
1328
+ phases.rowPersistence.observe(observation.sheetFlushLatencyMs);
1329
+ phases.dispatchQueueWait.observe(observation.dispatchQueueWaitMs);
1330
+ phases.rowResolverGap.observe(observation.rowResolverGapMs);
1331
+ phases.toolCallLogicalWall.observe(observation.toolCallLogicalWallMs);
1332
+ phases.resultDelivery.observe(observation.resultDeliveryMs);
1333
+ phases.deliveryWrap.observe(observation.deliveryWrapMs);
1334
+ phases.deliveryPublishWait.observe(observation.deliveryPublishWaitMs);
1335
+ phases.deliveryResolve.observe(observation.deliveryResolveMs);
1336
+ phases.flightSerialize.observe(observation.flightSerializeMs);
1337
+ phases.flightTransport.observe(observation.flightTransportMs);
1338
+ phases.flightDecode.observe(observation.flightDecodeMs);
1339
+ phases.gatewayAuthLaunch.observe(observation.gatewayAuthLaunchMs);
1340
+ phases.gatewayAuthVerify.observe(observation.gatewayAuthVerifyMs);
1341
+ phases.gatewayBodyParse.observe(observation.gatewayBodyParseMs);
1342
+ phases.gatewayBodyInflate.observe(observation.gatewayBodyInflateMs);
1343
+ phases.gatewayPoolWait.observe(observation.gatewayPoolWaitMs);
1344
+ phases.gatewayReceiptValuePersist.observe(
1345
+ observation.gatewayReceiptValuePersistMs,
1346
+ );
1347
+ phases.gatewayCallback.observe(observation.gatewayCallbackMs);
1348
+ phases.gatewayRoundTrip.observe(observation.gatewayRoundTripMs);
1349
+ phases.gatewayRequestSerialize.observe(
1350
+ observation.gatewayRequestSerializeMs,
1351
+ );
1352
+ phases.gatewayRequestPack.observe(observation.gatewayRequestPackMs);
1353
+ if (observation.gatewayAuthSession != null) {
1354
+ gatewayAuthSessionCounters[observation.gatewayAuthSession] += 1;
1355
+ }
1356
+ // Raw is the authority for the count: every request has serialized bytes,
1357
+ // so a missing wire size (an older transport) adds nothing rather than
1358
+ // silently reporting a request that moved zero bytes.
1359
+ if (observation.gatewayRequestRawBytes != null) {
1360
+ gatewayRequestBodyCounters.count += 1;
1361
+ gatewayRequestBodyCounters.rawBytes += Math.max(
1362
+ 0,
1363
+ Math.floor(observation.gatewayRequestRawBytes),
1364
+ );
1365
+ gatewayRequestBodyCounters.wireBytes += Math.max(
1366
+ 0,
1367
+ Math.floor(
1368
+ observation.gatewayRequestWireBytes ??
1369
+ observation.gatewayRequestRawBytes,
1370
+ ),
1371
+ );
1372
+ }
1373
+ if (observation.receiptCompletionReadBacks != null) {
1374
+ resultEgressCounters.readBacks += Math.max(
1375
+ 0,
1376
+ Math.floor(observation.receiptCompletionReadBacks),
1377
+ );
1378
+ }
1379
+ if (observation.receiptCompletionLiveResultReuses != null) {
1380
+ resultEgressCounters.liveResultReuses += Math.max(
1381
+ 0,
1382
+ Math.floor(observation.receiptCompletionLiveResultReuses),
1383
+ );
1384
+ }
1385
+ if (observation.receiptCompletionLivePublicationResults != null) {
1386
+ resultEgressCounters.livePublicationResults += Math.max(
1387
+ 0,
1388
+ Math.floor(observation.receiptCompletionLivePublicationResults),
1389
+ );
1390
+ }
1391
+ if (observation.receiptCompletionExistingWinners != null) {
1392
+ resultEgressCounters.existingWinners += Math.max(
1393
+ 0,
1394
+ Math.floor(observation.receiptCompletionExistingWinners),
1395
+ );
1396
+ }
1397
+ if (observation.receiptCompletionLegacyAcknowledgements != null) {
1398
+ resultEgressCounters.legacyAcknowledgements += Math.max(
1399
+ 0,
1400
+ Math.floor(observation.receiptCompletionLegacyAcknowledgements),
1401
+ );
1402
+ }
1403
+ if (observation.receiptCompletionMissingAcknowledgements != null) {
1404
+ resultEgressCounters.missingAcknowledgements += Math.max(
1405
+ 0,
1406
+ Math.floor(observation.receiptCompletionMissingAcknowledgements),
1407
+ );
1408
+ }
1409
+ if (observation.receiptCompletionNonterminalAcknowledgements != null) {
1410
+ resultEgressCounters.nonterminalAcknowledgements += Math.max(
1411
+ 0,
1412
+ Math.floor(observation.receiptCompletionNonterminalAcknowledgements),
1413
+ );
1414
+ }
1415
+ if (observation.receiptCompletionReadBackRecovered != null) {
1416
+ resultEgressCounters.readBackRecovered += Math.max(
1417
+ 0,
1418
+ Math.floor(observation.receiptCompletionReadBackRecovered),
1419
+ );
1420
+ }
1421
+ if (observation.receiptCompletionReadBackMissing != null) {
1422
+ resultEgressCounters.readBackMissing += Math.max(
1423
+ 0,
1424
+ Math.floor(observation.receiptCompletionReadBackMissing),
1425
+ );
1426
+ }
153
1427
  if (observation.sheetFlushLatencyMs != null) {
154
1428
  sheetFlushCounters.acquired += 1;
155
1429
  }
@@ -165,17 +1439,72 @@ export function createRuntimeResourceGovernor(input: {
165
1439
  Math.floor(observation.sheetFlushBytes),
166
1440
  );
167
1441
  }
168
- if (
1442
+ if (observation.receiptEgressBatchSize != null) {
1443
+ resultEgressCounters.batches += 1;
1444
+ resultEgressCounters.receipts += Math.max(
1445
+ 0,
1446
+ Math.floor(observation.receiptEgressBatchSize),
1447
+ );
1448
+ }
1449
+ if (observation.receiptEgressBytes != null) {
1450
+ const bytes = Math.max(0, Math.floor(observation.receiptEgressBytes));
1451
+ resultEgressCounters.bytes += bytes;
1452
+ resultEgressCounters.maxBatchBytes =
1453
+ resultEgressCounters.maxBatchBytes === null
1454
+ ? bytes
1455
+ : Math.max(resultEgressCounters.maxBatchBytes, bytes);
1456
+ }
1457
+ if (observation.receiptCompletionWriterInFlightBatches != null) {
1458
+ resultEgressCounters.writerPeakInFlightBatches = Math.max(
1459
+ resultEgressCounters.writerPeakInFlightBatches,
1460
+ Math.max(
1461
+ 0,
1462
+ Math.floor(observation.receiptCompletionWriterInFlightBatches),
1463
+ ),
1464
+ );
1465
+ }
1466
+ if (observation.receiptCompletionWriterQueued != null) {
1467
+ resultEgressCounters.writerPeakQueued = Math.max(
1468
+ resultEgressCounters.writerPeakQueued,
1469
+ Math.max(0, Math.floor(observation.receiptCompletionWriterQueued)),
1470
+ );
1471
+ }
1472
+ if (observation.receiptCompletionWriterBufferedItems != null) {
1473
+ resultEgressCounters.writerPeakBufferedItems = Math.max(
1474
+ resultEgressCounters.writerPeakBufferedItems,
1475
+ Math.max(
1476
+ 0,
1477
+ Math.floor(observation.receiptCompletionWriterBufferedItems),
1478
+ ),
1479
+ );
1480
+ }
1481
+ if (observation.receiptCompletionWriterBufferedBytes != null) {
1482
+ resultEgressCounters.writerPeakBufferedBytes = Math.max(
1483
+ resultEgressCounters.writerPeakBufferedBytes,
1484
+ Math.max(
1485
+ 0,
1486
+ Math.floor(observation.receiptCompletionWriterBufferedBytes),
1487
+ ),
1488
+ );
1489
+ }
1490
+ if (observation.concurrencyShedDelayMs != null) {
1491
+ concurrencyShedCounters.count += 1;
1492
+ concurrencyShedDelay.observe(observation.concurrencyShedDelayMs);
1493
+ }
1494
+ const hasProviderObservation =
169
1495
  observation.providerResourceKey ||
1496
+ observation.providerTelemetryKey ||
170
1497
  observation.providerLatencyMs != null ||
171
1498
  observation.provider429 ||
172
- observation.retryAfterMs != null
173
- ) {
1499
+ observation.retryAfterMs != null;
1500
+ if (hasProviderObservation) {
174
1501
  const stats = providerStats(observation.providerResourceKey ?? 'unknown');
175
- stats.latency.observe(observation.providerLatencyMs);
176
- stats.retryAfter.observe(observation.retryAfterMs);
177
- if (observation.provider429) {
178
- stats.provider429Count += 1;
1502
+ observeProviderStats(stats, observation);
1503
+ if (observation.providerTelemetryKey) {
1504
+ observeProviderStats(
1505
+ providerAttributionStats(observation.providerTelemetryKey),
1506
+ observation,
1507
+ );
179
1508
  }
180
1509
  if (
181
1510
  observation.providerSuccess === true &&
@@ -226,11 +1555,90 @@ export function createRuntimeResourceGovernor(input: {
226
1555
  return lease;
227
1556
  },
228
1557
 
229
- acquireProviderPermit(providerInput) {
230
- return input.executionGovernor.acquireProviderPermit(
1558
+ async acquireExternalExecutionSlot(slotInput) {
1559
+ const startedAt = Date.now();
1560
+ const lease = await input.executionGovernor.acquireToolExecutionSlot({
1561
+ signal: slotInput?.signal,
1562
+ });
1563
+ toolCounters.acquired += 1;
1564
+ observe({
1565
+ providerResourceKey: slotInput?.providerResourceKey ?? null,
1566
+ externalExecutionWaitMs: elapsedSince(startedAt),
1567
+ });
1568
+ return lease;
1569
+ },
1570
+
1571
+ tryAcquireExternalExecutionSlot(slotInput) {
1572
+ const lease = input.executionGovernor.tryAcquireToolExecutionSlot();
1573
+ if (!lease) return null;
1574
+ toolCounters.acquired += 1;
1575
+ observe({
1576
+ providerResourceKey: slotInput?.providerResourceKey ?? null,
1577
+ externalExecutionWaitMs: 0,
1578
+ });
1579
+ return lease;
1580
+ },
1581
+
1582
+ chargeToolCall: () => input.executionGovernor.chargeBudget('toolCall'),
1583
+
1584
+ async acquireProviderPermit(providerInput) {
1585
+ const startedAt = Date.now();
1586
+ const lease = await input.executionGovernor.acquireProviderPermit(
231
1587
  providerInput.toolId,
232
1588
  { signal: providerInput.signal },
233
1589
  );
1590
+ observe({
1591
+ providerResourceKey: lease.provider,
1592
+ providerTelemetryKey: lease.provider,
1593
+ providerAdmissionWaitMs: elapsedSince(startedAt),
1594
+ });
1595
+ return lease;
1596
+ },
1597
+
1598
+ tryAcquireProviderPermit(providerInput) {
1599
+ const lease = input.executionGovernor.tryAcquireProviderPermit(
1600
+ providerInput.toolId,
1601
+ );
1602
+ if (!lease) return null;
1603
+ observe({
1604
+ providerResourceKey: lease.provider,
1605
+ providerTelemetryKey: lease.provider,
1606
+ providerAdmissionWaitMs: 0,
1607
+ });
1608
+ return lease;
1609
+ },
1610
+
1611
+ beginProviderExecution(providerInput) {
1612
+ const providerTelemetryKey = providerAttributionKey(
1613
+ providerInput.providerTelemetryKey ??
1614
+ providerInput.providerResourceKey ??
1615
+ 'unknown',
1616
+ );
1617
+ const inFlightAtDispatch =
1618
+ activeProviderExecutions.get(providerTelemetryKey) ?? 0;
1619
+ activeProviderExecutions.set(
1620
+ providerTelemetryKey,
1621
+ inFlightAtDispatch + 1,
1622
+ );
1623
+ let released = false;
1624
+ return {
1625
+ providerTelemetryKey,
1626
+ inFlightAtDispatch,
1627
+ release() {
1628
+ if (released) return;
1629
+ released = true;
1630
+ const active = activeProviderExecutions.get(providerTelemetryKey);
1631
+ if (!active || active <= 1) {
1632
+ activeProviderExecutions.delete(providerTelemetryKey);
1633
+ return;
1634
+ }
1635
+ activeProviderExecutions.set(providerTelemetryKey, active - 1);
1636
+ },
1637
+ };
1638
+ },
1639
+
1640
+ tryAcquireIntegrationRequestSlot() {
1641
+ return input.executionGovernor.tryAcquireIntegrationRequestSlot();
234
1642
  },
235
1643
 
236
1644
  suggestedToolParallelism(toolId, fallback) {
@@ -259,8 +1667,91 @@ export function createRuntimeResourceGovernor(input: {
259
1667
 
260
1668
  observe,
261
1669
 
1670
+ stopSampling: stopEventLoopLagSampler,
1671
+ eventLoopLagEwmaMs: () => phases.eventLoopLag.snapshot().ewmaMs,
1672
+
1673
+ recordMapAdmission(mapName, snapshot) {
1674
+ // The ledger is per-process, not per-map: the runner publishes it once
1675
+ // under `memory` below. Repeating it inside every map's admission
1676
+ // snapshot only spends the terminal metadata budget, and a
1677
+ // runtimeResources record over that budget is dropped whole.
1678
+ mapAdmission[resourceKey(mapName)] = { ...snapshot, memory: null };
1679
+ },
1680
+
1681
+ memoryLedger: input.memoryLedger ?? null,
1682
+
262
1683
  snapshot() {
263
1684
  return {
1685
+ // At the capped mixed-provider maximum, preserve the controller and
1686
+ // residence table rather than risking the terminal envelope for a
1687
+ // secondary diagnostic. Normal fixture shapes retain this aggregate.
1688
+ ...(executeRoute.count > 0 &&
1689
+ providerAttribution.size < MAX_PROVIDER_ATTRIBUTION_BUCKETS
1690
+ ? {
1691
+ executeRoute: {
1692
+ ...executeRoute,
1693
+ ...(executeChargeOpen.count > 0
1694
+ ? { chargeOpen: { ...executeChargeOpen } }
1695
+ : {}),
1696
+ ...(executeGateway.count > 0
1697
+ ? { gateway: { ...executeGateway } }
1698
+ : {}),
1699
+ },
1700
+ }
1701
+ : {}),
1702
+ process: readProcessUsage(),
1703
+ mapAdmission: { ...mapAdmission },
1704
+ memory: readMemorySnapshot(),
1705
+ // Distributions ride only on the run-level phases. Per-provider
1706
+ // timings stay lean counters: the provider map is unbounded, and the
1707
+ // terminal metadata record is dropped whole once it passes its budget.
1708
+ phases: {
1709
+ rowAdmission: phases.rowAdmission.distribution(),
1710
+ providerAdmission: phases.providerAdmission.distribution(),
1711
+ externalExecution: phases.externalExecution.distribution(),
1712
+ providerResidence: phases.providerResidence.distribution(),
1713
+ fixtureDelay: phases.fixtureDelay.distribution(),
1714
+ transportSlotWait: phases.transportSlotWait.distribution(),
1715
+ fetchToHeaders: phases.fetchToHeaders.distribution(),
1716
+ bodyRead: phases.bodyRead.distribution(),
1717
+ eventLoopLag: phases.eventLoopLag.distribution(),
1718
+ receiptSettlement: phases.receiptSettlement.distribution(),
1719
+ receiptClaim: phases.receiptClaim.distribution(),
1720
+ receiptHydrationGateWait:
1721
+ phases.receiptHydrationGateWait.distribution(),
1722
+ receiptCompletionQueue: phases.receiptCompletionQueue.distribution(),
1723
+ receiptCompletionFlight:
1724
+ phases.receiptCompletionFlight.distribution(),
1725
+ receiptCompletionReadBack:
1726
+ phases.receiptCompletionReadBack.distribution(),
1727
+ rowPersistence: phases.rowPersistence.distribution(),
1728
+ dispatchQueueWait: phases.dispatchQueueWait.distribution(),
1729
+ rowResolverGap: phases.rowResolverGap.distribution(),
1730
+ toolCallLogicalWall: phases.toolCallLogicalWall.distribution(),
1731
+ resultDelivery: phases.resultDelivery.distribution(),
1732
+ deliveryWrap: phases.deliveryWrap.distribution(),
1733
+ deliveryPublishWait: phases.deliveryPublishWait.distribution(),
1734
+ deliveryResolve: phases.deliveryResolve.distribution(),
1735
+ flightSerialize: phases.flightSerialize.distribution(),
1736
+ flightTransport: phases.flightTransport.distribution(),
1737
+ flightDecode: phases.flightDecode.distribution(),
1738
+ gatewayAuthLaunch: phases.gatewayAuthLaunch.distribution(),
1739
+ gatewayAuthVerify: phases.gatewayAuthVerify.distribution(),
1740
+ gatewayBodyParse: phases.gatewayBodyParse.distribution(),
1741
+ gatewayBodyInflate: phases.gatewayBodyInflate.distribution(),
1742
+ gatewayPoolWait: phases.gatewayPoolWait.distribution(),
1743
+ gatewayReceiptValuePersist:
1744
+ phases.gatewayReceiptValuePersist.distribution(),
1745
+ gatewayCallback: phases.gatewayCallback.distribution(),
1746
+ gatewayRoundTrip: phases.gatewayRoundTrip.distribution(),
1747
+ gatewayRequestSerialize:
1748
+ phases.gatewayRequestSerialize.distribution(),
1749
+ gatewayRequestPack: phases.gatewayRequestPack.distribution(),
1750
+ },
1751
+ gateway: {
1752
+ authSession: { ...gatewayAuthSessionCounters },
1753
+ requestBody: { ...gatewayRequestBodyCounters },
1754
+ },
264
1755
  rows: {
265
1756
  acquired: rowCounters.acquired,
266
1757
  estimatedBytes: rowCounters.estimatedBytes,
@@ -275,10 +1766,43 @@ export function createRuntimeResourceGovernor(input: {
275
1766
  bytes: sheetFlushCounters.bytes,
276
1767
  latencyMsEwma: sheetFlushLatency.value,
277
1768
  },
1769
+ resultEgress: resultEgressCounters,
1770
+ concurrencyShed: {
1771
+ count: concurrencyShedCounters.count,
1772
+ delayMsEwma: concurrencyShedDelay.value,
1773
+ },
278
1774
  providers: Object.fromEntries(
279
1775
  [...providers.entries()].map(([key, stats]) => [
280
1776
  key,
281
1777
  {
1778
+ admission: stats.admission.snapshot(),
1779
+ residence: stats.residence.snapshot(),
1780
+ fetchToHeaders: stats.fetchToHeaders.snapshot(),
1781
+ latencyMsEwma: stats.latency.value,
1782
+ retryAfterMsEwma: stats.retryAfter.value,
1783
+ provider429Count: stats.provider429Count,
1784
+ },
1785
+ ]),
1786
+ ),
1787
+ providerAttribution: Object.fromEntries(
1788
+ [...providerAttribution.entries()].map(([key, stats]) => [
1789
+ key,
1790
+ {
1791
+ admission: stats.admission.snapshot(),
1792
+ residence: stats.residence.snapshot(),
1793
+ fixtureDelay: stats.fixtureDelay.snapshot(),
1794
+ transportSlotWait: stats.transportSlotWait.snapshot(),
1795
+ fetchToHeaders: stats.fetchToHeaders.snapshot(),
1796
+ bodyRead: stats.bodyRead.snapshot(),
1797
+ gateMs: stats.bodyAdmissionWait.snapshot().totalMs,
1798
+ controller: {
1799
+ permits: stats.controllerPermits,
1800
+ inFlightAtPermit: stats.inFlightAtPermit.snapshot(),
1801
+ runInFlightAtDispatch: stats.runInFlightAtDispatch.snapshot(),
1802
+ targetRequestsPerSecondEwma:
1803
+ stats.targetRequestsPerSecond.value,
1804
+ minimumRttMsEwma: stats.minimumRttMs.value,
1805
+ },
282
1806
  latencyMsEwma: stats.latency.value,
283
1807
  retryAfterMsEwma: stats.retryAfter.value,
284
1808
  provider429Count: stats.provider429Count,