@dvmkit/sdk 0.1.5-rc.9 → 0.2.0-rc.9

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 (56) hide show
  1. package/README.md +12 -0
  2. package/dist/{chunk-BIP6G74V.js → chunk-2ATUAUAO.js} +8 -8
  3. package/dist/{chunk-27V2ILSR.js → chunk-4A2RAKCW.js} +2 -2
  4. package/dist/{chunk-EVBK675R.js → chunk-6GRIKOFB.js} +28 -23
  5. package/dist/{chunk-CEOAHV2I.js → chunk-FDKRXOZO.js} +0 -5
  6. package/dist/{chunk-L4OYF4DQ.js → chunk-FT6HTUM4.js} +1 -1
  7. package/dist/{chunk-BTZY7VPH.js → chunk-GAIPXGM3.js} +1 -1
  8. package/dist/{chunk-U6M3ATSG.js → chunk-JDT5LCJC.js} +40 -6
  9. package/dist/{chunk-FROTD5XQ.js → chunk-JLXYOV4Y.js} +1 -2
  10. package/dist/{chunk-M7LHFJ5K.js → chunk-KMZXTBLA.js} +2 -2
  11. package/dist/{chunk-6BQM7TOW.js → chunk-L67WTZX2.js} +3 -7
  12. package/dist/{chunk-CGKZDODG.js → chunk-MG67KXU7.js} +0 -5
  13. package/dist/{chunk-JZWELPFH.js → chunk-MRAGS5VP.js} +1 -1
  14. package/dist/{chunk-2UUXIIOC.js → chunk-O2X2CCKH.js} +3 -3
  15. package/dist/{chunk-TQWGQCNV.js → chunk-OMIQMMME.js} +3 -3
  16. package/dist/{chunk-5PBOA25N.js → chunk-PCUQZDZA.js} +436 -355
  17. package/dist/{chunk-KVEHHC7W.js → chunk-PHHAYRQV.js} +7 -9
  18. package/dist/{chunk-SSSZUVWM.js → chunk-QP53RWAD.js} +88 -38
  19. package/dist/{chunk-DMNLFNTW.js → chunk-QT4ONTST.js} +1 -1
  20. package/dist/{chunk-RW5LP57K.js → chunk-SDK6KDJN.js} +0 -1
  21. package/dist/{chunk-MLRCSJYX.js → chunk-V7EVFLAK.js} +87 -90
  22. package/dist/{chunk-E4EVGPDX.js → chunk-XQXJKJ3P.js} +0 -2
  23. package/dist/{credit-ledger-2DFQHNLB.js → credit-ledger-5ZEJRI46.js} +1 -1
  24. package/dist/{credit-menu-enwMbn55.d.ts → credit-menu-D4Gcdgc4.d.ts} +487 -643
  25. package/dist/{fx-D860pZvP.d.ts → fx-B0SLBe5x.d.ts} +38 -82
  26. package/dist/index.d.ts +11 -14
  27. package/dist/index.js +2 -2
  28. package/dist/internal/caller.d.ts +618 -1525
  29. package/dist/internal/caller.js +28 -60
  30. package/dist/internal/server.d.ts +36 -61
  31. package/dist/internal/server.js +11 -11
  32. package/dist/{job-store-BUGqvCfL.d.ts → job-store-B2uZvga4.d.ts} +70 -59
  33. package/dist/{lightning-backend-BozcevPZ.d.ts → lightning-backend-CQBnQgsT.d.ts} +19 -27
  34. package/dist/{memory-credit-ledger-MNUOTQO5.js → memory-credit-ledger-ZOH6C3N4.js} +2 -2
  35. package/dist/{mpp-setup-4FJD6ZHV.js → mpp-setup-IOJBF7DB.js} +1 -1
  36. package/dist/{payout-reporter-RG6XNGPI.js → payout-reporter-5PIRYFVQ.js} +1 -1
  37. package/dist/{postgres-consumed-credential-store-VHBT4KEA.js → postgres-consumed-credential-store-ISRHBMOU.js} +1 -1
  38. package/dist/{postgres-job-store-3RAXMNSY.js → postgres-job-store-OGQ6IT4U.js} +1 -1
  39. package/dist/{postgres-kv-store-JFBDP5IP.js → postgres-kv-store-D5E2EZ24.js} +1 -1
  40. package/dist/{postgres-replay-store-UJXRT6VO.js → postgres-replay-store-IZFLTTAC.js} +1 -1
  41. package/dist/{pricing-4CEB34RM.js → pricing-MU5GNUJZ.js} +1 -1
  42. package/dist/{processed-payment-store-HAA4SFNK.js → processed-payment-store-FIDI3RNH.js} +1 -1
  43. package/dist/{revenue-reporter-ASZ7SHHH.js → revenue-reporter-NNCNRY4C.js} +1 -1
  44. package/dist/server/index.d.ts +53 -59
  45. package/dist/server/index.js +38 -37
  46. package/dist/{ssrf-DbFkpDv0.d.ts → ssrf-dMooihtY.d.ts} +1 -2
  47. package/dist/{step-cache-5dljDqrQ.d.ts → step-cache-CXg7ziML.d.ts} +389 -551
  48. package/dist/{tempo-charge-store-RIFTALZK.js → tempo-charge-store-76TDAF34.js} +1 -1
  49. package/dist/{tempo-lifecycle-DFIXQ54Q.js → tempo-lifecycle-DXM7QXJQ.js} +3 -3
  50. package/dist/{tempo-wallet-4QKSV65O.js → tempo-wallet-O67H5M4N.js} +2 -2
  51. package/dist/testing/index.d.ts +5 -15
  52. package/dist/testing/index.js +4 -11
  53. package/dist/{usd-DoRuAckA.d.ts → usd-BNDg1715.d.ts} +14 -16
  54. package/dist/{wallet-CJC8lwxx.d.ts → wallet-Dwjs5n_M.d.ts} +1 -1
  55. package/dist/{x402-5H27DCBE.js → x402-7S2EFINY.js} +2 -2
  56. package/package.json +2 -1
@@ -1,16 +1,16 @@
1
- import { ah as FundingMethod, o as PaymentMethod, bM as CreditLedgerLike, a1 as Message, X as FundingReceipt, bO as CreditSnapshot, Y as JobReceipt, S as SDKJobContext, aw as StepCache, u as ResponseContent, P as PaymentContent, a2 as MessageType, bj as X402Receipt, aE as X402Config, bi as X402ExactVersionSupport, cS as X402SettlementIntent, aq as PaymentRequirementsV2, c1 as CreditLedgerQuerier, cT as X402SettlementCursor, bQ as X402SettlementStatus, cU as X402SettlementWriteOff, bN as X402RefundSettlementGate, cV as X402FacilitatorAuth, cW as X402BatchSettlementConfig, cy as PostgresX402ChannelStorage, cX as X402PayoutObserver, br as MppxServer, ab as CashuMode, cY as CreditDepositEnqueue, cZ as X402SettlementReconciliationReason, ao as PaymentRequirements, a0 as MppxCredential, bm as CreditDepositPayload, bP as DrawResult, cn as CreditLedgerError, a6 as ReceiptCredit, ae as DrainReceiptEvent, ad as DrainReceipt, K as KVStore, y as SignedRequestAudience, c_ as CreditDrawReleaseEnqueue, cx as JobCostReportPayload, cA as RevenueSkippedNoRailPayload, Z as ZodLike, a as DVMDescriptor, bV as CreditInvoiceRecord, bW as InvoiceSettlement, ch as ClientCompatibilityGate, cf as ClientCompatibility, bu as PayoutReporter, R as ResolvedCreditConfig, g as CreditView } from './step-cache-5dljDqrQ.js';
1
+ import { ah as FundingMethod, o as PaymentMethod, bM as CreditLedgerLike, a1 as Message, X as FundingReceipt, bO as CreditSnapshot, Y as JobReceipt, S as SDKJobContext, aw as StepCache, u as ResponseContent, P as PaymentContent, a2 as MessageType, bj as X402Receipt, aE as X402Config, bi as X402ExactVersionSupport, cT as X402SettlementIntent, aq as PaymentRequirementsV2, c1 as CreditLedgerQuerier, cU as X402SettlementCursor, bQ as X402SettlementStatus, cV as X402SettlementWriteOff, bN as X402RefundSettlementGate, cW as X402FacilitatorAuth, cX as X402BatchSettlementConfig, cz as PostgresX402ChannelStorage, cY as X402PayoutObserver, br as MppxServer, ab as CashuMode, cZ as CreditDepositEnqueue, c_ as X402SettlementReconciliationReason, ao as PaymentRequirements, a0 as MppxCredential, bm as CreditDepositPayload, bP as DrawResult, cn as CreditLedgerError, a6 as ReceiptCredit, ae as DrainReceiptEvent, ad as DrainReceipt, K as KVStore, y as SignedRequestAudience, c$ as CreditDrawReleaseEnqueue, cx as JobCostReportPayload, cy as JobTerminalReportPayload, cB as RevenueSkippedNoRailPayload, Z as ZodLike, a as DVMDescriptor, bV as CreditInvoiceRecord, bW as InvoiceSettlement, ch as ClientCompatibilityGate, cf as ClientCompatibility, bu as PayoutReporter, R as ResolvedCreditConfig, g as CreditView } from './step-cache-CXg7ziML.js';
2
2
  import { ProofLike, SerializedDLEQ, Proof } from '@cashu/cashu-ts';
3
3
  import { Hono, Context } from 'hono';
4
4
  import { Pool } from 'pg';
5
- import { b as FxRateSnapshot, F as FxFetcher } from './fx-D860pZvP.js';
6
- import { g as LockPubkey, f as CheckMintHealthOptions, b as LightningBackend, A as AttestationPayload } from './lightning-backend-BozcevPZ.js';
7
- import { T as TopUpCapUnenforcedReason, A as AppendOutgoingOptions, J as JobRecord, b as JobStore } from './job-store-BUGqvCfL.js';
5
+ import { b as FxRateSnapshot, F as FxFetcher } from './fx-B0SLBe5x.js';
6
+ import { g as LockPubkey, f as CheckMintHealthOptions, b as LightningBackend, A as AttestationPayload } from './lightning-backend-CQBnQgsT.js';
7
+ import { T as TopUpCapUnenforcedReason, A as AppendOutgoingOptions, J as JobRecord, b as JobStore } from './job-store-B2uZvga4.js';
8
8
  import { Challenge } from 'mppx';
9
9
  import { SettleResponse, SupportedResponse } from '@x402/core/types';
10
10
  import { Channel, AutoSettlementConfig } from '@x402/evm/batch-settlement/server';
11
11
  import { FacilitatorClient } from '@x402/core/server';
12
12
 
13
- /** A row in the per-DVM `wallet_accumulator` table (internal-review). */
13
+ /** A row in the per-DVM `wallet_accumulator` table. */
14
14
  interface WalletAccumulatorRow {
15
15
  id: string;
16
16
  dvmId: string;
@@ -38,7 +38,7 @@ interface WalletAccumulatorRow {
38
38
  meltQuoteId: string | null;
39
39
  /**
40
40
  * NUT-11 locktime captured at accept time (ms since epoch). Null when the
41
- * accepted proof has no `locktime` tag (internal-review). Drives oldest-first
41
+ * accepted proof has no `locktime` tag. Drives oldest-first
42
42
  * ordering and the future `wallet_accumulator_batch_expiring_soon` monitor.
43
43
  */
44
44
  tExpire: number | null;
@@ -71,7 +71,7 @@ declare function initWalletAccumulatorTable(db: AccumulatorPool): Promise<void>;
71
71
  *
72
72
  * With `tx` (a client inside a caller-owned `BEGIN`), issues **no**
73
73
  * transaction control: the inserts join the caller's transaction so the rail
74
- * commit and the `CreditLedger.fund` + `draw` land atomically (internal-review, spec
74
+ * commit and the `CreditLedger.fund` + `draw` land atomically (spec
75
75
  * §2 condition 3). A `unique_violation` still surfaces as
76
76
  * `AccumulatorReplayError`, but the caller owns the ROLLBACK — note the
77
77
  * transaction is poisoned after the violation (Postgres aborts it), so the
@@ -82,7 +82,7 @@ declare function insertAccumulatorRows(db: AccumulatorPool, args: {
82
82
  /**
83
83
  * Per-proof matched lock pubkey, parallel to `proofs`. Recording the
84
84
  * matched value per row lets the monitor surface retired-batch alerts
85
- * (internal-review) and lets `dvmctl melt-pending`'s rotation walker pick the
85
+ * and lets `dvmctl melt-pending`'s rotation walker pick the
86
86
  * right privkey per batch. Branded `LockPubkey` so the lowercase invariant
87
87
  * is enforced at the type boundary, not by every call site.
88
88
  */
@@ -97,7 +97,7 @@ declare function insertAccumulatorRows(db: AccumulatorPool, args: {
97
97
  */
98
98
  tExpireMsByIndex?: (number | null)[];
99
99
  receivedAt?: number;
100
- /** External transaction handle — caller owns BEGIN/COMMIT/ROLLBACK (internal-review). */
100
+ /** External transaction handle — caller owns BEGIN/COMMIT/ROLLBACK. */
101
101
  tx?: AccumulatorQuerier;
102
102
  }): Promise<WalletAccumulatorRow[]>;
103
103
  /** Delete every accumulator row for a DVM. Used by `dvmadmin wallet-accumulator clear`. */
@@ -117,8 +117,8 @@ declare function hashLockKey(input: string): bigint;
117
117
  *
118
118
  * Used by `verifyUpfrontPayment` to reject replay of an MPP credential whose
119
119
  * `(realm, challenge.id)` was already accepted within the current TTL window
120
- * (internal-review). Mid-job replay is handled separately via per-job
121
- * `pendingMppChallengeIds` (internal-review).
120
+ * Mid-job replay is handled separately via per-job
121
+ * `pendingMppChallengeIds`.
122
122
  */
123
123
  interface ConsumedCredentialStore {
124
124
  /** True iff `(realm, challengeId)` was marked and the entry has not expired. */
@@ -126,7 +126,6 @@ interface ConsumedCredentialStore {
126
126
  /** Mark `(realm, challengeId)` as consumed for `ttlSeconds`. */
127
127
  mark(realm: string, challengeId: string, ttlSeconds: number): Promise<void>;
128
128
  }
129
- /** Options for `MemoryConsumedCredentialStore`. */
130
129
  interface MemoryConsumedCredentialStoreOpts {
131
130
  /** FIFO eviction kicks in when entry count would exceed this. Default: 10_000. */
132
131
  maxEntries?: number;
@@ -138,8 +137,8 @@ interface MemoryConsumedCredentialStoreOpts {
138
137
  *
139
138
  * Per-process and not multi-instance-safe — each replica tracks its own
140
139
  * consumed set, so a credential redirected to a different replica still works
141
- * once. Acceptable for first-party single-instance Fly DVMs (internal-review open
142
- * question); swap to a shared backend before deploying multiple replicas.
140
+ * once. Use only for a single-instance DVM; swap to a shared backend before
141
+ * deploying multiple replicas.
143
142
  */
144
143
  declare class MemoryConsumedCredentialStore implements ConsumedCredentialStore {
145
144
  private readonly maxEntries;
@@ -203,7 +202,7 @@ interface ServerJob {
203
202
  id: string;
204
203
  tags: string[];
205
204
  /**
206
- * Capability name this job belongs to (internal-review). Set at submission from
205
+ * Capability name this job belongs to. Set at submission from
207
206
  * `POST /v1/job` body's `capability` field; routes the SDK runtime to the
208
207
  * right `onJob` / `onResponse` / `onPayment` handler and the right input
209
208
  * schema. Required — the wire layer rejects requests that omit it.
@@ -214,12 +213,12 @@ interface ServerJob {
214
213
  requesterId: string;
215
214
  /**
216
215
  * SHA-256 hex of the per-job opaque `job_token` minted at creation for
217
- * anonymous callers (internal-review). Mirror of `JobRecord.requesterTokenHash`;
216
+ * anonymous callers. Mirror of `JobRecord.requesterTokenHash`;
218
217
  * see that field for the wire-level gating semantics.
219
218
  */
220
219
  requesterTokenHash?: string;
221
220
  /**
222
- * Submission provenance (internal-review) — mirrors `JobRecord.requesterToken` /
221
+ * Submission provenance — mirrors `JobRecord.requesterToken` /
223
222
  * `requestFingerprint` / `requesterPubkey`. Carried on the job purely so
224
223
  * `toJobRecord` persists it; nothing in the runtime reads it. It's the
225
224
  * replay gate: a retried paid submit that reproduces the fingerprint (and,
@@ -232,6 +231,16 @@ interface ServerJob {
232
231
  /** HTTP path independently recorded when the caller proof was accepted. */
233
232
  authRequestPath?: string;
234
233
  status: "processing" | "completed" | "failed" | "awaiting-input" | "cancelled" | "working";
234
+ /** Mirrors the durable completeness marker; false for legacy accepted jobs. */
235
+ timingKnown?: boolean;
236
+ /** SDK terminal attribution; never accepted from a handler. */
237
+ endedBy?: "caller" | "provider";
238
+ /** Unix ms when the terminal status committed; immutable afterwards. */
239
+ terminalAtMs?: number;
240
+ /** Accumulated awaiting-input time, excluding the currently open stretch. */
241
+ callerWaitMs?: number;
242
+ /** Unix ms at which the current awaiting-input stretch began. */
243
+ awaitingInputAtMs?: number;
235
244
  summary?: string;
236
245
  messages: Message[];
237
246
  seq: number;
@@ -243,9 +252,9 @@ interface ServerJob {
243
252
  * Settlement reference for the most-recent successful credit. Threaded
244
253
  * into `onJobCompleted` so the platform revenue ledger can populate
245
254
  * `revenue_events.tx_hash`. mpp/x402 carry the credential's `challenge.id`
246
- * / EVM tx hash from the facilitator (internal-review); cashu accumulator carries
247
- * the `X-Cashu-Request-Id` UUID (internal-review). Updated on every credit
248
- * (upfront or mid-job via `processIncomingPayment`) — internal-review.
255
+ * / EVM tx hash from the facilitator; cashu accumulator carries
256
+ * the `X-Cashu-Request-Id` UUID. Updated on every credit
257
+ * (upfront or mid-job via `processIncomingPayment`).
249
258
  * Single-row-per-job accounting keeps the most recent credit's hash,
250
259
  * mirroring `paymentRail`.
251
260
  */
@@ -256,19 +265,19 @@ interface ServerJob {
256
265
  * Rail-native amount accumulated across all successful credits on this
257
266
  * job (sats for mpp, USDC microunits for x402). The single
258
267
  * `revenue_events` row written at completion uses this as `gross_native`,
259
- * so multi-credit jobs sum the per-credit native amounts (internal-review).
260
- * internal-review wired the upfront credit; mid-job credits accumulate same-rail
268
+ * so multi-credit jobs sum the per-credit native amounts.
269
+ * The upfront credit initializes this value; mid-job credits accumulate same-rail
261
270
  * and reset on a cross-rail switch (see `processIncomingPayment`).
262
271
  */
263
272
  nativeAmount?: number;
264
- /** Native asset tag — paired with `nativeAmount`. internal-review. */
273
+ /** Native asset tag paired with `nativeAmount`. */
265
274
  nativeAsset?: "sats" | "usdc" | "usdc.e" | "usd-cents";
266
- /** Cashu flow discriminator written into `revenue_events.metadata.cashu_flow` (internal-review). */
275
+ /** Cashu flow discriminator written into `revenue_events.metadata.cashu_flow`. */
267
276
  cashuFlow?: "p2pk_accumulator";
268
277
  /**
269
278
  * What this job cost the **builder** to serve, in 1e-6 of
270
279
  * {@link ServerJob.costCurrency} — the running total the handler declared
271
- * through `ctx.cost()` (internal-review). Absent until a handler declares
280
+ * through `ctx.cost()`. Absent until a handler declares
272
281
  * something; absent is "unreported", which is not the same fact as a
273
282
  * declared zero and is reported differently.
274
283
  *
@@ -284,9 +293,9 @@ interface ServerJob {
284
293
  costCurrency?: string;
285
294
  /** Number of `ctx.cost()` declarations incorporated into the current cost state. */
286
295
  costRevision?: number;
287
- /** Credit the upfront payment funded/drew (internal-review). See `JobRecord.creditId`. */
296
+ /** Credit the upfront payment funded/drew. See `JobRecord.creditId`. */
288
297
  creditId?: string;
289
- /** The draw placed for this job on `creditId` (internal-review). */
298
+ /** The draw placed for this job on `creditId`. */
290
299
  drawId?: string;
291
300
  /** Original funding artifact returned by an explicit fund-and-draw. */
292
301
  fundingReceipt?: FundingReceipt;
@@ -299,11 +308,11 @@ interface ServerJob {
299
308
  * binds challenges to realm/method/amount/expiry, not to the dvmkit job-id;
300
309
  * verifying the incoming credential's `challenge.id` is in this set blocks
301
310
  * a credential lifted from a sibling job that requested the same fields.
302
- * Cleared on successful credit (internal-review).
311
+ * Cleared on successful credit.
303
312
  */
304
313
  pendingMppChallengeIds?: string[];
305
314
  /**
306
- * Per-job binding for x402 mid-job credentials (internal-review). 32-byte 0x-hex
315
+ * Per-job binding for x402 mid-job credentials. 32-byte 0x-hex
307
316
  * nonce issued by `requestPayment` and stamped onto the outbound x402
308
317
  * envelope; the caller signs `TransferWithAuthorization` against this exact
309
318
  * `bytes32`. Verification rejects an incoming `x402_payment` whose decoded
@@ -318,30 +327,30 @@ interface ServerJob {
318
327
  pendingX402AmountUsdcMicro?: string;
319
328
  /**
320
329
  * Fiat micro-units the outstanding `requestPayment` ask is worth, pinned when
321
- * the payment-request was emitted (internal-review). See `JobRecord`.
330
+ * the payment-request was emitted. See `JobRecord`.
322
331
  */
323
332
  pendingPaymentFiatMicro?: number;
324
333
  /** Currency of {@link pendingPaymentFiatMicro} (lowercase ISO-4217). */
325
334
  pendingPaymentFiatCurrency?: string;
326
335
  /**
327
336
  * Cumulative fiat micro this job has asked for mid-job, the ceiling on its
328
- * draw growth (internal-review). See `JobRecord.askedTopUpMicro` for the sentinel.
337
+ * draw growth. See `JobRecord.askedTopUpMicro` for the sentinel.
329
338
  */
330
339
  askedTopUpMicro?: number;
331
340
  /**
332
341
  * Currency of {@link askedTopUpMicro} — and this job's sticky ask
333
- * denomination (internal-review). See `JobRecord.askedTopUpCurrency`.
342
+ * denomination. See `JobRecord.askedTopUpCurrency`.
334
343
  */
335
344
  askedTopUpCurrency?: string;
336
345
  /**
337
- * Why this job's draw growth is not capped, when it isn't (internal-review). Mirror
346
+ * Why this job's draw growth is not capped, when it isn't. Mirror
338
347
  * of `JobRecord.topUpCapUnenforcedReason`.
339
348
  */
340
349
  topUpCapUnenforcedReason?: TopUpCapUnenforcedReason;
341
350
  /** Price the job was charged at (msats). Used to detect overpayment for change/melt gating. */
342
351
  requiredMsats?: number;
343
352
  /**
344
- * The signed receipt for this job's terminal outcome (internal-review). Mirror of
353
+ * The signed receipt for this job's terminal outcome. Mirror of
345
354
  * `JobRecord.receipt`, set once the terminal funnel has signed and persisted
346
355
  * it so the local read paths (which serve from `activeJobs` during the
347
356
  * cleanup window) hand back the same bytes as a cross-machine re-read.
@@ -349,7 +358,7 @@ interface ServerJob {
349
358
  receipt?: JobReceipt;
350
359
  /**
351
360
  * The in-flight terminal chain — persist, then sign + store the receipt
352
- * (internal-review). Assigned synchronously by `ctx.complete()` / `ctx.fail()` at
361
+ * Assigned synchronously by `ctx.complete()` / `ctx.fail()` at
353
362
  * the instant the job goes terminal, so the `POST /v1/job` fast path can
354
363
  * await it (bounded) and put the receipt on the synchronous 200 rather than
355
364
  * making the caller poll for it. Never rejects — the chain swallows its own
@@ -358,7 +367,7 @@ interface ServerJob {
358
367
  terminalWork?: Promise<void>;
359
368
  listeners: Set<(msg: Message) => void>;
360
369
  /**
361
- * Cancellation signal for the running handler (internal-review). Aborted whenever
370
+ * Cancellation signal for the running handler. Aborted whenever
362
371
  * the job is cancelled on this process — caller cancel, idle timeout,
363
372
  * stale-sweep teardown, supersession. Surfaced to builders as `ctx.signal`
364
373
  * and auto-threaded into `ctx.fetch`, so an in-flight provider call
@@ -368,18 +377,18 @@ interface ServerJob {
368
377
  */
369
378
  abort: AbortController;
370
379
  /**
371
- * Hook for cross-machine message persistence (Tx A, internal-review). Set by
380
+ * Hook for cross-machine message persistence (Tx A). Set by
372
381
  * `JobManager` when the store is streamable. The appender runs the
373
382
  * outgoing-message tx atomically with any payment-request counter bump so
374
383
  * `(message, pending_payment_msats)` land together — never separately.
375
384
  *
376
- * Per-job serialised (internal-review): each call chains onto `messageAppenderTail`
385
+ * Per-job serialised: each call chains onto `messageAppenderTail`
377
386
  * so two synchronous `providerMessage` calls (e.g. `artifact` followed by
378
387
  * `complete`) can't race for the DB-side seq allocation.
379
388
  */
380
389
  messageAppender?: (msg: Message, opts?: AppendOutgoingOptions) => void;
381
390
  /**
382
- * Tail of the per-job appender chain (internal-review). `wireMessageAppender` updates
391
+ * Tail of the per-job appender chain. `wireMessageAppender` updates
383
392
  * this on every call so `persistJob` can await it before the terminal snapshot
384
393
  * save runs `DELETE FROM job_messages`.
385
394
  */
@@ -411,7 +420,7 @@ declare function toJobRecord(job: ServerJob): JobRecord;
411
420
  /** Reconstitute a ServerJob from a persisted JobRecord with fresh runtime fields. */
412
421
  declare function fromJobRecord(record: JobRecord): ServerJob;
413
422
  /**
414
- * Signal cancellation to a running handler (internal-review). Idempotent — aborting an
423
+ * Signal cancellation to a running handler. Idempotent — aborting an
415
424
  * already-aborted controller is a no-op, so the overlapping teardown paths
416
425
  * (caller cancel then stale sweep, say) can each call it unconditionally.
417
426
  */
@@ -426,22 +435,21 @@ declare class JobCancelledError extends Error {
426
435
  }
427
436
  /** Append a provider-sent message to the job and notify SSE listeners. */
428
437
  declare function providerMessage(job: ServerJob, type: MessageType, content: Record<string, unknown> | object): void;
429
- /** Check if a job status is terminal (completed, failed, cancelled). */
430
438
  declare function isTerminal(status: ServerJob["status"]): boolean;
431
439
  /** Check if a message is a yield point (ends the provider's turn). */
432
440
  declare function isYieldMessage(msg: Message): boolean;
433
441
 
434
442
  /**
435
- * Per-DVM runtime mint-health tracker (internal-review). Alongside the platform's
443
+ * Per-DVM runtime mint-health tracker. Alongside the platform's
436
444
  * durable mint-health cron, probes every configured
437
445
  * mint on a timer, tracks consecutive failures, and flips a mint to `sick`
438
446
  * once the threshold is crossed. The SDK uses the resulting view to:
439
447
  *
440
- * 1. Filter `/v1/info`'s advertised `mints` to currently-healthy ones.
441
- * 2. Reject new accumulator receives at sick mints before they touch the
442
- * DB (`cashu_mint_sick` 503 from `verifyAccumulatorReceipt`).
448
+ * 1. Filter `/v1/info`'s advertised `mints` to currently-healthy ones.
449
+ * 2. Reject new accumulator receives at sick mints before they touch the
450
+ * DB (`cashu_mint_sick` 503 from `verifyAccumulatorReceipt`).
443
451
  *
444
- * Since internal-review this tracker is the sole owner of mint health: boot no longer
452
+ * Since this tracker is the sole owner of mint health: boot no longer
445
453
  * runs a fail-fast check before binding the port. To preserve what boot used
446
454
  * to guarantee it (a) treats a mint as healthy only when it's reachable AND
447
455
  * NUT-compliant (reproducing `assertNutSupport` via `nutCompliant`), and (b)
@@ -454,7 +462,7 @@ declare function isYieldMessage(msg: Message): boolean;
454
462
  * pages the builder when a stuck batch nears `t_expire`.
455
463
  *
456
464
  * In-memory only — no DB persistence. The platform cron keeps the durable
457
- * record + email path (internal-review); the SDK only needs fresh in-process state
465
+ * record + email path; the SDK only needs fresh in-process state
458
466
  * to make routing decisions.
459
467
  */
460
468
 
@@ -467,8 +475,8 @@ interface MintHealthSnapshot {
467
475
  /**
468
476
  * True once the mint is considered unhealthy for routing: either
469
477
  * `consecutiveFailures` crossed the threshold, or the last probe reached the
470
- * mint but it fails the NUT gate (a deterministic, permanent config error
471
- * that flips `sick` immediately — internal-review).
478
+ * mint but it fails the NUT gate, a deterministic, permanent config error
479
+ * that flips `sick` immediately.
472
480
  */
473
481
  sick: boolean;
474
482
  /**
@@ -483,10 +491,11 @@ interface MintHealthSnapshot {
483
491
  /** Error category from the most recent failed probe. */
484
492
  errorCode?: string;
485
493
  }
486
- /** Tunables for {@link MintHealthTracker}. */
487
494
  interface MintHealthTrackerOptions {
488
495
  /** Cashu mint URLs the DVM accepts. The tracker probes every entry. */
489
496
  mints: string[];
497
+ /** Host environment used for default timing and failure settings. */
498
+ env?: Record<string, string | undefined>;
490
499
  /**
491
500
  * Tick cadence in ms. Defaults to {@link DEFAULT_TICK_INTERVAL_MS} or the
492
501
  * `DVMKIT_MINT_HEALTH_TICK_MS` env var when set.
@@ -497,9 +506,7 @@ interface MintHealthTrackerOptions {
497
506
  * {@link DEFAULT_FAILURES_TO_SICK} or `DVMKIT_MINT_FAILURES_TO_SICK` env.
498
507
  */
499
508
  consecutiveFailuresToSick?: number;
500
- /** Injected `fetch` for tests. */
501
509
  fetchImpl?: typeof fetch;
502
- /** Injected `Date.now` for tests. */
503
510
  now?: () => number;
504
511
  /**
505
512
  * Per-probe timeout / retry / backoff, forwarded to {@link checkMintHealth}.
@@ -542,7 +549,7 @@ declare class MintHealthTracker {
542
549
  /**
543
550
  * True once the first full probe tick has landed. Before this, paid calls
544
551
  * are held at `503 mint_health_pending` rather than accepted against
545
- * unvalidated mints (internal-review).
552
+ * unvalidated mints.
546
553
  */
547
554
  initialProbeComplete(): boolean;
548
555
  /**
@@ -559,7 +566,7 @@ declare class MintHealthTracker {
559
566
  * gate — a deterministic, permanent config error, unlike a transient outage.
560
567
  * Unknown mints return false. `advertisedMints()` uses this to keep a
561
568
  * permanently-unsettleable mint off `/v1/info` even in the all-sick fallback,
562
- * where a merely-flapping mint is still published (internal-review).
569
+ * where a merely-flapping mint is still published.
563
570
  */
564
571
  isNutIncompatible(mintUrl: string): boolean;
565
572
  /** Plain-object snapshot keyed by mint URL — for tests + observability. */
@@ -569,37 +576,37 @@ declare class MintHealthTracker {
569
576
  * One-shot structured summary emitted after the first probe tick. Replaces
570
577
  * the boot check's per-mint `cashu_mint_startup_health` lines and surfaces an
571
578
  * all-mints-unhealthy warning — the operator alert that the Fly restart-loop
572
- * used to be before boot stopped refusing to start (internal-review).
579
+ * used to be before boot stopped refusing to start.
573
580
  */
574
581
  private logBootHealth;
575
582
  }
576
583
 
577
584
  /**
578
- * Credit fields riding the signed request body (internal-review, spec §2).
585
+ * Credit fields carried inside the signed request body.
579
586
  *
580
587
  * An explicit draw references the credit INSIDE the secp256k1/Schnorr-signed
581
588
  * `body.data` — no new caller crypto. Wire field names (snake_case, matching
582
589
  * the rest of the wire surface):
583
590
  *
584
591
  * - `credit_id` — the credit to draw against.
585
- * - `draw_id` — client-generated draw id; the ledger's idempotency key.
586
- * - `fund` — optional `{ amount_micro, commitment }` funding commitment:
587
- * present iff a funding artifact (X-Cashu / X-PAYMENT / mpp credential)
588
- * rides the same request. `commitment` is the SHA-256 hex over the raw
589
- * artifact bytes, binding the header-borne proof — which sits OUTSIDE the
590
- * signed body — to the credit its sender intended (spec §2 condition 3).
592
+ * - `draw_id` — client-generated draw id; the ledger's idempotency key.
593
+ * - `fund` — optional `{ amount_micro, commitment }` funding commitment:
594
+ * present iff a funding artifact (X-Cashu / X-PAYMENT / mpp credential)
595
+ * rides the same request. `commitment` is the SHA-256 hex over the raw
596
+ * artifact bytes, binding the header-borne proof — which sits OUTSIDE the
597
+ * signed body — to the credit its sender intended (the funding-commitment rule).
591
598
  *
592
599
  * These are envelope-level fields, not capability input: **the SDK** removes
593
600
  * them before any builder-owned schema parses ({@link stripCreditEnvelope} in
594
601
  * `JobManager.parseInput` and on the quote path; {@link
595
602
  * creditEnvelopeIgnoreFields} feeding the auth verifier's own schema check), so
596
603
  * handlers never see them and a top-level `.strict()` capability schema is
597
- * fine (internal-review). Relying on Zod's default strip mode instead was the trap:
604
+ * fine. Relying on Zod's default strip mode instead was the trap:
598
605
  * `.strict()` rejects unknown keys, so an explicit draw 400'd at parse before
599
606
  * the envelope was ever extracted.
600
607
  *
601
608
  * The strip never touches the canonical signing bytes. Every auth call site
602
- * verifies the raw wire body (`signedRequestInput`, internal-review), so the credit
609
+ * verifies the raw wire body (`signedRequestInput`), so the credit
603
610
  * fields are in the verified bytes because they were never taken out of them —
604
611
  * the strip is only ever applied to what a schema is about to parse.
605
612
  */
@@ -634,7 +641,7 @@ declare class CreditEnvelopeError extends Error {
634
641
  declare function extractCreditEnvelope(data: unknown): CreditEnvelope | undefined;
635
642
  /**
636
643
  * The reserved keys `schema` does not itself declare — the ones the SDK is
637
- * free to remove before handing it an input (internal-review).
644
+ * free to remove before handing it an input.
638
645
  *
639
646
  * A capability schema declares none of them, so all three are removable. The
640
647
  * one exception this exists for is `/v1/credit`'s own `CREDIT_REQUEST_SCHEMA`,
@@ -648,7 +655,7 @@ declare function extractCreditEnvelope(data: unknown): CreditEnvelope | undefine
648
655
  declare function creditEnvelopeIgnoreFields(schema: unknown): readonly string[];
649
656
  /**
650
657
  * Remove the reserved credit keys from `data` before `schema` parses it, so a
651
- * strict schema doesn't reject the protocol's own envelope (internal-review). Keys
658
+ * strict schema doesn't reject the protocol's own envelope. Keys
652
659
  * `schema` declares are left alone — see {@link creditEnvelopeIgnoreFields}.
653
660
  *
654
661
  * Returns `data` unchanged when it isn't a plain object or carries none of the
@@ -659,10 +666,10 @@ declare function creditEnvelopeIgnoreFields(schema: unknown): readonly string[];
659
666
  declare function stripCreditEnvelope(schema: unknown, data: unknown): unknown;
660
667
 
661
668
  /**
662
- * Fiat denomination of the job price, pinned per request (internal-review).
669
+ * Fiat denomination of the job price, pinned per request.
663
670
  *
664
- * The credit ledger is fiat-micro denominated (internal-review baked decision:
665
- * 1e-6 of the DVM's pricing currency, never msats). The conversion pins at
671
+ * The credit ledger is fiat-micro denominated: 1e-6 of the DVM's pricing
672
+ * currency, never msats. The conversion pins at
666
673
  * quote time: the verify path already fixes both the fiat price and its msat
667
674
  * equivalent, so the implicit N=1 fund credits the QUOTED fiat amount when
668
675
  * the attached token satisfies the quoted msats — no fresh BTC/USD lookup in
@@ -677,36 +684,13 @@ interface PriceFiat {
677
684
  }
678
685
 
679
686
  /**
680
- * Resolve the fiat denomination for a request's price (internal-review).
681
- *
682
- * Both sources are already fiat-exact, so this never consults an fx rate —
683
- * which is the point: since internal-review removed numeric-msats prices there is no
684
- * price form that needs one, and the ledger can be denominated for every paid
685
- * request rather than only the ones a rate provider happened to be up for.
686
- *
687
- * - `dynamicUpfront` — the validated `QuoteResult.upfront` fiat envelope a
688
- * dynamic-priced capability returned for THIS request.
689
- * - a static `"$X.XX"` price — parsed directly.
690
- *
691
- * Returns `undefined` for free jobs (`priceMsats` unset or 0). For a paid job
692
- * it always returns a denomination: `validateQuoteResult` rejects a dynamic
693
- * amount too small or too large to express in micro-units, and `configureDVM`
694
- * rejects a static price with the same defect at boot.
695
- *
696
- * internal-review: whichever branch answers, the currency is the DVM's declared
697
- * pricing currency, so a job draws in the denomination `/v1/credit` funded in.
698
- * Held there by two guards outside this function, which is why neither branch
699
- * needs to know the DVM's currency to return it — `validateQuoteResult`
700
- * refuses a quote that disagrees with the declaration, and `configureDVM`
701
- * refuses a static (USD-literal) price on a DVM that declares anything but
702
- * `"usd"`. Both refuse rather than convert, deliberately: an fx lookup on this
703
- * path is the internal-review shape, where a cold-start rate outage took money and
704
- * recorded no draw.
687
+ * Paid requests pin the validated fiat price without an FX lookup. Free jobs
688
+ * return undefined. configureDVM and validateQuoteResult enforce micro-unit
689
+ * range and the DVM's declared currency before this helper is called; neither
690
+ * guard converts a mismatched currency.
705
691
  */
706
692
  declare function resolvePriceFiat(args: {
707
- /** The capability's static `price` value, if any. */
708
693
  price: string | undefined;
709
- /** The resolved required price in msats (static or dynamic). */
710
694
  priceMsats: number | undefined;
711
695
  /** Fiat envelope from a dynamic quote, when the price came from `onQuote`. */
712
696
  dynamicUpfront?: {
@@ -715,28 +699,11 @@ declare function resolvePriceFiat(args: {
715
699
  };
716
700
  }): PriceFiat | undefined;
717
701
  /**
718
- * The micro-unit half of {@link resolvePriceFiat}, without its "is this job
719
- * paid at all" gate — the one derivation every surface that states an exact
720
- * fiat price reads (internal-review).
721
- *
722
- * A caller doing an explicit fund-and-draw has to sign the provider's own
723
- * valuation of the artifact it attaches (`price_micro × paid_msats /
724
- * required_msats`), and `price_micro` is `PriceFiat.amountMicro`. Reconstructing
725
- * that integer from a rendered decimal is lossy the moment any surface between
726
- * the two rounds — the isolate tier advertises at four decimals, and the CLI's
727
- * synthetic quote used to re-round a 402 the same way — so `/v1/quote`'s
728
- * `upfront.amount_micro` and the upfront 402's `price_micro` state the integer
729
- * itself. Both **must** derive through here rather than recomputing: two
730
- * independent derivations of one figure is the shape that produced the mismatch
731
- * these fields exist to remove.
732
- *
733
- * The `priceMsats` gate stays on `resolvePriceFiat` alone. An advertisement
734
- * surface has no msat figure in hand — the quote route states a price before
735
- * anything has converted it — and a free capability is already excluded there
736
- * by having no price to pass.
702
+ * Shared exact integer for quote, 402 and ledger valuation. Callers must sign
703
+ * this micro-unit figure rather than reconstruct it from a rounded display.
704
+ * Unlike resolvePriceFiat, advertisement callers need no msat price in hand.
737
705
  */
738
706
  declare function priceFiatMicro(args: {
739
- /** The capability's static `price` value, if any. */
740
707
  price?: string | undefined;
741
708
  /** Fiat envelope from a dynamic quote, when the price came from `onQuote`. */
742
709
  dynamicUpfront?: {
@@ -744,17 +711,7 @@ declare function priceFiatMicro(args: {
744
711
  currency: string;
745
712
  };
746
713
  }): PriceFiat | undefined;
747
- /**
748
- * Why a denomination could not be produced (internal-review). Carried out of
749
- * {@link msatsToFiatMicro} and {@link resolveFxSnapshot} so the skip that
750
- * follows can name its cause.
751
- *
752
- * Every one of these used to collapse into a bare `undefined`, which is how a
753
- * `credit_topup_skipped` / `denomination_unavailable` line came to be
754
- * undiagnosable: a rate outage, a currency the snapshot never carried, and an
755
- * ask too small to express in micro-units all read identically in the log, and
756
- * the only way to tell them apart was to re-derive the whole path by hand.
757
- */
714
+ /** Reasons are kept distinct so a skipped ledger leg identifies its cause. */
758
715
  type FiatDenominationFailure =
759
716
  /** Nothing to convert — a zero-msat ask. */
760
717
  "no_msats"
@@ -771,7 +728,7 @@ type FiatDenominationFailure =
771
728
  | "rate_stale_refused";
772
729
  /**
773
730
  * An fx snapshot plus how fresh it is, or why there is none. `stale` means the
774
- * live fetch failed and this is the last snapshot the fetcher saw (internal-review);
731
+ * live fetch failed and this is the last snapshot the fetcher saw;
775
732
  * `cachedAt` is the Unix ms it landed.
776
733
  */
777
734
  type ResolvedFx = {
@@ -790,7 +747,7 @@ type ResolvedFx = {
790
747
  * `stale` covers both degradation rungs and `carriedForward` distinguishes
791
748
  * them: either the whole snapshot came from `lastKnown()` because the live
792
749
  * fetch failed, or the fetch succeeded and only *this* currency was carried
793
- * over from an earlier one because the body omitted it (internal-review). They read
750
+ * over from an earlier one because the body omitted it. They read
794
751
  * differently to an operator — the rate source down, versus the rate source
795
752
  * having quietly narrowed — so the log says which.
796
753
  */
@@ -806,80 +763,51 @@ type FiatDenomination = {
806
763
  detail?: string;
807
764
  };
808
765
  /**
809
- * Resolve an fx snapshot for a denomination hop, degrading to the fetcher's
810
- * last-known one when the live fetch fails (internal-review).
811
- *
812
- * The same ladder `resolveServerBtcUsdRate` walks for the x402/Tempo rails
813
- * (`btc-rate.ts`), and it exists here because the mid-job top-up's two fx legs
814
- * — the ask-time pin in `context.ts` and the verify-time hop in
815
- * {@link msatsToFiatMicro} — were the only ones in the payment layer that
816
- * called `fetch()` raw and swallowed the throw. `FxFetcher.lastKnown` is
817
- * documented as "the offline degradation source for the payment rail", so a
818
- * process holding a perfectly good snapshot was nonetheless dropping the
819
- * receipt's whole `credit` block over one blip at the rate provider.
820
- *
821
- * **A known-stale refusal fails closed and never degrades** (internal-review): the
822
- * platform decided the snapshot is too old to price against, so serving the
823
- * last-known one prices off exactly what it refused. Every other failure
824
- * degrades, which is the internal-review posture.
825
- *
826
- * No cool-down latch, unlike `resolveServerBtcUsdRate`. That one guards a
827
- * per-request hot path; this runs at most twice per mid-job ask, and a latch
828
- * shared across every DVM in the process would suppress the recovery probe a
829
- * long-lived host needs.
766
+ * A live fetch failure may use lastKnown(), but a known-stale refusal never
767
+ * does: that would use the very snapshot the platform refused. No shared
768
+ * cooldown suppresses the recovery probe on a later mid-job ask.
830
769
  */
831
770
  declare function resolveFxSnapshot(fetcher: FxFetcher): Promise<ResolvedFx>;
832
771
  /**
833
- * Convert an msat amount into a target currency's micro-units through the
834
- * shared fx snapshot (internal-review) — the denomination for a mid-job
835
- * `requestPayment` ask that carries no fiat envelope of its own.
836
- *
837
- * internal-review removed the numeric-msats *price*, so {@link resolvePriceFiat} needs
838
- * no rate; the mid-job ask is the one surface where a bare msat amount survives
839
- * (`ctx.requestPayment(50_000, …)`), and the credit it tops up may be
840
- * denominated in a currency the ask never named. An fx hop is the only way to
841
- * put either on the ledger.
842
- *
843
- * Answers a *reason* rather than `undefined` when it can't denominate — the
844
- * caller still accepts the money and skips the ledger leg rather than refusing
845
- * over a rate outage (internal-review), but it can now say which failure it degraded
846
- * on (internal-review). That fail-soft is why this stays separate from
847
- * `resolvePriceFiat`, which is now total for every paid request.
772
+ * Bare-msat mid-job asks need an FX conversion into the credit's currency.
773
+ * Failure carries a reason: callers accept the payment and skip its ledger
774
+ * leg rather than refusing over an outage. Upfront prices use resolvePriceFiat
775
+ * and require no rate, so they do not share this fail-soft behavior.
848
776
  */
849
777
  declare function msatsToFiatMicro(args: {
850
778
  msats: number;
851
779
  currency: string;
852
780
  fxFetcher: FxFetcher;
853
781
  /**
854
- * A snapshot already in hand (internal-review). The mid-job ask path fetches one to
782
+ * A snapshot already in hand. The mid-job ask path fetches one to
855
783
  * size a fiat-form ask's msats; converting on that same snapshot costs no
856
784
  * second fetch and keeps the two figures arithmetically consistent.
857
785
  */
858
786
  snapshot?: FxRateSnapshot;
859
787
  }): Promise<FiatDenomination>;
860
788
  /**
861
- * The mid-job ask's fiat pin, in the target currency (internal-review) — what the cap
789
+ * The mid-job ask's fiat pin, in the target currency — what the cap
862
790
  * on this job's cumulative draw growth is summed from, and what the top-up
863
791
  * funds against.
864
792
  *
865
793
  * Two differences from {@link msatsToFiatMicro}, both scoped to the ask:
866
794
  *
867
795
  * - **A fiat-form ask already in the target currency is taken verbatim**, so a
868
- * `ctx.requestPayment({ amount, currency })` keeps the exactness it has and
869
- * never round-trips through a rate. Any other form converts `msats` on the
870
- * caller's snapshot — including a fiat-form ask in some *other* currency,
871
- * which converts on the very snapshot that sized its msats, so the pin and
872
- * the wire ask can't disagree about the rate.
796
+ * `ctx.requestPayment({ amount, currency })` keeps the exactness it has and
797
+ * never round-trips through a rate. Any other form converts `msats` on the
798
+ * caller's snapshot — including a fiat-form ask in some *other* currency,
799
+ * which converts on the very snapshot that sized its msats, so the pin and
800
+ * the wire ask can't disagree about the rate.
873
801
  * - **Floors at one micro-unit rather than returning `undefined`.**
874
- * `ctx.requestPayment(500)` is half a micro at $100k/BTC — a legitimate, if
875
- * tiny, ask, and refusing to denominate it poisons the job's whole ask total
876
- * and with it the ceiling. One micro is provably conservative for a ceiling:
877
- * the ask is worth less than that. `resolvePriceFiat` and `msatsToFiatMicro`
878
- * keep their sub-micro refusals, which are load-bearing on the upfront path.
802
+ * `ctx.requestPayment(500)` is half a micro at $100k/BTC — a legitimate, if
803
+ * tiny, ask, and refusing to denominate it poisons the job's whole ask total
804
+ * and with it the ceiling. One micro is provably conservative for a ceiling:
805
+ * the ask is worth less than that. `resolvePriceFiat` and `msatsToFiatMicro`
806
+ * keep their sub-micro refusals, which are load-bearing on the upfront path.
879
807
  *
880
808
  * Throws only what `fxRateFor` throws — an unsupported target currency, or an
881
809
  * `fx_rate_unavailable` for one the snapshot never carried. The ask path catches
882
- * both and degrades to an unpinnable ask (internal-review), naming which it was.
810
+ * both and degrades to an unpinnable ask, naming which it was.
883
811
  */
884
812
  declare function pinAskFiat(args: {
885
813
  msats: number;
@@ -892,65 +820,29 @@ declare function pinAskFiat(args: {
892
820
  }): PriceFiat | undefined;
893
821
  /**
894
822
  * Fiat micro-units actually funded for a rail payment of `paidMsats` against
895
- * a job quoted at `requiredMsats` ↔ `priceFiat` (operator ruling: overpay
896
- * funds and draws the FULL paid amount — ledger truth equals money truth).
823
+ * a job quoted at `requiredMsats` ↔ `priceFiat`. An overpayment funds and draws
824
+ * the full paid amount so ledger value matches money received.
897
825
  * Pro-rata at the quote-pinned ratio, so the exact-payment case — what every
898
826
  * conformant client sends — is `priceFiat.amountMicro` with zero drift.
899
827
  */
900
828
  declare function fundedMicroFor(priceFiat: PriceFiat, paidMsats: number, requiredMsats: number): number;
901
829
  /**
902
- * The µUSDC figure an x402 402 advertises as `maxAmountRequired`, and the same
903
- * figure the settled authorization is valued against at submit (internal-review).
904
- *
905
- * **A USD-priced job states its price verbatim.** USDC is a six-decimal USD
906
- * stablecoin, and `priceFiat.amountMicro` is already an exact USD micro figure,
907
- * so the advertisement is the price — no rate in the derivation, and therefore
908
- * no way for the 402 and the submit to disagree about it.
909
- *
910
- * The BTC hop this replaces was not merely lossy, it was *unpinned*. The 402 is
911
- * stateless, so the figure was recomputed at submit from whatever the fx cache
912
- * held by then, through two rate-dependent roundings: `resolveStaticPriceMsats`
913
- * ceils the price to a whole **satoshi**, and `msatsToUsdc` ceils that back to
914
- * µUSDC. A rate refresh between the 402 and the payment therefore moved the
915
- * reconstruction by up to a satoshi's worth (~$0.0013 at $100k/BTC) — and when
916
- * it moved down, the caller's exact payment read as an overpayment, pro-rated
917
- * above `price_micro`, and was refused `funding_commitment_mismatch` *after*
918
- * the facilitator had settled. Money moved, no job, no credit. The sat-ceil
919
- * also overcharged every x402 caller outright: at $0.01 and $97,432/BTC the
920
- * quote is 11 sats and the old advertisement demanded 10,718 µUSDC — 7% above
921
- * the price the caller was quoted and the ledger recorded.
922
- *
923
- * Every caller gates x402 on a USD-priced DVM before reaching this helper.
924
- * Keeping the helper USD-only makes a future advertisement call site fail
925
- * closed instead of quietly restoring the rate-derived non-USD path.
830
+ * USD micro-units are already USDC's six-decimal units. Advertise them verbatim
831
+ * and value settlement against the same figure; a BTC conversion would add
832
+ * rounding and an unpinned rate between challenge and settlement.
833
+ * Non-USD callers fail closed rather than implicitly introducing that FX hop.
926
834
  */
927
835
  declare function x402RequiredUsdcMicro(priceFiat: PriceFiat): number;
928
836
  /**
929
- * A settled x402 authorization's share of a quoted figure, taken against the
930
- * `maxAmountRequired` the 402 advertised (internal-review) — `quoted` unmodified when
931
- * the authorization paid exactly that, pro-rata otherwise. Unit-agnostic like
932
- * {@link fundedMicroFor}: the same ratio restates the job's fiat price and its
933
- * msat quote, so the two frames can never disagree about what landed.
934
- *
935
- * x402 must NOT reach {@link fundedMicroFor} through `usdcToMsats`. The
936
- * advertised figure is stated in µUSDC by {@link x402RequiredUsdcMicro} — the
937
- * price verbatim for a USD job — and the
938
- * receipt converts back with `usdcToMsats`, a `Math.round`, which is the
939
- * inverse of neither. The round trip lands at or above `requiredMsats`, which
940
- * took the pro-rata branch and valued a payment of exactly the advertised
941
- * amount above `price_micro`. That mismatch used to be refused only after the
942
- * facilitator had broadcast the transfer, so a conformant caller signing the
943
- * quoted price lost the payment outright (the gate now also runs pre-settle —
944
- * internal-review).
945
- *
946
- * Valuing in the rail's own units removes the manufactured disagreement and
947
- * nothing else: a genuine overpayment still pro-rates, and both inputs are on
948
- * the 402, so the caller can derive the figure it must sign from that alone.
837
+ * Value a settled authorization against the advertised USDC amount, preserving
838
+ * the quote at exact payment and prorating genuine over/underpayment. Use this
839
+ * ratio for both fiat and msat frames: a USDC-to-msat round trip can round an
840
+ * exact payment into a false overpayment and invalidate its signed commitment.
949
841
  */
950
842
  declare function x402SettledShare(quoted: number, requiredUsdcMicro: number, settledUsdcMicro: number): number;
951
843
  /**
952
844
  * SHA-256 hex over the raw funding artifact — the value an explicit
953
- * fund-and-draw request must sign as `fund.commitment` (spec §2 condition 3).
845
+ * fund-and-draw request must sign as `fund.commitment` (the funding-commitment rule).
954
846
  * The artifact is the exact header-borne string: the `X-Cashu` header value,
955
847
  * the `X-PAYMENT` header value, or the extracted `Payment <…>` mpp scheme
956
848
  * string. Hashing the verbatim wire string keeps the commitment computable by
@@ -964,14 +856,14 @@ declare function fundingCommitment(artifact: string): string;
964
856
  declare function implicitCreditId(rail: "cashu" | "x402" | "tempo", paymentId: string): string;
965
857
  /**
966
858
  * Whether a credit id sits in a namespace the server derives — which a caller
967
- * may **reference** but must never **create** (internal-review).
859
+ * may **reference** but must never **create**.
968
860
  *
969
861
  * Both namespaces are computable by a third party: `imp:` from the rail's
970
862
  * payment id, `fnd:` from `(pubkey, fund_id)`. `CreditLedger.fund` INSERTs at
971
863
  * whatever id it is handed, so without this rule anyone could pre-open a
972
864
  * credit at an id the server would later derive for someone else. The victim's
973
865
  * top-up then settles on the rail before `fund` refuses with `caller_mismatch`
974
- * — they pay and hold nothing. Keeping creation server-side means a derived id
866
+ * they pay and hold nothing. Keeping creation server-side means a derived id
975
867
  * is only ever owned by the caller it was derived for.
976
868
  *
977
869
  * Referencing stays open, and has to: the id of a credit opened this way is
@@ -981,7 +873,7 @@ declare function implicitCreditId(rail: "cashu" | "x402" | "tempo", paymentId: s
981
873
  declare function isDerivedCreditId(creditId: string): boolean;
982
874
  /**
983
875
  * Deterministic credit id for a `/v1/credit` top-up that names no credit —
984
- * the documented "omit `credit_id` to open a new one" flow (internal-review).
876
+ * the documented "omit `credit_id` to open a new one" flow.
985
877
  *
986
878
  * Minting a fresh random id per attempt would make that flow the one top-up
987
879
  * shape that is *not* retry-safe: the second attempt looks up
@@ -998,8 +890,8 @@ declare function isDerivedCreditId(creditId: string): boolean;
998
890
  */
999
891
  declare function derivedFundCreditId(callerPubkey: string, fundId: string): string;
1000
892
  /**
1001
- * Settlement reference stamped on the revenue event of an **explicit** draw
1002
- * (internal-review). One funding backs N draws, so the funding's own rail reference
893
+ * Settlement reference stamped on the revenue event of an **explicit** draw;
894
+ * one funding backs N draws, so the funding's own rail reference
1003
895
  * cannot key them: `revenue_events` carries a global `UNIQUE (rail, tx_hash)`
1004
896
  * that deliberately drops cross-job reuse of a settlement reference, and
1005
897
  * reusing it would silently discard every draw but the first.
@@ -1013,17 +905,17 @@ declare function drawSettlementRef(dvmId: string, creditId: string, drawId: stri
1013
905
 
1014
906
  /**
1015
907
  * Durable marker for a rail payment that already funded the credit ledger
1016
- * (internal-review, spec §2 condition 3). The x402 and mpp rails have no dvmkit-side
908
+ * (the funding-commitment rule). The x402 and mpp rails have no dvmkit-side
1017
909
  * commit point of their own — the money moves at the facilitator / the payer's
1018
910
  * mpp server — so the marker row, inserted in the SAME transaction as
1019
911
  * `CreditLedger.fund` + `draw`, is what makes a crash-replayed credential
1020
912
  * unable to fund twice: the second attempt collides on the primary key and
1021
913
  * surfaces as {@link ProcessedPaymentReplayError}, which the verifier routes
1022
- * into the internal-review recovery gates instead of a second fund.
914
+ * into the recovery gates instead of a second fund.
1023
915
  *
1024
916
  * The Cashu rail does not use this store — its accumulator insert is already
1025
917
  * the durable commit point, and its replay key (the `X-Cashu-Request-Id`
1026
- * regime) must stay exactly as-is (dual-idempotency rule, spec §2).
918
+ * regime) must stay exactly as-is (dual-idempotency rule, the signed credit contract).
1027
919
  */
1028
920
  interface ProcessedPaymentStore {
1029
921
  /**
@@ -1086,7 +978,7 @@ declare class PostgresProcessedPaymentStore implements ProcessedPaymentStore {
1086
978
  withTx<T>(fn: (tx?: ProcessedPaymentQuerier) => Promise<T>): Promise<T>;
1087
979
  /** Create the `processed_payments` table if absent. Call once at SDK boot. */
1088
980
  init(): Promise<void>;
1089
- /** The boot DDL itself — always runs under {@link withSdkInitLock} (internal-review). */
981
+ /** The boot DDL itself — always runs under {@link withSdkInitLock}. */
1090
982
  private createTables;
1091
983
  record(args: {
1092
984
  dvmId: string;
@@ -1128,7 +1020,7 @@ declare class MemoryProcessedPaymentStore implements ProcessedPaymentStore {
1128
1020
  /**
1129
1021
  * Machine codes an accumulator-path receive can reject with. Named and exported
1130
1022
  * so the payment-error builder in `payment.ts` folds them into `PaymentErrorCode`
1131
- * and keeps display/hint/retryable copy in lockstep with this union (internal-review).
1023
+ * and keeps display/hint/retryable copy in lockstep with this union.
1132
1024
  */
1133
1025
  type AccumulatorRejectionCode = "missing_request_id" | "missing_lock_pubkey" | "not_p2pk_locked" | "wrong_lock_pubkey" | "proof_not_unspent" | "proof_pending" | "replay_rejected" | "mint_unreachable" | "invalid_token";
1134
1026
 
@@ -1437,7 +1329,7 @@ interface X402BatchChannelObservation {
1437
1329
  refundNonce: number;
1438
1330
  }
1439
1331
  /**
1440
- * The chain submission behind an accepted voucher did not return success (internal-review).
1332
+ * The chain submission behind an accepted voucher did not return success.
1441
1333
  *
1442
1334
  * Typed and `retryable` because it is a service-availability fault, not a fault
1443
1335
  * in the credential: the voucher verified, the ledger leg rolled back, and the
@@ -1479,16 +1371,16 @@ interface X402BatchRefusal {
1479
1371
  * `false` when re-signing cannot fix this: the caller must be answered with a
1480
1372
  * terminal error rather than a 402 carrying fresh requirements, because an
1481
1373
  * agent reads a corrective 402 as "sign this and resubmit" and lands straight
1482
- * back on the same refusal (internal-review). Omitted means corrective.
1374
+ * back on the same refusal. Omitted means corrective.
1483
1375
  */
1484
1376
  corrective?: boolean;
1485
1377
  }
1486
1378
  /**
1487
- * What the chain says about one wedged settlement (internal-review).
1379
+ * What the chain says about one wedged settlement.
1488
1380
  *
1489
1381
  * The four answers are kept apart because their repairs differ and because an
1490
1382
  * operator re-pointing an RPC needs a definitive answer to read as definitive
1491
- * — the same split `LightningReceive.lookupSettlement` draws between
1383
+ * the same split `LightningReceive.lookupSettlement` draws between
1492
1384
  * `invoice_unknown_to_wallet` and `wallet_unreachable`. `findAppliedSettlement`
1493
1385
  * collapses all of them (`undefined` for absent *and* unbookmarked, a throw for
1494
1386
  * transport), so this is where they are separated.
@@ -1563,7 +1455,7 @@ interface X402SettlementRepaired<T> {
1563
1455
  }
1564
1456
  /**
1565
1457
  * The operator's exit from a settlement stuck between "chain paid" and "ledger
1566
- * booked" (internal-review).
1458
+ * booked".
1567
1459
  *
1568
1460
  * `reconcile` is the ordinary recovery path with the chain's figure substituted
1569
1461
  * for the facilitator's: the amount is re-derived from
@@ -1617,7 +1509,7 @@ interface X402BatchSettlementServer {
1617
1509
  * Required on `refund`: the credit's unspent balance in the channel token's
1618
1510
  * own units. It is the ceiling the on-chain payout is sized to, so that a
1619
1511
  * drain returns what the caller is owed and nothing the DVM has earned
1620
- * (internal-review). `commit` must re-assert it against the authoritative ledger
1512
+ * `commit` must re-assert it against the authoritative ledger
1621
1513
  * figure, since this one is read before the channel lock is taken.
1622
1514
  */
1623
1515
  refundBoundNative?: number;
@@ -1633,7 +1525,7 @@ interface X402BatchSettlementServer {
1633
1525
  * required in the *type*, because the payload the payer presents is
1634
1526
  * what revokes, settles and pays: a refund voucher naming another
1635
1527
  * channel would extinguish this credit's balance out of that channel's
1636
- * escrow (internal-review). The fund path binds in the ledger
1528
+ * escrow. The fund path binds in the ledger
1637
1529
  * (`credit-ledger.ts`'s `rail_mismatch`) and the Tempo close binds in
1638
1530
  * its credential verifier; this is x402's.
1639
1531
  */
@@ -1648,20 +1540,19 @@ interface X402BatchSettlementServer {
1648
1540
  claimAndSettle(): Promise<void>;
1649
1541
  /**
1650
1542
  * Operator repair for a settlement wedged between chain and ledger
1651
- * (internal-review). Absent without durable storage: with no settlement rows there
1543
+ * Absent without durable storage: with no settlement rows there
1652
1544
  * is no queue and nothing a repair could act on.
1653
1545
  */
1654
1546
  repair?: X402SettlementRepair;
1655
1547
  /**
1656
1548
  * The durable settlement read the credit ledger gates spending on
1657
- * (internal-review). Absent without durable storage, on the same reasoning as
1549
+ * Absent without durable storage, on the same reasoning as
1658
1550
  * {@link repair}: with no settlement rows nothing can be wedged, so there is
1659
1551
  * nothing to gate.
1660
1552
  */
1661
1553
  settlementGate?: X402RefundSettlementGate;
1662
1554
  stop(): Promise<void>;
1663
1555
  }
1664
- /** Options for constructing one DVM's batch-settlement server. */
1665
1556
  interface CreateX402BatchSettlementServerOpts {
1666
1557
  network: string;
1667
1558
  payTo: string;
@@ -1677,12 +1568,12 @@ interface CreateX402BatchSettlementServerOpts {
1677
1568
  rpcUrl?: string;
1678
1569
  db?: Pool;
1679
1570
  /**
1680
- * Durable store to adopt instead of building one from {@link db} (internal-review).
1571
+ * Durable store to adopt instead of building one from {@link db}.
1681
1572
  *
1682
1573
  * `createDVMServer` builds it at ledger construction, because the credit
1683
1574
  * ledger's spend gate has to exist whether or not this server is ever
1684
1575
  * constructed. Adopting it here keeps one `PostgresX402ChannelStorage` — and
1685
- * so one settlement pool — per mount, which is what the internal-review reasoning on
1576
+ * so one settlement pool — per mount, which is what the reasoning on
1686
1577
  * {@link PostgresX402ChannelStorage} rests on. Ignored when the config
1687
1578
  * supplies its own {@link X402BatchSettlementConfig.storage}.
1688
1579
  */
@@ -1694,7 +1585,7 @@ interface CreateX402BatchSettlementServerOpts {
1694
1585
  * `undefined` means the channel's credit could not be resolved.
1695
1586
  *
1696
1587
  * Required, not optional: it is the ceiling every claim is capped at
1697
- * (internal-review), and a server that cannot derive one must claim nothing rather
1588
+ * and a server that cannot derive one must claim nothing rather
1698
1589
  * than fall back to the deposit.
1699
1590
  */
1700
1591
  earnedNative: (channelId: string) => Promise<number | undefined>;
@@ -1705,13 +1596,13 @@ interface CreateX402BatchSettlementServerOpts {
1705
1596
  /** Authoritative channel-view override for deterministic tests. */
1706
1597
  channelStateReader?: (channelId: string) => Promise<X402BatchChannelObservation>;
1707
1598
  /**
1708
- * The payout tracker (internal-review). Attached with this server's settle scope
1599
+ * The payout tracker. Attached with this server's settle scope
1709
1600
  * and routed every claim and settle, so the batch that lands at `pay_to` is
1710
1601
  * reported with the value claimed into it, and the pending snapshot can say
1711
1602
  * what is still on the channels and whether the settle is wedged.
1712
1603
  *
1713
1604
  * @internal Wired by `createDVMServer` from the platform reporter; not a
1714
- * builder surface, and not part of the extractable SDK contract (internal-review).
1605
+ * builder surface, and not part of the extractable SDK contract.
1715
1606
  */
1716
1607
  payout?: X402PayoutObserver;
1717
1608
  }
@@ -1728,7 +1619,7 @@ interface PaymentInfo {
1728
1619
  /**
1729
1620
  * Rail value this payment contributes to the job, in millisatoshis.
1730
1621
  *
1731
- * For a credit-drawn job (internal-review) this is the **draw's** allocated share of
1622
+ * For a credit-drawn job this is the **draw's** allocated share of
1732
1623
  * the credit's rail value, not the amount the caller handed over on this
1733
1624
  * request — under an explicit fund-and-draw the caller may have funded twenty
1734
1625
  * jobs' worth. That makes it the revenue basis for this job: mid-job top-ups
@@ -1739,38 +1630,38 @@ interface PaymentInfo {
1739
1630
  /**
1740
1631
  * Rail that satisfied the upfront payment, if any. A {@link FundingMethod}
1741
1632
  * rather than a `PaymentMethod`: a draw against a Lightning-funded credit
1742
- * reports `"lightning"` here (internal-review), which is what lets the revenue
1633
+ * reports `"lightning"` here, which is what lets the revenue
1743
1634
  * ledger book it instead of silently dropping the row.
1744
1635
  */
1745
1636
  paymentRail?: FundingMethod;
1746
1637
  receivedProofs: ProofLike[];
1747
1638
  /**
1748
1639
  * Settlement reference for the credit. x402 carries the EVM tx hash from
1749
- * the facilitator (internal-review); mpp carries the credential's `challenge.id`,
1750
- * HMAC-bound to the realm so cross-DVM collisions are impossible (internal-review);
1751
- * cashu accumulator (internal-review) sets it to the `X-Cashu-Request-Id` UUID
1752
- * (internal-review). Required by the platform revenue ledger for `tempo`/`x402`
1640
+ * the facilitator; mpp carries the credential's `challenge.id`,
1641
+ * HMAC-bound to the realm so cross-DVM collisions are impossible;
1642
+ * cashu accumulator sets it to the `X-Cashu-Request-Id` UUID
1643
+ * Required by the platform revenue ledger for `tempo`/`x402`
1753
1644
  * rails; nullable for cashu's `tx_hash` column.
1754
1645
  */
1755
1646
  paymentTxHash?: string;
1756
1647
  /** Chain transaction returned to a caller recovering this accepted request. */
1757
1648
  paymentTransactionHash?: string;
1758
1649
  /**
1759
- * Rail-native payment amount in atomic units (internal-review). Sats for mpp,
1650
+ * Rail-native payment amount in atomic units. Sats for mpp,
1760
1651
  * USDC microunits for x402. Cashu leaves it unset — the existing
1761
1652
  * `paidMsats / 1000` derivation in the platform callback covers it.
1762
1653
  */
1763
1654
  nativeAmount?: number;
1764
- /** Native asset tag matching `revenue_events.native_asset` (internal-review). */
1655
+ /** Native asset tag matching `revenue_events.native_asset`. */
1765
1656
  nativeAsset?: "sats" | "usdc" | "usdc.e" | "usd-cents";
1766
1657
  /**
1767
1658
  * Discriminator written into `revenue_events.metadata.cashu_flow` so ops
1768
- * queries can split per-call cashu rows by source path (internal-review).
1659
+ * queries can split per-call cashu rows by source path.
1769
1660
  */
1770
1661
  cashuFlow?: "p2pk_accumulator";
1771
1662
  /**
1772
1663
  * Base64-encoded x402 `SettleResponse` for the `X-PAYMENT-RESPONSE`
1773
- * response header (internal-review). Set on the upfront-flow x402 success path;
1664
+ * response header. Set on the upfront-flow x402 success path;
1774
1665
  * `app.ts` attaches it to the 2xx response per x402 spec.
1775
1666
  */
1776
1667
  x402SettleResponseHeader?: string;
@@ -1781,21 +1672,21 @@ interface PaymentInfo {
1781
1672
  replayed: boolean;
1782
1673
  };
1783
1674
  /**
1784
- * Credit-ledger linkage (internal-review). Set whenever the payment funded and/or
1675
+ * Credit-ledger linkage. Set whenever the payment funded and/or
1785
1676
  * drew the ledger — every paid job with a ledger wired. Persisted on the
1786
1677
  * job so the terminal funnel can settle/release the draw and the receipt
1787
1678
  * can countersign the `ReceiptCredit` block.
1788
1679
  */
1789
1680
  creditId?: string;
1790
- /** The draw placed for this job on `creditId` (internal-review). */
1681
+ /** The draw placed for this job on `creditId`. */
1791
1682
  drawId?: string;
1792
- /** The draw's fiat amount, 1e-6 of {@link creditCurrency} (internal-review). */
1683
+ /** The draw's fiat amount, 1e-6 of {@link creditCurrency}. */
1793
1684
  drawAmountMicro?: number;
1794
- /** Currency the credit — and therefore the draw — is denominated in (internal-review). */
1685
+ /** Currency the credit — and therefore the draw — is denominated in. */
1795
1686
  creditCurrency?: string;
1796
1687
  /**
1797
1688
  * The funding leg, when this request actually moved money onto a credit
1798
- * (internal-review). Reported to the platform as a **deposit**: a liability until
1689
+ * Reported to the platform as a **deposit**: a liability until
1799
1690
  * drawn, never summed into revenue. Absent on a pure draw against an
1800
1691
  * existing balance.
1801
1692
  */
@@ -1805,7 +1696,7 @@ interface PaymentInfo {
1805
1696
  fundingCredit?: CreditSnapshot;
1806
1697
  /**
1807
1698
  * Fiat micro of {@link creditCurrency} this payment funded that bought the
1808
- * job **nothing** (internal-review) — a second payment for an ask the job's draw
1699
+ * job **nothing** — a second payment for an ask the job's draw
1809
1700
  * already covers, or the overpaid tail of an oversized one. It is available
1810
1701
  * balance on {@link creditId}, drainable at once, and the caller has to be
1811
1702
  * told or they will re-send. Absent on every ordinary payment.
@@ -1813,7 +1704,7 @@ interface PaymentInfo {
1813
1704
  unappliedMicro?: number;
1814
1705
  }
1815
1706
  /**
1816
- * A funding event as the platform books it — one deposit row (internal-review, spec
1707
+ * A funding event as the platform books it — one deposit row (spec
1817
1708
  * §10). Keyed on `(dvmId, creditId, fundingId)`, so a retried report is a
1818
1709
  * no-op rather than a double-count.
1819
1710
  */
@@ -1845,12 +1736,12 @@ interface CreditFundingReport {
1845
1736
  channelId: string;
1846
1737
  cumulativeAmount: string;
1847
1738
  };
1848
- /** TIP-1034 chain binding, reported so the platform can route a close (internal-review). */
1739
+ /** TIP-1034 chain binding, reported so the platform can route a close. */
1849
1740
  tempoChannel?: TempoChannelReport;
1850
1741
  }
1851
1742
  /**
1852
1743
  * The chain identity of a TIP-1034 channel, as reported to the platform
1853
- * alongside its deposit (internal-review). Read from the DVM's own durable channel
1744
+ * alongside its deposit. Read from the DVM's own durable channel
1854
1745
  * store, never from the caller's credential.
1855
1746
  */
1856
1747
  interface TempoChannelReport {
@@ -1858,7 +1749,6 @@ interface TempoChannelReport {
1858
1749
  escrow: string;
1859
1750
  payee?: string;
1860
1751
  }
1861
- /** Options for verifying an upfront payment on job submission. */
1862
1752
  interface UpfrontPaymentOpts {
1863
1753
  cashuToken?: string;
1864
1754
  requiredMsats?: number;
@@ -1875,7 +1765,7 @@ interface UpfrontPaymentOpts {
1875
1765
  /**
1876
1766
  * Resource URL the client retried against. Bound into the rebuilt
1877
1767
  * `PaymentRequirements` when verifying x402, and surfaced on the 402 body
1878
- * `accepts` array for x402 dual-serve (internal-review).
1768
+ * `accepts` array for x402 dual-serve.
1879
1769
  */
1880
1770
  x402Resource?: string;
1881
1771
  /** Either the structured credential object or its serialized `Authorization: Payment <…>` value. */
@@ -1884,17 +1774,17 @@ interface UpfrontPaymentOpts {
1884
1774
  /**
1885
1775
  * Request path of the resource being paid for (e.g. `/v1/job`). Bound into
1886
1776
  * each issued mppx challenge's `meta.path` so a credential can't be replayed
1887
- * against a different paid endpoint of the same DVM (internal-review).
1777
+ * against a different paid endpoint of the same DVM.
1888
1778
  */
1889
1779
  resourcePath?: string;
1890
1780
  /**
1891
1781
  * Whether `tempo/session` may be issued and newly accepted right now — the
1892
- * platform close-observer and hosted settlement-readiness gates (internal-review,
1893
- * internal-review), resolved per request by `DVMServer`. Absent means offered: a
1782
+ * platform close-observer and hosted settlement-readiness gates, resolved per
1783
+ * request by `DVMServer`. Absent means offered: a
1894
1784
  * self-hosted DVM operates these responsibilities itself.
1895
1785
  *
1896
1786
  * `false` refuses a session credential that would open a channel the platform
1897
- * cannot safely protect or settle (internal-review, internal-review), and withholds session
1787
+ * cannot safely protect or settle, and withholds session
1898
1788
  * challenges from every 402 this call emits, *except* on a credit already
1899
1789
  * bound to a TIP-1034 channel. That deposit is already exposed, so refusing
1900
1790
  * its vouchers only strands it; and since a channel-bound credit can be funded
@@ -1907,11 +1797,11 @@ interface UpfrontPaymentOpts {
1907
1797
  /**
1908
1798
  * Tracks consumed `(realm, challenge.id)` pairs so a credential that was
1909
1799
  * already accepted on the upfront path can't be replayed within its
1910
- * `expires` window (internal-review). Optional: when absent, the upfront flow has
1800
+ * `expires` window. Optional: when absent, the upfront flow has
1911
1801
  * no per-process replay protection beyond mppx's own expiry check.
1912
1802
  */
1913
1803
  consumedCredentialStore?: ConsumedCredentialStore;
1914
- /** Cashu receive mode (internal-review / internal-review). Routes the receive path. */
1804
+ /** Cashu receive mode. Routes the receive path. */
1915
1805
  cashuMode?: CashuMode;
1916
1806
  /** Per-DVM Postgres pool — required for the `p2pk-accumulator` path. */
1917
1807
  accumulatorDb?: AccumulatorPool;
@@ -1921,7 +1811,7 @@ interface UpfrontPaymentOpts {
1921
1811
  /**
1922
1812
  * Active NUT-11 P2PK lock pubkeys — required for the `p2pk-accumulator`
1923
1813
  * path. Includes the current pubkey followed by retired pubkeys still
1924
- * within the rotation grace window (internal-review). Caller resolves via
1814
+ * within the rotation grace window. Caller resolves via
1925
1815
  * `loadLockPubkeyState` per-request so rotations propagate without a
1926
1816
  * server restart.
1927
1817
  */
@@ -1929,7 +1819,7 @@ interface UpfrontPaymentOpts {
1929
1819
  /** UUIDv4 from `X-Cashu-Request-Id` header. */
1930
1820
  requestId?: string;
1931
1821
  /**
1932
- * Runtime mint-health tracker (internal-review). Receive path short-circuits with
1822
+ * Runtime mint-health tracker. Receive path short-circuits with
1933
1823
  * `cashu_mint_sick` when the token's mint is currently flagged sick, so
1934
1824
  * agents retry against a healthy alternative without waiting for the
1935
1825
  * per-call mint timeout to fire inside `acceptAccumulatorPayment`.
@@ -1937,14 +1827,14 @@ interface UpfrontPaymentOpts {
1937
1827
  mintHealthTracker?: MintHealthTracker;
1938
1828
  /**
1939
1829
  * Host fx fetcher used to price the non-sat rails (x402 USDC, mppx fiat)
1940
- * through the same BTC/USD source the quote path uses (internal-review). On a hosted
1830
+ * through the same BTC/USD source the quote path uses. On a hosted
1941
1831
  * DVM this is the platform-served snapshot; self-hosted defaults to
1942
1832
  * CoinGecko-direct. Optional: a lazy default fetcher stands in when unset, so
1943
1833
  * the payment path never reaches `fetchBtcUsdRate`.
1944
1834
  */
1945
1835
  fxFetcher?: FxFetcher;
1946
1836
  /**
1947
- * Credit ledger every payment funds and draws through (internal-review, spec §1):
1837
+ * Credit ledger every payment funds and draws through (the credit lifecycle contract):
1948
1838
  * an attached rail payment is an implicit N=1 funding — `fund` the paid
1949
1839
  * amount + `draw` it, atomically with the rail commit. When absent (or
1950
1840
  * when the price can't be fiat-denominated), the payment is accepted with
@@ -1953,21 +1843,21 @@ interface UpfrontPaymentOpts {
1953
1843
  */
1954
1844
  creditLedger?: CreditLedgerLike;
1955
1845
  /**
1956
- * Durable processed-payment markers for the x402/mpp rails (internal-review).
1846
+ * Durable processed-payment markers for the x402/mpp rails.
1957
1847
  * Those rails commit money outside dvmkit, so the marker row — written in
1958
1848
  * the same transaction as the ledger fund — is what makes a crash-replayed
1959
1849
  * credential unable to fund twice.
1960
1850
  */
1961
1851
  processedPayments?: ProcessedPaymentStore;
1962
1852
  /**
1963
- * Reporter-owned transactional outbox enqueue (internal-review). When present,
1853
+ * Reporter-owned transactional outbox enqueue. When present,
1964
1854
  * every funding awaits this inside the rail's commit transaction, so money
1965
1855
  * and its durable deposit report land together.
1966
1856
  */
1967
1857
  enqueueCreditDeposit?: CreditDepositEnqueue;
1968
1858
  /**
1969
1859
  * The job price's fiat denomination, pinned by the caller from the same
1970
- * quote surface that produced `requiredMsats` (internal-review). The ledger is
1860
+ * quote surface that produced `requiredMsats`. The ledger is
1971
1861
  * fiat-micro denominated; fund = draw = this amount in the exact-payment
1972
1862
  * case, so no fresh fx conversion happens on the verify hot path.
1973
1863
  */
@@ -1983,14 +1873,14 @@ interface UpfrontPaymentOpts {
1983
1873
  /** Requester id — funder identity fallback for DVMs without descriptor auth. */
1984
1874
  requesterId?: string;
1985
1875
  /**
1986
- * Explicit credit fields extracted from the signed body (spec §2). Their
1876
+ * Explicit credit fields extracted from the signed body (the signed credit contract). Their
1987
1877
  * signature coverage and structural validation happen in `app.ts` before
1988
1878
  * payment verification; this layer enforces ownership, the funding
1989
1879
  * commitment, and the draw itself.
1990
1880
  */
1991
1881
  creditEnvelope?: CreditEnvelope;
1992
1882
  /**
1993
- * Turn this verification into a **fund-only top-up** (internal-review): the rails
1883
+ * Turn this verification into a **fund-only top-up**: the rails
1994
1884
  * verify and commit exactly as they do for a job, but the ledger leg funds
1995
1885
  * without drawing — there is no job to pay for. Set by `POST /v1/credit`;
1996
1886
  * `requiredMsats` / `priceFiat` carry the requested top-up amount rather
@@ -2021,7 +1911,7 @@ interface FundOnlyRequest {
2021
1911
  /** Client-generated idempotency key for this deposit (`credit_fundings` PK). */
2022
1912
  fundId: string;
2023
1913
  /**
2024
- * SHA-256 hex over the raw funding artifact, signed by the caller (spec §2
1914
+ * SHA-256 hex over the raw funding artifact, signed by the caller (the signed credit contract
2025
1915
  * condition 3). Checked before any rail work: it is what binds the artifact
2026
1916
  * presented on the header to the deposit named in the signed body.
2027
1917
  */
@@ -2033,14 +1923,14 @@ interface PaymentErrorDetail {
2033
1923
  status: number;
2034
1924
  /**
2035
1925
  * mppx challenges to advertise via `WWW-Authenticate` headers on the 402
2036
- * response (internal-review). Populated whenever the DVM has an mppx handle and
1926
+ * response. Populated whenever the DVM has an mppx handle and
2037
1927
  * the request is short on payment — including on payment_invalid, since
2038
1928
  * draft-ryan-httpauth-payment-01 requires a fresh challenge on rejection.
2039
1929
  */
2040
1930
  mppChallenges?: Challenge.Challenge[];
2041
1931
  /**
2042
1932
  * x402 `PaymentRequirements` to merge into the 402 body's `accepts`
2043
- * array under the `x402Version` envelope (internal-review). Populated when the
1933
+ * array under the `x402Version` envelope. Populated when the
2044
1934
  * DVM has x402 wired and dual-serve is on.
2045
1935
  */
2046
1936
  x402Requirements?: PaymentRequirements[];
@@ -2049,30 +1939,30 @@ interface PaymentErrorDetail {
2049
1939
  /**
2050
1940
  * Scheme-level error code for the x402 v2 envelope, kept apart from the
2051
1941
  * body's human `message` because a scheme client matches on it verbatim to
2052
- * decide whether a 402 is correctable (internal-review).
1942
+ * decide whether a 402 is correctable.
2053
1943
  */
2054
1944
  x402ErrorCode?: string;
2055
1945
  /**
2056
1946
  * On a `replay_rejected` from the x402/mpp processed-payment marker
2057
- * (internal-review): the payment id the original funding committed under. The
2058
- * route feeds it to the internal-review recovery gates (jobs persist it as
1947
+ * the payment id the original funding committed under. The
1948
+ * route feeds it to the recovery gates (jobs persist it as
2059
1949
  * `payment_tx_hash`) so a crash-replayed credential can recover its
2060
1950
  * original job instead of a bare 409.
2061
1951
  */
2062
1952
  replayPaymentId?: string;
2063
1953
  /**
2064
1954
  * A short payment that was kept under the fail-closed posture and settled
2065
- * on the spot (internal-review). The route books it as revenue under a synthetic
1955
+ * on the spot. The route books it as revenue under a synthetic
2066
1956
  * job id — no job exists to carry it — tagged so it stays separable from
2067
1957
  * per-job service revenue.
2068
1958
  */
2069
1959
  forfeit?: ShortPayForfeit;
2070
1960
  /**
2071
- * Money that landed on a credit even though this request failed (internal-review,
2072
- * internal-review). Set when a short mid-job pay funds without completing its ask,
1961
+ * Money that landed on a credit even though this request failed. Set when a
1962
+ * short mid-job pay funds without completing its ask,
2073
1963
  * or an explicit upfront fund-and-draw commits the deposit but the combined
2074
1964
  * balance cannot cover the draw. In both cases the caller keeps an available
2075
- * balance they can reclaim under the internal-review drain. That is a liability, so
1965
+ * balance they can reclaim under the drain. That is a liability, so
2076
1966
  * the deposit has to reach the platform on the 402 path exactly as it does on
2077
1967
  * the success path, or the outstanding-liability view is short by precisely
2078
1968
  * the money we still owe.
@@ -2085,7 +1975,7 @@ interface PaymentErrorDetail {
2085
1975
  */
2086
1976
  funding?: CreditFundingReport;
2087
1977
  }
2088
- /** A kept-but-undelivered short payment, ready to be booked as tagged revenue (internal-review). */
1978
+ /** A kept-but-undelivered short payment, ready to be booked as tagged revenue. */
2089
1979
  interface ShortPayForfeit {
2090
1980
  /** Cashu request id — the rail settlement reference. */
2091
1981
  paymentId: string;
@@ -2101,9 +1991,9 @@ type PaymentResult = PaymentInfo & {
2101
1991
  error?: PaymentErrorDetail;
2102
1992
  /**
2103
1993
  * The signed body's `(credit_id, draw_id)` matches an already-recorded
2104
- * draw (internal-review, spec §2 condition 1 — the explicit idempotency regime).
1994
+ * draw (the draw-idempotency rule — the explicit idempotency regime).
2105
1995
  * No rail work ran and no second hold was placed; the route applies the
2106
- * internal-review proof-of-origin gates and re-issues the original job's response.
1996
+ * proof-of-origin gates and re-issues the original job's response.
2107
1997
  */
2108
1998
  replayedDraw?: {
2109
1999
  creditId: string;
@@ -2112,7 +2002,7 @@ type PaymentResult = PaymentInfo & {
2112
2002
  };
2113
2003
  };
2114
2004
  /**
2115
- * Whether a dev-mode server skips payment verification outright (internal-review).
2005
+ * Whether a dev-mode server skips payment verification outright.
2116
2006
  *
2117
2007
  * Both upfront and mid-job acceptance require verification whenever any Cashu,
2118
2008
  * x402, or Tempo rail is configured. An unusable configured rail fails closed;
@@ -2134,7 +2024,7 @@ declare function devModeSkipsPaymentVerification(opts: {
2134
2024
  */
2135
2025
  declare const PAYMENT_PROOF_KEYS: readonly ["cashu_token", "x402_payment", "tempo_credential"];
2136
2026
  /**
2137
- * Whether a `payment` message carries a proof on any mid-job rail (internal-review).
2027
+ * Whether a `payment` message carries a proof on any mid-job rail.
2138
2028
  *
2139
2029
  * Deliberately colocated with the rail dispatch it mirrors, because two call
2140
2030
  * sites decide on it: `validateMessageContent` (`server/app.ts`) admits a
@@ -2146,26 +2036,26 @@ declare const PAYMENT_PROOF_KEYS: readonly ["cashu_token", "x402_payment", "temp
2146
2036
  declare function hasPaymentProof(content: Record<string, unknown>): boolean;
2147
2037
  /**
2148
2038
  * Issue one mppx Challenge per registered method for the upfront HTTP-transport
2149
- * 402 path (internal-review). Mirrors the message-based issuance loop in
2039
+ * 402 path. Mirrors the message-based issuance loop in
2150
2040
  * `context.ts` but binds challenges via `meta` (resource path + per-request
2151
- * nonce) instead of the per-job `pendingMppChallengeIds` binding (internal-review) —
2041
+ * nonce) instead of the per-job `pendingMppChallengeIds` binding —
2152
2042
  * there's no job at upfront challenge-issue time, so the binding has to live
2153
2043
  * inside the challenge itself.
2154
2044
  *
2155
2045
  * `meta.nonce` is unique-per-issue and HMAC-bound; consumed-id tracking on
2156
- * the verification side is wired via `ConsumedCredentialStore` (internal-review), so
2046
+ * the verification side is wired via `ConsumedCredentialStore`, so
2157
2047
  * a successfully-accepted credential can't be replayed within its `expires`
2158
2048
  * window even if it lands on the same paid endpoint.
2159
2049
  *
2160
- * `btcUsdRate` is resolved once per request by the caller (internal-review) rather
2050
+ * `btcUsdRate` is resolved once per request by the caller rather
2161
2051
  * than fetched here, so every rail this request advertises or verifies prices
2162
2052
  * off the same number and a rate-provider outage is handled in one place.
2163
2053
  *
2164
- * `sessionIssuable` is the platform close-observer gate (internal-review), threaded in
2054
+ * `sessionIssuable` is the platform close-observer gate, threaded in
2165
2055
  * by `DVMServer` and defaulting to issuable for a self-hosted DVM that watches
2166
2056
  * its own closes. It used to gate advertisement only, so a `/v1/credit` 402
2167
2057
  * kept issuing `tempo/session` challenges the DVM had just stopped advertising
2168
- * — and its own interface doc said "advertised **and** issued" (internal-review). The
2058
+ * and its own interface doc said "advertised **and** issued". The
2169
2059
  * caller resolves it as "the gate is open, **or** this credit is already bound
2170
2060
  * to a channel", so a top-up on an existing channel keeps its challenge while
2171
2061
  * the gate is closed; `verifyUpfrontPayment` still refuses any *other* channel
@@ -2179,7 +2069,6 @@ declare function issueUpfrontChallenges(mpp: MppxServer, requiredMsats: number,
2179
2069
  declare function verifyUpfrontPayment(opts: UpfrontPaymentOpts): Promise<PaymentResult>;
2180
2070
  /**
2181
2071
  * A management credential signed for a channel other than the one required
2182
- * (internal-review).
2183
2072
  *
2184
2073
  * Typed rather than a bare `Error` because the drain route has to tell it apart
2185
2074
  * from the transport and chain failures its catch ladder reconciles: this one is
@@ -2206,7 +2095,7 @@ declare function verifyTempoSessionManagementCredential(args: {
2206
2095
  *
2207
2096
  * The drain route re-asserts its close intent here rather than a line above
2208
2097
  * the call so that a credential signed for another channel is refused before
2209
- * the reservation is touched (internal-review). Only this function knows where that
2098
+ * the reservation is touched. Only this function knows where that
2210
2099
  * seam is, so putting the hook here makes the ordering structural instead of a
2211
2100
  * comment the next edit can reorder past. A throw propagates to the caller
2212
2101
  * with nothing broadcast.
@@ -2218,7 +2107,7 @@ declare function verifyTempoSessionManagementCredential(args: {
2218
2107
  cumulativeAmount?: string;
2219
2108
  }>;
2220
2109
  /**
2221
- * Every machine code a flat payment-error body can carry (internal-review) — the six
2110
+ * Every machine code a flat payment-error body can carry — the six
2222
2111
  * codes constructed directly in this file plus the agent-wallet cashu rejection
2223
2112
  * codes ({@link AccumulatorRejectionCode}), which surface verbatim through the
2224
2113
  * accumulator branch of {@link verifyAccumulatorReceipt}. `fx_rate_unavailable`
@@ -2229,7 +2118,7 @@ declare function verifyTempoSessionManagementCredential(args: {
2229
2118
  type PaymentErrorCode = "payment_invalid" | "x402_not_offered" | "x402_settlement_ambiguous" | "cashu_unavailable" | "cashu_not_p2pk_locked" | "mint_health_pending" | "cashu_mint_sick" | "payment_insufficient" | "payment_unapplied" | "insufficient_credit" | "credit_expired" | "credit_unbacked" | "credit_not_found" | "tempo_channel_closing" | "settlement_pending" | "draw_conflict" | "funding_commitment_mismatch" | "credit_not_supported" | "one_shot_credit_not_supported" | "credit_below_min" | "below_rail_minimum" | "credit_over_max" | "credit_id_unavailable" | "nothing_to_drain" | "drain_below_dust" | "drain_not_found" | "drain_conflict" | "drain_method_unsupported" | "tempo_channel_exit_required" | "x402_settlement_submission_failed" | X402SettlementReconciliationReason | "lightning_settlement_pending" | "lightning_invoice_expired" | "lightning_unavailable" | AccumulatorRejectionCode;
2230
2119
  /**
2231
2120
  * Build a flat payment-error body carrying the four agent-facing fields every
2232
- * payment error must have (internal-review): the machine `code`, the operator-facing
2121
+ * payment error must have: the machine `code`, the operator-facing
2233
2122
  * `message`, and the `display`/`hint`/`retryable` copy an agent relays to a
2234
2123
  * human and branches retries on. `display`, `hint`, and `retryable` default from
2235
2124
  * {@link PAYMENT_ERROR_COPY} keyed on `code`; `message` is the per-site operator
@@ -2241,7 +2130,7 @@ type PaymentErrorCode = "payment_invalid" | "x402_not_offered" | "x402_settlemen
2241
2130
  *
2242
2131
  * `retryable` overrides on the same terms, and for the same reason: a code that
2243
2132
  * covers more than one refusal can be terminal for one of them and clear on its
2244
- * own for another — `drain_conflict` is both (internal-review). Override it only
2133
+ * own for another — `drain_conflict` is both. Override it only
2245
2134
  * alongside the `hint`, since the two are one answer: a hint that says retry
2246
2135
  * under `retryable: false` is the disagreement this exists to prevent.
2247
2136
  *
@@ -2258,14 +2147,14 @@ declare function paymentErrorBody(code: PaymentErrorCode, opts: {
2258
2147
  /**
2259
2148
  * Build a payment-error response carrying a JSON error body plus one
2260
2149
  * `WWW-Authenticate: Payment <serialized challenge>` header per mppx challenge
2261
- * (internal-review, per draft-ryan-httpauth-payment-01). When `challenges` is empty,
2150
+ * (per draft-ryan-httpauth-payment-01). When `challenges` is empty,
2262
2151
  * returns a plain JSON response (Cashu/x402-only DVMs).
2263
2152
  *
2264
2153
  * Status defaults to 402 (Payment Required) but callers can override — e.g.
2265
- * the internal-review sick-mint short-circuit returns 503 because the issue is a
2154
+ * the sick-mint short-circuit returns 503 because the failure is a
2266
2155
  * mint-side outage, not a payment problem.
2267
2156
  *
2268
- * When `x402Requirements` is present (internal-review, x402 dual-serve), merge the
2157
+ * When `x402Requirements` is present (x402 dual-serve), merge the
2269
2158
  * x402-spec envelope `{ x402Version, accepts: [...] }` into the body next to
2270
2159
  * the existing dvmkit error fields so x402 clients can find their retry
2271
2160
  * shape on the same response. The MPP `WWW-Authenticate` header and the
@@ -2275,7 +2164,6 @@ declare function paymentErrorBody(code: PaymentErrorCode, opts: {
2275
2164
  * are single-use and shared caches must not return them to other clients.
2276
2165
  */
2277
2166
  declare function buildPaymentErrorResponse(body: Record<string, unknown>, challenges?: Challenge.Challenge[], x402Requirements?: PaymentRequirements[], status?: number, x402V2Requirements?: PaymentRequirementsV2[], x402V2Resource?: string, x402ExactVersions?: X402ExactVersionSupport, x402ErrorCode?: string): Response;
2278
- /** Options for processing an incoming mid-job payment message. */
2279
2167
  interface IncomingPaymentOpts {
2280
2168
  mints?: string[];
2281
2169
  x402Config?: X402Config;
@@ -2288,7 +2176,7 @@ interface IncomingPaymentOpts {
2288
2176
  mpp?: MppxServer;
2289
2177
  /** Resource URL bound into the rebuilt x402 `PaymentRequirements`. */
2290
2178
  resourcePath?: string;
2291
- /** Cashu receive mode (internal-review). Mirrors {@link UpfrontPaymentOpts.cashuMode}. */
2179
+ /** Cashu receive mode. Mirrors {@link UpfrontPaymentOpts.cashuMode}. */
2292
2180
  cashuMode?: CashuMode;
2293
2181
  /** Per-DVM Postgres pool — required for the `p2pk-accumulator` path. */
2294
2182
  accumulatorDb?: AccumulatorPool;
@@ -2297,28 +2185,28 @@ interface IncomingPaymentOpts {
2297
2185
  dvmId?: string;
2298
2186
  /** Active NUT-11 P2PK lock pubkeys (current + retired-in-grace). */
2299
2187
  lockPubkeys?: LockPubkey[];
2300
- /** Runtime mint-health tracker (internal-review). */
2188
+ /** Runtime mint-health tracker. */
2301
2189
  mintHealthTracker?: MintHealthTracker;
2302
2190
  /**
2303
- * Host fx fetcher for the non-sat rails (internal-review). See
2191
+ * Host fx fetcher for the non-sat rails. See
2304
2192
  * {@link UpfrontPaymentOpts.fxFetcher}.
2305
2193
  */
2306
2194
  fxFetcher?: FxFetcher;
2307
2195
  /**
2308
- * Credit ledger the mid-job top-up funds and grows (internal-review, spec §1:
2196
+ * Credit ledger the mid-job top-up funds and grows (the credit lifecycle contract:
2309
2197
  * "mid-job `requestPayment` becomes a top-up"). Absent ⇒ the payment is
2310
2198
  * accepted with pre-credits semantics, exactly as before.
2311
2199
  */
2312
2200
  creditLedger?: CreditLedgerLike;
2313
2201
  /**
2314
- * Durable processed-payment markers (internal-review). x402/mpp money moves outside
2202
+ * Durable processed-payment markers. x402/mpp money moves outside
2315
2203
  * dvmkit, so the marker + `fund` + `growDraw` in one transaction is what
2316
2204
  * makes the mid-job ledger leg atomic and crash-replay safe — the cashu path
2317
2205
  * gets the same property from the accumulator's own commit transaction.
2318
2206
  */
2319
2207
  processedPayments?: ProcessedPaymentStore;
2320
2208
  /**
2321
- * Reporter-owned transactional outbox enqueue (internal-review). Runs inside the
2209
+ * Reporter-owned transactional outbox enqueue. Runs inside the
2322
2210
  * mid-job rail transaction after the ledger top-up/growth and before commit.
2323
2211
  */
2324
2212
  enqueueCreditDeposit?: CreditDepositEnqueue;
@@ -2328,7 +2216,7 @@ interface IncomingPaymentOpts {
2328
2216
  creditTtlMs?: number;
2329
2217
  }
2330
2218
  /**
2331
- * Pure verification of an incoming mid-job payment (internal-review). Runs the
2219
+ * Pure verification of an incoming mid-job payment. Runs the
2332
2220
  * rail-specific verify path and returns the credit shape; does not mutate
2333
2221
  * the job. The caller (`JobManager.processPayment`) applies the result
2334
2222
  * inside Tx C so verify+credit land atomically.
@@ -2341,7 +2229,7 @@ interface VerifyIncomingSnapshot {
2341
2229
  pendingPaymentMsats?: number;
2342
2230
  pendingMppChallengeIds?: string[];
2343
2231
  /**
2344
- * Per-job x402 binding (internal-review). When set, the incoming `x402_payment`'s
2232
+ * Per-job x402 binding. When set, the incoming `x402_payment`'s
2345
2233
  * decoded `authorization.nonce` must match this value or the credential is
2346
2234
  * rejected — closes the pre-settlement cross-job replay window. Pre-fix
2347
2235
  * DVMs leave this `undefined`; the verify-side check no-ops for them.
@@ -2350,9 +2238,9 @@ interface VerifyIncomingSnapshot {
2350
2238
  /** Exact advertised USDC microunits paired with `pendingX402Nonce`. */
2351
2239
  pendingX402AmountUsdcMicro?: string;
2352
2240
  paymentRail?: FundingMethod;
2353
- /** The credit the upfront leg funded and drew, when it had one (internal-review). */
2241
+ /** The credit the upfront leg funded and drew, when it had one. */
2354
2242
  creditId?: string;
2355
- /** The draw this job holds on {@link creditId}; the top-up grows it (internal-review). */
2243
+ /** The draw this job holds on {@link creditId}; the top-up grows it. */
2356
2244
  drawId?: string;
2357
2245
  /**
2358
2246
  * The job's current settlement reference. Used to tell an explicit
@@ -2361,17 +2249,17 @@ interface VerifyIncomingSnapshot {
2361
2249
  * upfront leg established.
2362
2250
  */
2363
2251
  paymentTxHash?: string;
2364
- /** Fiat envelope pinned when the ask was emitted (internal-review). See `JobRecord`. */
2252
+ /** Fiat envelope pinned when the ask was emitted. See `JobRecord`. */
2365
2253
  pendingPaymentFiatMicro?: number;
2366
2254
  pendingPaymentFiatCurrency?: string;
2367
2255
  /**
2368
2256
  * Everything this job has asked for mid-job, summed and never decremented
2369
- * (internal-review) — the ceiling on its draw growth. See `JobRecord`, including
2257
+ * the ceiling on its draw growth. See `JobRecord`, including
2370
2258
  * why it can't be derived from the outstanding figure above.
2371
2259
  */
2372
2260
  askedTopUpMicro?: number;
2373
2261
  askedTopUpCurrency?: string;
2374
- /** Why the total above can't express a ceiling, when it can't (internal-review). */
2262
+ /** Why the total above can't express a ceiling, when it can't. */
2375
2263
  topUpCapUnenforcedReason?: TopUpCapUnenforcedReason;
2376
2264
  /**
2377
2265
  * Caller identity for a top-up that has to mint a *fresh* implicit credit
@@ -2382,7 +2270,6 @@ interface VerifyIncomingSnapshot {
2382
2270
  requesterPubkey?: string;
2383
2271
  requesterId?: string;
2384
2272
  }
2385
- /** Result of `verifyIncomingPayment`. */
2386
2273
  interface VerifiedIncomingPayment {
2387
2274
  paidMsats: number;
2388
2275
  paymentMint?: string;
@@ -2391,21 +2278,21 @@ interface VerifiedIncomingPayment {
2391
2278
  nativeAmount?: number;
2392
2279
  nativeAsset?: "sats" | "usdc" | "usdc.e" | "usd-cents";
2393
2280
  cashuFlow?: "p2pk_accumulator";
2394
- /** True when this credit should accumulate onto an existing same-rail native amount (internal-review). */
2281
+ /** True when this credit should accumulate onto an existing same-rail native amount. */
2395
2282
  sameRail: boolean;
2396
2283
  /**
2397
- * Credit this top-up opened (internal-review). Only set when the job had none — a
2284
+ * Credit this top-up opened. Only set when the job had none — a
2398
2285
  * free-then-paid job — so Tx C can bind it; a job that already holds a credit
2399
2286
  * keeps its binding, because the top-up grew that draw.
2400
2287
  */
2401
2288
  creditId?: string;
2402
2289
  /** The draw opened alongside {@link creditId}. */
2403
2290
  drawId?: string;
2404
- /** The funding leg, reported to the platform as a deposit (internal-review). */
2291
+ /** The funding leg, reported to the platform as a deposit. */
2405
2292
  funding?: CreditFundingReport;
2406
2293
  /**
2407
2294
  * Fiat micro this payment funded that the job's draw did not take
2408
- * (internal-review). See `PaymentInfo.unappliedMicro`. When it equals the whole
2295
+ * See `PaymentInfo.unappliedMicro`. When it equals the whole
2409
2296
  * funding, the payment moved no job counters at all and Tx C is handed a
2410
2297
  * `null` delta.
2411
2298
  */
@@ -2413,7 +2300,7 @@ interface VerifiedIncomingPayment {
2413
2300
  }
2414
2301
  /**
2415
2302
  * Verify an incoming payment without mutating the job. Returns the credit
2416
- * shape on success or an error envelope on failure. internal-review.
2303
+ * shape on success or an error envelope on failure.
2417
2304
  *
2418
2305
  * The rails dispatched on below are the list {@link PAYMENT_PROOF_KEYS}
2419
2306
  * carries — add one here and it must be added there in the same commit.
@@ -2428,27 +2315,27 @@ declare function verifyIncomingPayment(body: {
2428
2315
  status: number;
2429
2316
  /**
2430
2317
  * A short mid-job pay that funded a credit before this request failed
2431
- * (internal-review) — still a deposit, still reported. See `PaymentErrorDetail`.
2318
+ * still a deposit, still reported. See `PaymentErrorDetail`.
2432
2319
  */
2433
2320
  funding?: CreditFundingReport;
2434
2321
  };
2435
2322
  }>;
2436
2323
  /**
2437
2324
  * Apply a verified payment result to the in-memory job. Used by callers that
2438
- * don't run Tx C (e.g., the legacy isolate-job-manager path). internal-review.
2325
+ * don't run Tx C (e.g., the legacy isolate-job-manager path).
2439
2326
  */
2440
2327
  declare function applyPaymentInfoToJob(job: ServerJob, info: VerifiedIncomingPayment): void;
2441
2328
  /**
2442
2329
  * Process an incoming payment message. Returns an error body on failure.
2443
2330
  *
2444
- * **The isolate-runtime path, and deliberately ledger-less** (spec §3). Its
2331
+ * **The isolate-runtime path, and deliberately ledger-less** (the isolate-runtime rule). Its
2445
2332
  * only caller is `platform/isolate-job-manager.ts`; isolate DVMs have no
2446
2333
  * Postgres of their own, so they run implicit N=1 with today's semantics
2447
2334
  * preserved and never advertise credit. The credits-carrying mid-job path is
2448
2335
  * {@link verifyIncomingPayment} + `JobManager.processPayment` (Tx C), where
2449
- * internal-review wired `fund` + `growDraw`. Wiring a ledger here would need a
2336
+ * wired `fund` + `growDraw`. Wiring a ledger here would need a
2450
2337
  * platform-side ledger leg with its own funding-atomicity and receipt-key
2451
- * story — the trust-surface expansion internal-review exists to decide.
2338
+ * story — the trust-surface expansion exists to decide.
2452
2339
  */
2453
2340
  declare function processIncomingPayment(job: ServerJob, body: {
2454
2341
  type: MessageType;
@@ -2463,22 +2350,22 @@ interface CommittedFunding {
2463
2350
  /** Snapshot fixed immediately after this request's funding leg, before any draw. */
2464
2351
  fundingCredit?: CreditSnapshot;
2465
2352
  /**
2466
- * Absent for a `/v1/credit` fund-only top-up (internal-review) — money landed on the
2353
+ * Absent for a `/v1/credit` fund-only top-up — money landed on the
2467
2354
  * credit with no job to pay for — for a short mid-job pay, which funds
2468
- * without drawing or growing (internal-review), and for an explicit short deposit
2469
- * whose combined balance cannot cover the draw (internal-review). On a mid-job
2355
+ * without drawing or growing, and for an explicit short deposit
2356
+ * whose combined balance cannot cover the draw. On a mid-job
2470
2357
  * top-up this is the **grown** draw, so `amountMicro` is the job's running
2471
2358
  * total, not this leg's contribution.
2472
2359
  */
2473
2360
  draw?: DrawResult;
2474
2361
  /**
2475
2362
  * An explicit short deposit committed, but the combined available balance
2476
- * could not cover the full-price draw (internal-review). Preserved instead of
2363
+ * could not cover the full-price draw. Preserved instead of
2477
2364
  * thrown so the rail receive and deposit commit atomically with no draw.
2478
2365
  */
2479
2366
  drawRefusal?: CreditLedgerError;
2480
2367
  /**
2481
- * What this leg added to an already-placed draw (internal-review). Set only on a
2368
+ * What this leg added to an already-placed draw. Set only on a
2482
2369
  * mid-job top-up; the upfront legs contribute the whole draw, so they leave
2483
2370
  * it unset and `draw.railValue` is the same thing.
2484
2371
  */
@@ -2488,7 +2375,7 @@ interface CommittedFunding {
2488
2375
  drawNative: number | null;
2489
2376
  };
2490
2377
  /**
2491
- * Fiat micro that landed on the credit but grew no draw (internal-review) — a
2378
+ * Fiat micro that landed on the credit but grew no draw — a
2492
2379
  * duplicate payment for an ask already satisfied, the clipped tail of an
2493
2380
  * oversized one, or a payment that arrived after the ask was met. It stays
2494
2381
  * the caller's available balance; `UnappliedCredit` on the 201 is how they
@@ -2503,9 +2390,9 @@ interface CommittedFunding {
2503
2390
  *
2504
2391
  * Exported because the builder-supplied `onCreditFunded` override is a second
2505
2392
  * door onto the same report, and both must say the same thing: hand-rolling the
2506
- * mapping there once dropped the internal-review `tempoChannel` block, so a DVM
2393
+ * mapping there once dropped the `tempoChannel` block, so a DVM
2507
2394
  * reporting through the override registered no channel with the close observer
2508
- * (internal-review). One builder, no drift.
2395
+ * One builder, no drift.
2509
2396
  */
2510
2397
  declare function creditDepositPayload(dvmId: string, funding: CreditFundingReport): CreditDepositPayload;
2511
2398
  /** Finish the local ledger effect retained by a durable exact-settlement intent. */
@@ -2518,7 +2405,6 @@ declare function repairX402ExactSettlementEffect(args: {
2518
2405
  tx?: CreditLedgerQuerier;
2519
2406
  }): Promise<CommittedFunding | undefined>;
2520
2407
 
2521
- /** Everything the issuer needs to sign for one DVM. */
2522
2408
  interface ReceiptIssuerOpts {
2523
2409
  /** 32-byte hex receipt secret — `DVMKIT_RECEIPT_KEY`, or an ephemeral dev key. */
2524
2410
  secret: string;
@@ -2528,7 +2414,7 @@ interface ReceiptIssuerOpts {
2528
2414
  dvmId: string;
2529
2415
  }
2530
2416
  /**
2531
- * Signs job receipts for one DVM (internal-review).
2417
+ * Signs job receipts for one DVM.
2532
2418
  *
2533
2419
  * Constructed only when a receipt key is wired, so the presence of an issuer
2534
2420
  * *is* the "this DVM emits receipts" signal that `/v1/info` advertises. Pure:
@@ -2546,19 +2432,23 @@ declare class ReceiptIssuer {
2546
2432
  constructor(opts: ReceiptIssuerOpts);
2547
2433
  /**
2548
2434
  * Build and sign the receipt for a terminal job. `seq` comes from
2549
- * `JobStore.claimReceiptSeq`, `issuedAt` defaults to now (tests pin it).
2435
+ * `JobStore.claimReceiptSeq`; `issuedAt` is epoch seconds and defaults to now.
2550
2436
  *
2551
2437
  * Free jobs get receipts too, with `paid.msats: 0` — they still consume a
2552
2438
  * sequence number and still attest an outcome. Whether feedback is
2553
2439
  * paid-only is the feedback layer's call, not this one's.
2554
2440
  *
2555
- * `credit` is the resolved draw block (internal-review) — present on every job
2441
+ * Timing and attribution come from the committed terminal row, not signing
2442
+ * time or handler input. Legacy rows without those durable inputs omit the
2443
+ * optional blocks rather than inventing historical evidence.
2444
+ *
2445
+ * `credit` is the resolved draw block — present on every job
2556
2446
  * whose payment funded/drew the ledger, absent otherwise. Signature-
2557
2447
  * compatible either way: `canonicalize` omits absent keys.
2558
2448
  */
2559
2449
  issue(record: JobRecord, seq: number, issuedAt?: number, credit?: ReceiptCredit): JobReceipt;
2560
2450
  /**
2561
- * Countersign one reclaim event (internal-review). Unlike job receipts there is
2451
+ * Countersign one reclaim event. Unlike job receipts there is
2562
2452
  * no store-allocated sequence — the drain's own `ledger_seq` (taken under
2563
2453
  * the credit row lock, shared with draws) already orders it in the
2564
2454
  * per-credit evidence chain.
@@ -2650,13 +2540,9 @@ declare class X402FacilitatorHealth implements X402FacilitatorHealthLike {
2650
2540
  private refreshOnce;
2651
2541
  }
2652
2542
 
2653
- /** Options for creating a JobManager. */
2654
2543
  interface JobManagerOpts {
2655
- /** Environment variables for ctx.env. */
2656
2544
  env: Record<string, string>;
2657
- /** KV store for ctx.store. */
2658
2545
  store: KVStore;
2659
- /** Cashu mints accepted for payment. */
2660
2546
  mints?: string[];
2661
2547
  /** Persistent backing store for job records. Default: in-memory. */
2662
2548
  jobStore?: JobStore;
@@ -2664,7 +2550,6 @@ interface JobManagerOpts {
2664
2550
  devMode?: boolean;
2665
2551
  /** Payment methods this DVM accepts. Default: derived by the server from configured rails. */
2666
2552
  paymentMethods?: PaymentMethod[];
2667
- /** x402 stablecoin payment configuration. */
2668
2553
  x402?: X402Config;
2669
2554
  /** Durable exact-settlement coordinator shared with upfront verification. */
2670
2555
  x402ExactSettlement?: X402ExactSettlementServer;
@@ -2672,16 +2557,16 @@ interface JobManagerOpts {
2672
2557
  x402FacilitatorHealth?: X402FacilitatorHealthLike;
2673
2558
  /** MPP multi-rail payment handle (built via `createMppFromOpts`). */
2674
2559
  mpp?: MppxServer;
2675
- /** Cashu receive mode (internal-review). */
2560
+ /** Cashu receive mode. */
2676
2561
  cashuMode?: CashuMode;
2677
- /** Builder's NUT-11 P2PK lock pubkey (internal-review). Required for accumulator mode. */
2562
+ /** Builder's NUT-11 P2PK lock pubkey. Required for accumulator mode. */
2678
2563
  lockPubkey?: string;
2679
2564
  /** Test-only atomic Cashu backend, supplied by the development host. */
2680
2565
  disposableCashu?: DisposableCashuCommit;
2681
2566
  /** Postgres pool for wallet accumulator persistence. */
2682
2567
  db?: Pool;
2683
2568
  /**
2684
- * Agent-wallet (internal-review): per-DVM identifier used for the scheduler advisory
2569
+ * Agent-wallet: per-DVM identifier used for the scheduler advisory
2685
2570
  * lock and the `(dvm_id, request_id)` replay key. Defaults to `DVMKIT_DVM_ID`
2686
2571
  * env at boot in `createDVMHost()`.
2687
2572
  */
@@ -2690,18 +2575,18 @@ interface JobManagerOpts {
2690
2575
  authAudience?: SignedRequestAudience;
2691
2576
  /**
2692
2577
  * Shared fx fetcher used to convert USD-string descriptor prices and
2693
- * fiat-form `requestPayment` calls into sats (internal-review). The SDK server owns
2578
+ * fiat-form `requestPayment` calls into sats. The SDK server owns
2694
2579
  * one per process so concurrent quotes share the 60s cache window.
2695
2580
  */
2696
2581
  fxFetcher: FxFetcher;
2697
2582
  /**
2698
- * Signs a receipt at every terminal transition (internal-review). Absent when the
2583
+ * Signs a receipt at every terminal transition. Absent when the
2699
2584
  * DVM has no receipt key wired — jobs then terminate exactly as before and
2700
2585
  * `/v1/info` doesn't advertise `receipts`.
2701
2586
  */
2702
2587
  receiptIssuer?: ReceiptIssuer;
2703
2588
  /**
2704
- * Credit ledger for the terminal funnel (internal-review): a job carrying a
2589
+ * Credit ledger for the terminal funnel: a job carrying a
2705
2590
  * `creditId`/`drawId` settles its draw on success and releases it on
2706
2591
  * failure/cancel — this is how "no debit on job failure" is mechanically
2707
2592
  * real. The resolution runs before receipt issuance so the receipt's
@@ -2709,31 +2594,31 @@ interface JobManagerOpts {
2709
2594
  */
2710
2595
  creditLedger?: CreditLedgerLike;
2711
2596
  /**
2712
- * Durable processed-payment markers (internal-review), threaded through to the
2713
- * mid-job top-up path (internal-review) so an x402/mpp payment's marker, `fund`, and
2597
+ * Durable processed-payment markers, threaded through to the
2598
+ * mid-job top-up path so an x402/mpp payment's marker, `fund`, and
2714
2599
  * `growDraw` commit together.
2715
2600
  */
2716
2601
  processedPayments?: ProcessedPaymentStore;
2717
2602
  /**
2718
2603
  * Reporter-owned transactional deposit enqueue threaded into mid-job rail
2719
- * commits (internal-review).
2604
+ * commits.
2720
2605
  */
2721
2606
  enqueueCreditDeposit?: CreditDepositEnqueue;
2722
- /** Reporter outbox inserted atomically with a terminal draw release (internal-review). */
2607
+ /** Reporter outbox inserted atomically with a terminal draw release. */
2723
2608
  enqueueCreditDrawRelease?: CreditDrawReleaseEnqueue;
2724
2609
  /** Credit lifetime a top-up mints with, from the DVM's advertised `credit.ttl`. */
2725
2610
  creditTtlMs?: number;
2726
2611
  /**
2727
- * The DVM's declared pricing currency (internal-review), which is the currency of
2612
+ * The DVM's declared pricing currency, which is the currency of
2728
2613
  * every credit it opens. Threaded into the job context so a mid-job ask on a
2729
2614
  * job that holds no credit yet is still pinned in the denomination its first
2730
- * payment will open the credit in (internal-review). `DVMServer` passes its resolved
2615
+ * payment will open the credit in. `DVMServer` passes its resolved
2731
2616
  * `pricingCurrency`; a host building a `JobManager` directly falls back to the
2732
2617
  * descriptor, and then to `"usd"`.
2733
2618
  */
2734
2619
  pricingCurrency?: string;
2735
2620
  /**
2736
- * Callback fired when a mid-job top-up moves money onto a credit (internal-review).
2621
+ * Callback fired when a mid-job top-up moves money onto a credit.
2737
2622
  * The platform books it as a **deposit** — a liability until drawn, never
2738
2623
  * summed into revenue — so a top-up that skipped this would leave the
2739
2624
  * outstanding-liability view short. Mirrors `DVMServer.reportCreditDeposit`,
@@ -2741,7 +2626,7 @@ interface JobManagerOpts {
2741
2626
  */
2742
2627
  onCreditFunded?: (info: CreditDepositPayload) => void | Promise<void>;
2743
2628
  /**
2744
- * Callback fired when a paid job completes (internal-review). Container-runtime DVMs
2629
+ * Callback fired when a paid job completes. Container-runtime DVMs
2745
2630
  * use this to report revenue to the platform via `RevenueReporter`. Mirrors
2746
2631
  * the isolate path's `IsolateJobManager.opts.onJobCompleted`.
2747
2632
  */
@@ -2773,16 +2658,18 @@ interface JobManagerOpts {
2773
2658
  }) => void | Promise<void>;
2774
2659
  /**
2775
2660
  * Callback fired when a terminal job declared a builder cost but emitted no
2776
- * revenue report (internal-review). Container-runtime DVMs use the reporter's
2661
+ * revenue report. Container-runtime DVMs use the reporter's
2777
2662
  * durable `job-cost` outbox path. The receiver de-duplicates by DVM + job,
2778
2663
  * independently of the rail-keyed revenue ledger.
2779
2664
  */
2780
2665
  onJobCost?: (info: JobCostReportPayload) => void | Promise<void>;
2666
+ /** SDK-owned hosted terminal outbox callback. */
2667
+ onJobTerminal?: (info: JobTerminalReportPayload) => Promise<void>;
2781
2668
  /**
2782
2669
  * Callback fired when the stale-job reaper force-fails a *paid* job — its
2783
2670
  * pending credit draw is released rather than settled, because only a
2784
- * completed job settles a draw (internal-review). Container-runtime DVMs wire this
2785
- * to a paid-job-death report → operator `notice` (internal-review). Never fires for
2671
+ * completed job settles a draw. Container-runtime DVMs wire this
2672
+ * to a paid-job-death report → operator `notice`. Never fires for
2786
2673
  * free jobs (`paidMsats === 0`). Fired fire-and-forget so a throw or a slow
2787
2674
  * report can't wedge the sweep.
2788
2675
  */
@@ -2799,20 +2686,20 @@ interface JobManagerOpts {
2799
2686
  }) => void | Promise<void>;
2800
2687
  /**
2801
2688
  * Callback fired when a settled credit draw cannot book a revenue event
2802
- * because no usable payment rail is available (internal-review). Container-runtime
2689
+ * because no usable payment rail is available. Container-runtime
2803
2690
  * DVMs auto-wire this to the platform's deduped operator notice. Fired
2804
2691
  * fire-and-forget so alert delivery cannot block terminal handling or draw
2805
2692
  * reconciliation.
2806
2693
  */
2807
2694
  onRevenueSkippedNoRail?: (info: RevenueSkippedNoRailPayload) => void | Promise<void>;
2808
2695
  /**
2809
- * Stale-job sweep threshold in ms (internal-review). Jobs in a non-terminal status
2696
+ * Stale-job sweep threshold in ms. Jobs in a non-terminal status
2810
2697
  * (`processing` / `working` / `awaiting-input`) whose `lastActivityAt` is
2811
2698
  * older than this are force-cancelled with reason `stale_no_terminal_status`,
2812
2699
  * so callers always reach a terminal status instead of polling forever after
2813
2700
  * a worker crash, OOM, or silent `messageAppender` failure. Default:
2814
- * `2 × descriptor.idleTimeout + STALE_JOB_WATCHDOG_HEADROOM_MS`, matching
2815
- * the internal-review acceptance criterion against scrape's `JOB_TIMEOUT_MS`.
2701
+ * `2 × descriptor.idleTimeout + STALE_JOB_WATCHDOG_HEADROOM_MS`, which keeps
2702
+ * the default beyond scrape's `JOB_TIMEOUT_MS`.
2816
2703
  * Builders whose per-handler wall-clock bound exceeds 90s must override
2817
2704
  * this — otherwise the watchdog fires on a legitimate in-flight handler.
2818
2705
  * Set to `0` to disable (test seam).
@@ -2824,7 +2711,7 @@ interface JobManagerOpts {
2824
2711
  */
2825
2712
  staleJobSweepIntervalMs?: number;
2826
2713
  /**
2827
- * Worker-liveness watchdog in ms (internal-review). Jobs in `processing`/`working`
2714
+ * Worker-liveness watchdog in ms. Jobs in `processing`/`working`
2828
2715
  * whose `lastActivityAt` is older than this are marked `failed` (dead
2829
2716
  * worker), separately from the longer `awaiting-input` idle timeout above.
2830
2717
  * Default: `descriptor.processingWatchdog * 1000` or
@@ -2834,15 +2721,15 @@ interface JobManagerOpts {
2834
2721
  /**
2835
2722
  * Interval at which locally-active `processing`/`working` jobs have their
2836
2723
  * `lastActivityAt` bumped so the processing watchdog only fires on a truly
2837
- * dead worker (internal-review). Default: `DEFAULT_HEARTBEAT_INTERVAL_MS`. Set to
2838
- * `0` to disable (test seam). Also floors how far the internal-review clock guard
2724
+ * dead worker. Default: `DEFAULT_HEARTBEAT_INTERVAL_MS`. Set to
2725
+ * `0` to disable (test seam). Also floors how far the clock guard
2839
2726
  * may compensate a backwards step on the processing arm — a cadence close to
2840
2727
  * `processingWatchdogMs` leaves it no room and it compensates nothing.
2841
2728
  */
2842
2729
  heartbeatIntervalMs?: number;
2843
2730
  /**
2844
2731
  * Age in ms at which a `pending` credit draw whose `job_id` matches no row in
2845
- * the job store is released as orphaned (internal-review). The draw commits before
2732
+ * the job store is released as orphaned. The draw commits before
2846
2733
  * the job row is persisted, so a crash or a fail-closed refusal in that
2847
2734
  * window strands a hold no terminal path can ever reach. Must stay
2848
2735
  * comfortably above the submit path's draw→persist latency. Set to `0` to
@@ -2853,7 +2740,7 @@ interface JobManagerOpts {
2853
2740
  orphanDrawAgeMs?: number;
2854
2741
  /**
2855
2742
  * Age in ms at which a `pending` credit draw whose job row **is** terminal is
2856
- * reconciled against that row's outcome (internal-review) — settled for a
2743
+ * reconciled against that row's outcome — settled for a
2857
2744
  * `completed` job, released for a `failed`/`cancelled` one. Covers the hole
2858
2745
  * `orphanDrawAgeMs` cannot: `resolveCreditDraw` throwing on a ledger error
2859
2746
  * leaves a terminal job whose hold no later path retries.
@@ -2861,7 +2748,7 @@ interface JobManagerOpts {
2861
2748
  * Rides the same scan as the orphan arm, which has two consequences for the
2862
2749
  * value you set here. Setting `orphanDrawAgeMs` to `0` disables this arm too.
2863
2750
  * And the effective gate is `max(orphanDrawAgeMs, terminalDrawReconcileAgeMs)`
2864
- * — the scan never returns a row younger than its own cutoff, so anything
2751
+ * the scan never returns a row younger than its own cutoff, so anything
2865
2752
  * below `orphanDrawAgeMs` is silently clamped up to it. That floor is
2866
2753
  * deliberate rather than a wart: honouring a narrower value would mean
2867
2754
  * widening the scan, which hands the orphan arm rows younger than
@@ -2900,7 +2787,7 @@ interface JobManagerOpts {
2900
2787
  /**
2901
2788
  * Grace window in ms a reactivating machine waits for a live original handler
2902
2789
  * to win the single-execution claim before replaying an `awaiting-input` job
2903
- * itself (internal-review). Default: `DEFAULT_REACTIVATION_CLAIM_GRACE_MS`. Widen if
2790
+ * itself. Default: `DEFAULT_REACTIVATION_CLAIM_GRACE_MS`. Widen if
2904
2791
  * cross-machine NOTIFY latency causes spurious double executions; lower in
2905
2792
  * tests for speed.
2906
2793
  */
@@ -2908,7 +2795,7 @@ interface JobManagerOpts {
2908
2795
  }
2909
2796
  type ResolvedInput<I extends ZodLike | undefined> = I extends ZodLike<infer O> ? O : string;
2910
2797
  /**
2911
- * A deposit this payment funded that the job row did **not** take (internal-review).
2798
+ * A deposit this payment funded that the job row did **not** take.
2912
2799
  *
2913
2800
  * Reached when two mid-job top-ups race on a free-then-paid job: each opens its
2914
2801
  * own implicit credit, and `verifyAndCredit`'s set-if-null bind keeps one. The
@@ -2958,12 +2845,13 @@ declare class JobManager<State, InputSchema extends ZodLike | undefined> {
2958
2845
  private readonly cleanupTimers;
2959
2846
  /** Cost revisions held only by a terminal handler owner until its durable merge succeeds. */
2960
2847
  private readonly terminalCostHandoffRetryTimers;
2961
- /** Per-job NOTIFY unsubscribe handles for the durable-status watch (internal-review). */
2848
+ /** Per-job NOTIFY unsubscribe handles for the durable-status watch. */
2962
2849
  private readonly statusWatchers;
2963
- /** Job ids whose durable-status re-read is in flight — coalesces notify storms (internal-review). */
2850
+ /** Job ids whose durable-status re-read is in flight — coalesces notify storms. */
2964
2851
  private readonly statusChecksInFlight;
2965
- /** Job ids that were notified mid-re-read and must be re-checked (internal-review). */
2852
+ /** Job ids that were notified mid-re-read and must be re-checked. */
2966
2853
  private readonly statusChecksQueued;
2854
+ private readonly inputResumeTails;
2967
2855
  private readonly sessionId;
2968
2856
  private nextJobId;
2969
2857
  private accumulatorMonitor?;
@@ -2971,7 +2859,7 @@ declare class JobManager<State, InputSchema extends ZodLike | undefined> {
2971
2859
  private readonly processingWatchdogMs;
2972
2860
  private readonly reactivationClaimGraceMs;
2973
2861
  /**
2974
- * Worker-heartbeat cadence (internal-review). Also floors the internal-review clock
2862
+ * Worker-heartbeat cadence. Also floors the clock
2975
2863
  * guard's compensation on the processing arm — see
2976
2864
  * {@link staleSweepCompensationCapMs}.
2977
2865
  */
@@ -2991,7 +2879,7 @@ declare class JobManager<State, InputSchema extends ZodLike | undefined> {
2991
2879
  private jobRetentionResumeFrom?;
2992
2880
  /**
2993
2881
  * A `Date.now()` reading that cannot regress within this manager's lifetime
2994
- * (internal-review). Anchored at construction, so a manager already running when
2882
+ * Anchored at construction, so a manager already running when
2995
2883
  * the clock stepped is covered. The stale-job sweep's two cutoffs, the
2996
2884
  * orphan-draw age gate and the reactivation claim grace all read it; see
2997
2885
  * {@link createMonotonicClock} for what it costs and where it is clamped.
@@ -3004,18 +2892,16 @@ declare class JobManager<State, InputSchema extends ZodLike | undefined> {
3004
2892
  private jobRetentionSweepInFlight;
3005
2893
  private heartbeatInFlight;
3006
2894
  /**
3007
- * The denomination of every credit this DVM opens (internal-review). Resolved once,
2895
+ * The denomination of every credit this DVM opens. Resolved once,
3008
2896
  * with the same boundary fallback `DVMServer` applies for direct JavaScript
3009
2897
  * callers that force an incomplete value past the descriptor contract.
3010
2898
  */
3011
2899
  private readonly pricingCurrency;
3012
2900
  constructor(descriptor: DVMDescriptor<State, InputSchema>, opts: JobManagerOpts);
3013
- /** Active in-memory jobs. */
3014
2901
  get activeJobs(): Map<string, ServerJob>;
3015
- /** The backing job store. */
3016
2902
  get store(): JobStore;
3017
2903
  /**
3018
- * True when this DVM will actually issue receipts (internal-review) — a key *and*
2904
+ * True when this DVM will actually issue receipts — a key *and*
3019
2905
  * a store that can allocate sequence numbers and persist bytes write-once.
3020
2906
  * `/v1/info#receipts` reads this rather than the key alone, so the flag can
3021
2907
  * never promise something `issueReceipt` silently declines to do.
@@ -3026,7 +2912,7 @@ declare class JobManager<State, InputSchema extends ZodLike | undefined> {
3026
2912
  /** Names of every capability this descriptor exposes — used for error envelopes. */
3027
2913
  capabilityNames(): string[];
3028
2914
  /**
3029
- * Resolve a capability's static `price` to msats (internal-review).
2915
+ * Resolve a capability's static `price` to msats.
3030
2916
  *
3031
2917
  * `"$X.XX"` is parsed as USD and converted via the SDK's shared fx fetcher.
3032
2918
  * Returns `undefined` for dynamic-priced capabilities (those that declare
@@ -3035,7 +2921,7 @@ declare class JobManager<State, InputSchema extends ZodLike | undefined> {
3035
2921
  currentPriceMsats(capability: string): Promise<number | undefined>;
3036
2922
  /**
3037
2923
  * Translate a capability's static `price` into the fiat envelope used by
3038
- * the per-capability `pricing.max` advertised on `/v1/info` (internal-review).
2924
+ * the per-capability `pricing.max` advertised on `/v1/info`.
3039
2925
  * Returns `undefined` for dynamic-priced capabilities and for unknown
3040
2926
  * names (the route handler validates the name before invoking this).
3041
2927
  */
@@ -3044,24 +2930,24 @@ declare class JobManager<State, InputSchema extends ZodLike | undefined> {
3044
2930
  currency: string;
3045
2931
  } | undefined;
3046
2932
  /**
3047
- * Parse a request body through a capability's input schema (internal-review).
2933
+ * Parse a request body through a capability's input schema.
3048
2934
  *
3049
2935
  * Resolution order when a capability declares an `input` schema:
3050
2936
  * 1. `body.data` is preferred — agents pass structured fields directly
3051
- * (CLI builds this from `--param k=v`).
2937
+ * (CLI builds this from `--param k=v`).
3052
2938
  * 2. Fallback: `JSON.parse(body.input)` for clients still on the legacy
3053
- * JSON-string contract.
2939
+ * JSON-string contract.
3054
2940
  * 3. Neither usable → throw `MissingStructuredInputError` so the route can
3055
- * return `invalid_input` with a hint pointing at `/v1/info`.
2941
+ * return `invalid_input` with a hint pointing at `/v1/info`.
3056
2942
  *
3057
2943
  * When the capability has no `input` schema, returns `body.input` raw
3058
2944
  * (primitive path).
3059
2945
  *
3060
- * The internal-review credit envelope is removed before the schema runs, on both
3061
- * branches (internal-review) — it rides the signed body but is protocol-level, so a
2946
+ * The credit envelope is removed before the schema runs, on both
2947
+ * branches — it rides the signed body but is protocol-level, so a
3062
2948
  * top-level `.strict()` capability schema would otherwise reject every
3063
2949
  * explicit draw as an unknown key, before the envelope was even extracted.
3064
- * The persisted `record.input` the internal-review reactivation path re-reads is the
2950
+ * The persisted `record.input` the reactivation path re-reads is the
3065
2951
  * pre-Zod wire form, so it comes through the second branch carrying them too.
3066
2952
  */
3067
2953
  parseInput(body: {
@@ -3069,7 +2955,7 @@ declare class JobManager<State, InputSchema extends ZodLike | undefined> {
3069
2955
  data?: unknown;
3070
2956
  }, capability: string): unknown;
3071
2957
  /**
3072
- * Look up the per-capability descriptor by name (internal-review). Throws when the
2958
+ * Look up the per-capability descriptor by name. Throws when the
3073
2959
  * name doesn't exist — the route layer validates body.capability first, so
3074
2960
  * reaching this with an unknown name is a programmer error.
3075
2961
  */
@@ -3083,7 +2969,7 @@ declare class JobManager<State, InputSchema extends ZodLike | undefined> {
3083
2969
  */
3084
2970
  private getCapability;
3085
2971
  /**
3086
- * Allocate the id the next job will be created under (internal-review). The
2972
+ * Allocate the id the next job will be created under. The
3087
2973
  * submit path calls this BEFORE payment verification so the ledger draw
3088
2974
  * commits with its job linkage, then passes the id back through
3089
2975
  * `createJob`'s provenance. Ids allocated for requests whose payment is
@@ -3092,7 +2978,7 @@ declare class JobManager<State, InputSchema extends ZodLike | undefined> {
3092
2978
  */
3093
2979
  allocateJobId(): string;
3094
2980
  /**
3095
- * Create a new job from a request body. `provenance` (internal-review) is what the
2981
+ * Create a new job from a request body. `provenance` is what the
3096
2982
  * idempotent-replay path on `POST /v1/job` reads back: the raw `job_token`
3097
2983
  * to re-issue, and the fingerprint + caller pubkey a retry must reproduce
3098
2984
  * to be given it.
@@ -3107,32 +2993,32 @@ declare class JobManager<State, InputSchema extends ZodLike | undefined> {
3107
2993
  requestId?: string;
3108
2994
  authRequestPath?: string;
3109
2995
  /**
3110
- * Pre-allocated id from {@link allocateJobId} (internal-review) — the submit
2996
+ * Pre-allocated id from {@link allocateJobId} — the submit
3111
2997
  * path allocates before payment verification so the ledger draw can
3112
2998
  * record the job it pays for.
3113
2999
  */
3114
3000
  jobId?: string;
3115
3001
  }): ServerJob;
3116
- /** Build an SDKJobContext and attach it to the job. */
3117
3002
  buildAndAttachContext(job: ServerJob, parsedInput: unknown): SDKJobContext<State, ResolvedInput<InputSchema>>;
3118
- /** Start the handler for a job. */
3119
3003
  runHandler(job: ServerJob, sdkCtx: SDKJobContext<unknown, unknown>): void;
3120
- /** Dispatch a validated incoming message to the appropriate handler or pending resolver. */
3121
3004
  dispatchMessage(job: ServerJob, type: MessageType, content: unknown): Promise<void>;
3005
+ private queueInputResume;
3006
+ private claimLocalInput;
3007
+ private dispatchMessageNow;
3122
3008
  /**
3123
3009
  * Persist a job to the backing store.
3124
3010
  *
3125
- * Awaits the per-job appender tail (internal-review) so that:
3126
- * 1. The snapshot's `messages` is consistent with the `job_messages` table
3127
- * — no row is still in flight at snapshot time.
3128
- * 2. For terminal saves, the `DELETE FROM job_messages` inside `save()`
3129
- * can't race a still-pending `appendOutgoing` for the final yield
3130
- * message (which would otherwise wipe the row before an in-flight SSE
3131
- * subscriber's NOTIFY-driven fetch can see it).
3011
+ * Awaits the per-job appender tail so that:
3012
+ * 1. The snapshot's `messages` is consistent with the `job_messages` table
3013
+ * no row is still in flight at snapshot time.
3014
+ * 2. For terminal saves, the `DELETE FROM job_messages` inside `save()`
3015
+ * can't race a still-pending `appendOutgoing` for the final yield
3016
+ * message (which would otherwise wipe the row before an in-flight SSE
3017
+ * subscriber's NOTIFY-driven fetch can see it).
3132
3018
  */
3133
3019
  persistJob(job: ServerJob): Promise<void>;
3134
3020
  /**
3135
- * Cross-machine terminal guard (internal-review). `buildContext`'s guard reads the
3021
+ * Cross-machine terminal guard. `buildContext`'s guard reads the
3136
3022
  * in-memory `job.status`, so on its own it only protects the machine running
3137
3023
  * the handler. On a multi-machine DVM a `DELETE /v1/job/:id` routinely lands
3138
3024
  * on a machine that isn't running the job — `app.ts` cancels it in the store
@@ -3144,7 +3030,7 @@ declare class JobManager<State, InputSchema extends ZodLike | undefined> {
3144
3030
  * fires `job.abort` so in-flight `ctx.fetch` calls tear down. Returns true when
3145
3031
  * the durable state won and the caller must skip its save.
3146
3032
  *
3147
- * Two triggers: `watchDurableStatus`'s NOTIFY subscription (internal-review) fires
3033
+ * Two triggers: `watchDurableStatus`'s NOTIFY subscription fires
3148
3034
  * this within a round-trip of the remote cancel committing, which is what
3149
3035
  * actually stops the provider spend; `persistJob` calls it again on every save
3150
3036
  * as the backstop for the window where a cancel commits between a handler's
@@ -3163,7 +3049,7 @@ declare class JobManager<State, InputSchema extends ZodLike | undefined> {
3163
3049
  /** Durably merge a terminal handler owner's latest cost before reporting it. */
3164
3050
  private persistAdoptedTerminalCost;
3165
3051
  /**
3166
- * Watch the durable status of a locally-active job (internal-review).
3052
+ * Watch the durable status of a locally-active job.
3167
3053
  *
3168
3054
  * `ctx.signal` is raised by `dispatchMessage`, which only runs on the machine
3169
3055
  * holding the job in `activeJobs`. On a multi-machine DVM the `DELETE` usually
@@ -3181,30 +3067,30 @@ declare class JobManager<State, InputSchema extends ZodLike | undefined> {
3181
3067
  */
3182
3068
  private watchDurableStatus;
3183
3069
  /**
3184
- * Tear down a job's durable-status subscription (internal-review). Must be called
3070
+ * Tear down a job's durable-status subscription. Must be called
3185
3071
  * wherever a job leaves `activeJobs` — a leaked subscriber outlives the job on
3186
3072
  * the store's shared LISTEN connection. Idempotent.
3187
3073
  */
3188
3074
  unwatchDurableStatus(jobId: string): void;
3189
3075
  /**
3190
- * NOTIFY-driven durable-status re-read, coalesced per job (internal-review).
3076
+ * NOTIFY-driven durable-status re-read, coalesced per job.
3191
3077
  *
3192
3078
  * A notify that arrives while a re-read is in flight is queued rather than
3193
3079
  * dropped: the in-flight read may have observed the row a moment *before* the
3194
- * cancel committed, and dropping its notify would put the abort back where
3195
- * this issue found it — waiting for the handler's next store write.
3080
+ * cancel committed, and dropping its notify would leave the local handler
3081
+ * running until its next store write instead of aborting promptly.
3196
3082
  */
3197
3083
  private checkDurableTerminal;
3198
3084
  /**
3199
3085
  * Wire the Tx A appender when the store supports streaming.
3200
3086
  *
3201
- * Tx A (internal-review): outgoing message + `pending_payment_msats` bump land in
3087
+ * Tx A: outgoing message + `pending_payment_msats` bump land in
3202
3088
  * the same transaction. The DB allocates the row's seq via
3203
3089
  * `UPDATE jobs SET next_seq = next_seq + 1 RETURNING` so concurrent inbound
3204
3090
  * traffic on different machines can never collide on the `(job_id, seq)` PK.
3205
3091
  * In-memory `job.seq` keeps its own counter for same-machine SSE listeners.
3206
3092
  *
3207
- * Per-job serialisation (internal-review): chained through `job.messageAppenderTail`
3093
+ * Per-job serialisation: chained through `job.messageAppenderTail`
3208
3094
  * so two synchronous `providerMessage` calls (e.g. `artifact` followed by
3209
3095
  * `complete`) commit their `appendOutgoing` transactions in call order.
3210
3096
  * Without this, the two transactions race for the `jobs` row lock and the
@@ -3219,15 +3105,15 @@ declare class JobManager<State, InputSchema extends ZodLike | undefined> {
3219
3105
  startIdleTimer(job: ServerJob): void;
3220
3106
  /** Clear the idle timer for a job. */
3221
3107
  clearIdleTimer(id: string): void;
3222
- /** Cancel a job due to idle timeout. Exposed for the reactivation path's idle-expiry guard (internal-review). */
3108
+ /** Cancel a job due to idle timeout. Exposed for the reactivation path's idle-expiry guard. */
3223
3109
  cancelJobIdle(job: ServerJob): Promise<void>;
3224
3110
  /**
3225
3111
  * Force-terminate stale non-terminal jobs. Two status-aware arms:
3226
- * • `awaiting-input` past `staleJobTimeoutMs` → `cancelled`
3227
- * (`stale_no_terminal_status`) — the caller never paid / responded.
3228
- * • `processing`/`working` past `processingWatchdogMs` → `failed`
3229
- * (`worker_died_mid_job`) — the worker died mid-job. The heartbeat keeps
3230
- * live workers fresh, so a stale row here means a dead process.
3112
+ * • `awaiting-input` past `staleJobTimeoutMs` → `cancelled`
3113
+ * (`stale_no_terminal_status`) — the caller never paid / responded.
3114
+ * • `processing`/`working` past `processingWatchdogMs` → `failed`
3115
+ * (`worker_died_mid_job`) — the worker died mid-job. The heartbeat keeps
3116
+ * live workers fresh, so a stale row here means a dead process.
3231
3117
  *
3232
3118
  * Fires on a timer (wired in the constructor) and also callable on demand
3233
3119
  * (tests, ops). The CAS in `cancelStaleJob` makes this safe to run
@@ -3236,17 +3122,17 @@ declare class JobManager<State, InputSchema extends ZodLike | undefined> {
3236
3122
  * descriptors — the local activeJobs teardown only makes sense on the
3237
3123
  * JobManager that actually hosted the zombie handler.
3238
3124
  *
3239
- * **Both cutoffs float off the wall clock (internal-review).** Each is one
3125
+ * **Both cutoffs float off the wall clock.** Each is one
3240
3126
  * `Date.now()` sample compared against `last_activity_at`, stamped from a
3241
3127
  * different sample at a different moment, so a backwards step between the
3242
3128
  * two makes every row look more recently active than it is: the query
3243
3129
  * matches nothing and both arms go silent for the length of the skew. The
3244
3130
  * dead worker's job keeps its `processing` status, its credit hold stays
3245
- * `pending`, and the internal-review paid-job-death alert — wired to this reaper —
3246
- * never fires. Same defect, same host class, as internal-review's orphan sweep.
3131
+ * `pending`, and the paid-job-death alert — wired to this reaper —
3132
+ * never fires. Same defect, same host class, as orphan sweep.
3247
3133
  *
3248
3134
  * **The compensation is capped** — see {@link staleSweepCompensationCapMs}
3249
- * for where each arm's cap comes from — which internal-review did not need to do. Its eagerness costs at worst an early release
3135
+ * for where each arm's cap comes from — which did not need to do. Its eagerness costs at worst an early release
3250
3136
  * of an unclaimed hold, refused outright for any live job row; ours
3251
3137
  * force-*fails* a running job. `cancelStaleJob`'s CAS does not cover that:
3252
3138
  * `expectedActivityBefore` is the same compensated threshold the query used,
@@ -3278,7 +3164,7 @@ declare class JobManager<State, InputSchema extends ZodLike | undefined> {
3278
3164
  }>;
3279
3165
  /**
3280
3166
  * How far one watchdog arm may lean on {@link monotonicNowMs} past the wall
3281
- * clock to cover a backwards step (internal-review). The compensation is capped,
3167
+ * clock to cover a backwards step. The compensation is capped,
3282
3168
  * not free: a claimed row must still have been silent for
3283
3169
  * `windowMs - cap`, and unlike the orphan sweep, claiming eagerly here
3284
3170
  * force-fails a job that may well be alive.
@@ -3298,7 +3184,7 @@ declare class JobManager<State, InputSchema extends ZodLike | undefined> {
3298
3184
  * clock stepped. That pair is marginal already; the guard must not make it
3299
3185
  * deterministic. The cap collapses to zero there, which is today's
3300
3186
  * behaviour: late, never wrong. The `awaiting-input` arm takes no such term
3301
- * — nothing heartbeats it by design, and its refresh is an inbound caller
3187
+ * nothing heartbeats it by design, and its refresh is an inbound caller
3302
3188
  * message on no cadence at all.
3303
3189
  *
3304
3190
  * **Why a magnitude and not a predicate.** The tempting sharper rule is to
@@ -3335,7 +3221,7 @@ declare class JobManager<State, InputSchema extends ZodLike | undefined> {
3335
3221
  * Resolve `pending` credit draws the terminal funnel can no longer reach.
3336
3222
  * Two arms over one scan, distinguished by whether the draw's job row exists.
3337
3223
  *
3338
- * **No job row (internal-review) — release.** internal-review allocates the job id and
3224
+ * **No job row — release.** allocates the job id and
3339
3225
  * commits the ledger draw, with its `job_id` linkage, before `recordReplay`
3340
3226
  * and `persistJob` write the job row. A crash, a `draw_conflict` 409, or a
3341
3227
  * fail-closed `replay_detected` 401 in that window leaves a committed hold
@@ -3345,12 +3231,12 @@ declare class JobManager<State, InputSchema extends ZodLike | undefined> {
3345
3231
  * available balance stays reduced forever. Cosmetic for an implicit N=1
3346
3232
  * credit, a silent balance shrink for an explicit N>1 one.
3347
3233
  *
3348
- * **Terminal job row (internal-review) — reconcile to its outcome.** The funnel
3234
+ * **Terminal job row — reconcile to its outcome.** The funnel
3349
3235
  * demonstrably fails: `resolveCreditDraw` throws on a ledger/DB error,
3350
3236
  * `issueReceipt` catches it, logs `credit_resolve_failed` and returns
3351
3237
  * nothing, and until now nothing retried. Same stranded hold, reached through
3352
3238
  * a different door — and for a `completed` job it strands the platform's
3353
- * books too, since draws *are* the revenue events (internal-review): the caller is
3239
+ * books too, since draws *are* the revenue events: the caller is
3354
3240
  * charged nothing, the balance never moves, and outstanding liability
3355
3241
  * (`deposits − draw revenue`) overstates forever. So a late settle books, off
3356
3242
  * the committed draw row, through the ordinary reporter path.
@@ -3377,8 +3263,8 @@ declare class JobManager<State, InputSchema extends ZodLike | undefined> {
3377
3263
  reconciled: number;
3378
3264
  }>;
3379
3265
  /**
3380
- * The end-of-scan line for a tick that resolved nothing (internal-review, extended
3381
- * by internal-review). Two shapes are worth a warning, and neither is the ordinary
3266
+ * The end-of-scan line for a tick that resolved nothing. Two shapes are
3267
+ * worth a warning, and neither is the ordinary
3382
3268
  * one — the timer runs every 5 minutes per ledger in production.
3383
3269
  *
3384
3270
  * `examined > 0`: aged candidates were looked at and none moved. Usually
@@ -3387,7 +3273,7 @@ declare class JobManager<State, InputSchema extends ZodLike | undefined> {
3387
3273
  *
3388
3274
  * `examined === 0`: the query returned nothing. Ordinarily that means there
3389
3275
  * is nothing to do — but it is equally what a blinded scan looks like, which
3390
- * is the case the internal-review gate could not reach. Probe for the oldest
3276
+ * is the case the gate could not reach. Probe for the oldest
3391
3277
  * `pending` hold at any age and speak up when one exists the scan should
3392
3278
  * have seen and didn't: already past the age gate outright, stamped ahead of
3393
3279
  * our clock (some other process's clock is fast), or hidden while our own
@@ -3400,7 +3286,7 @@ declare class JobManager<State, InputSchema extends ZodLike | undefined> {
3400
3286
  */
3401
3287
  private reportSweepOutcome;
3402
3288
  /**
3403
- * Resolve one aged `pending` draw whose job row reached terminal (internal-review),
3289
+ * Resolve one aged `pending` draw whose job row reached terminal,
3404
3290
  * mirroring what `resolveCreditDraw` would have done in line. Returns true
3405
3291
  * when this call is the one that moved the draw — the caller counts it, and
3406
3292
  * only it books.
@@ -3434,7 +3320,7 @@ declare class JobManager<State, InputSchema extends ZodLike | undefined> {
3434
3320
  /**
3435
3321
  * Refresh `lastActivityAt` for jobs this process is actively running
3436
3322
  * (`processing`/`working`) so the processing watchdog only fires once the
3437
- * worker is genuinely dead (internal-review). `awaiting-input` jobs are
3323
+ * worker is genuinely dead. `awaiting-input` jobs are
3438
3324
  * deliberately excluded — their idle timeout must still elapse. Fires on the
3439
3325
  * heartbeat timer; also callable on demand for tests.
3440
3326
  */
@@ -3442,15 +3328,15 @@ declare class JobManager<State, InputSchema extends ZodLike | undefined> {
3442
3328
  beat: number;
3443
3329
  }>;
3444
3330
  /**
3445
- * Single-execution claim for a reactivating machine (internal-review). Before
3331
+ * Single-execution claim for a reactivating machine. Before
3446
3332
  * replaying an `awaiting-input` job, wait a bounded grace window for a live
3447
3333
  * original handler to win the `awaiting-input → processing` CAS via its
3448
3334
  * NOTIFY wake. Resolves:
3449
- * • `false` — the row left `awaiting-input` during the window (the original
3450
- * handler claimed it / drove it terminal). Stand down; do not replay.
3451
- * • `true` — the window elapsed still `awaiting-input` (the original worker
3452
- * is gone or has no live resolver) AND this machine won the claim CAS.
3453
- * Replay for dead-worker recovery.
3335
+ * • `false` — the row left `awaiting-input` during the window (the original
3336
+ * handler claimed it / drove it terminal). Stand down; do not replay.
3337
+ * • `true` — the window elapsed still `awaiting-input` (the original worker
3338
+ * is gone or has no live resolver) AND this machine won the claim CAS.
3339
+ * Replay for dead-worker recovery.
3454
3340
  *
3455
3341
  * Biasing the original handler to win kills the double execution (double
3456
3342
  * substrate spend, clobbered artifact) without heartbeating `awaiting-input`
@@ -3459,7 +3345,7 @@ declare class JobManager<State, InputSchema extends ZodLike | undefined> {
3459
3345
  */
3460
3346
  claimAwaitingInputForReactivation(jobId: string): Promise<boolean>;
3461
3347
  /**
3462
- * Record an inbound client message durably via Tx B (internal-review) and append
3348
+ * Record an inbound client message durably via Tx B and append
3463
3349
  * it to the in-memory `job.messages` array. Returns the DB-allocated seq
3464
3350
  * (`null` when the store isn't streamable — non-Postgres test fallback).
3465
3351
  *
@@ -3478,13 +3364,13 @@ declare class JobManager<State, InputSchema extends ZodLike | undefined> {
3478
3364
  * in-memory `ServerJob`, wires the appender, builds the context, starts
3479
3365
  * the idle timer. The caller has already recorded the inbound via Tx B
3480
3366
  * and run Tx C (verify + credit); reactivation is now decoupled from
3481
- * credit (internal-review, internal-review). The caller decides whether to run the
3367
+ * credit. The caller decides whether to run the
3482
3368
  * handler (Pattern A: status was `awaiting-input`) or to dispatch the
3483
3369
  * message to a custom handler (Pattern B).
3484
3370
  *
3485
3371
  * For DVMs that declare descriptor-level auth, the persisted
3486
3372
  * `record.input` carries the original signed envelope. We re-verify the
3487
- * signature here (internal-review) so a DB-layer tamper — compromised admin, SQL
3373
+ * signature here so a DB-layer tamper — compromised admin, SQL
3488
3374
  * injection, malicious operator with DB access — can't silently feed an
3489
3375
  * attacker-supplied pubkey/envelope into the handler. The drift window
3490
3376
  * and replay store are deliberately skipped: the persisted timestamp is
@@ -3498,7 +3384,7 @@ declare class JobManager<State, InputSchema extends ZodLike | undefined> {
3498
3384
  * What gets re-verified is the persisted row read back through
3499
3385
  * {@link signedRequestInput} — `app.ts` stores the pre-Zod wire form, so
3500
3386
  * those are the caller's own signed bytes, the same ones `/v1/quote` and the
3501
- * submit checked (internal-review). That makes the tamper check strictly stronger
3387
+ * submit checked. That makes the tamper check strictly stronger
3502
3388
  * than the parsed form it replaced: an injected key the capability schema
3503
3389
  * doesn't declare used to be stripped before the signature was checked, so
3504
3390
  * it re-verified clean.
@@ -3508,7 +3394,7 @@ declare class JobManager<State, InputSchema extends ZodLike | undefined> {
3508
3394
  sdkCtx: SDKJobContext<unknown, unknown>;
3509
3395
  };
3510
3396
  /**
3511
- * Verify an inbound payment and apply the credit via Tx C (internal-review).
3397
+ * Verify an inbound payment and apply the credit via Tx C.
3512
3398
  * The inbound message must have been recorded via Tx B already
3513
3399
  * (`recordInboundPending` returned `inboundSeq`). For non-streamable
3514
3400
  * stores (`inboundSeq === null`), falls back to in-memory mutation via
@@ -3518,12 +3404,12 @@ declare class JobManager<State, InputSchema extends ZodLike | undefined> {
3518
3404
  * `pendingPaymentMsats` without external verification. Gated on
3519
3405
  * `devModeSkipsPaymentVerification` — the same predicate the upfront path
3520
3406
  * reads, so a dev server wired to a mint verifies mid-job payments for real
3521
- * (internal-review) — plus the explicit `dev_auto` opt-out the dev console uses,
3407
+ * plus the explicit `dev_auto` opt-out the dev console uses,
3522
3408
  * which is the one caller that has no wallet to pay from. `dev_auto` loses to
3523
3409
  * any proof riding the same message: money on the wire always takes the rail,
3524
3410
  * so the flag can never leave a real token unspent against a credited job.
3525
3411
  *
3526
- * Tx C is not atomic with the rail commit (internal-review). `verifyIncomingPayment`
3412
+ * Tx C is not atomic with the rail commit. `verifyIncomingPayment`
3527
3413
  * commits the proofs *and* the ledger leg in one transaction and returns;
3528
3414
  * only then does `verifyAndCredit` write the job row, on its own connection.
3529
3415
  * Everything after that call therefore runs with the caller's money already
@@ -3539,7 +3425,7 @@ declare class JobManager<State, InputSchema extends ZodLike | undefined> {
3539
3425
  mintHealthTracker?: MintHealthTracker;
3540
3426
  }): Promise<ProcessPaymentOutcome>;
3541
3427
  /**
3542
- * Tx C with a bounded retry (internal-review).
3428
+ * Tx C with a bounded retry.
3543
3429
  *
3544
3430
  * By the time this runs on the verified path, the rail commit and the ledger
3545
3431
  * leg have already committed in a transaction this call is not part of — so a
@@ -3573,7 +3459,7 @@ declare class JobManager<State, InputSchema extends ZodLike | undefined> {
3573
3459
  private creditInbound;
3574
3460
  /**
3575
3461
  * Answer a payment whose rail and ledger legs committed but whose job row
3576
- * could not be written (internal-review) — every retry spent, the money real.
3462
+ * could not be written — every retry spent, the money real.
3577
3463
  *
3578
3464
  * The refusal names the credit the money landed on so the caller can act on
3579
3465
  * it directly, mirroring the short mid-job pay's 402 (`payment.ts`). It is a
@@ -3582,7 +3468,7 @@ declare class JobManager<State, InputSchema extends ZodLike | undefined> {
3582
3468
  * fault an operator should see in their 5xx rate. `retryable` is true because
3583
3469
  * the ask is genuinely still outstanding.
3584
3470
  *
3585
- * Nothing is released here. The hold is left to the internal-review reconciler,
3471
+ * Nothing is released here. The hold is left to the reconciler,
3586
3472
  * which makes the same decision — unbound draw ⇒ release, never settle — but
3587
3473
  * under the credit row's `FOR UPDATE`, after the job is terminal, where it
3588
3474
  * cannot race an in-flight COMMIT. Releasing from here would also be
@@ -3605,23 +3491,23 @@ declare class JobManager<State, InputSchema extends ZodLike | undefined> {
3605
3491
  private reportUnappliedPayment;
3606
3492
  /**
3607
3493
  * Describe a deposit the job row never took, in the shape both the 201 and
3608
- * the `payment_unapplied` 500 carry (internal-review). `undefined` when the payment
3494
+ * the `payment_unapplied` 500 carry. `undefined` when the payment
3609
3495
  * ran ledger-less (no credit ledger wired, or the top-up preflight skipped) —
3610
3496
  * there is no credit to name, so the 201 carries no `credit` block and the
3611
3497
  * 500 takes its words from `unappliedCopy` directly.
3612
3498
  */
3613
3499
  private unappliedCredit;
3614
- /** Book a mid-job top-up's funding as a deposit (internal-review, spec §10). */
3500
+ /** Book a mid-job top-up's funding as a deposit (the deposit-accounting rule). */
3615
3501
  private reportCreditDeposit;
3616
3502
  /**
3617
3503
  * Internal: build the BuildContextOpts shared between `createJob` and
3618
3504
  * `reactivateJob`. Centralised so persistence/terminal callbacks and the
3619
- * internal-review NOTIFY-driven cross-machine wake stay in one place.
3505
+ * NOTIFY-driven cross-machine wake stay in one place.
3620
3506
  */
3621
3507
  private buildContextOpts;
3622
3508
  /**
3623
3509
  * Internal: what unit `ctx.requestPayment`'s auto-credit gate may measure this
3624
- * job's remaining pool in (internal-review).
3510
+ * job's remaining pool in.
3625
3511
  *
3626
3512
  * The regime is read off the DRAW, never off the job. Implicit N=1 is exactly
3627
3513
  * `credit_id === imp:<rail>:<draw_id>`, because `fundAndDraw` derives both
@@ -3639,15 +3525,14 @@ declare class JobManager<State, InputSchema extends ZodLike | undefined> {
3639
3525
  * drew and whose pool this can't read or denominate answers `unpriced`, which
3640
3526
  * the gate declines to auto-credit from: the msat figure it would otherwise
3641
3527
  * fall back on is a slice of the credit's rail value at a ratio pinned
3642
- * whenever that credit was funded, which is the exact figure this issue exists
3643
- * to stop spending against.
3528
+ * whenever that credit was funded, so it cannot safely fund a new ask.
3644
3529
  */
3645
3530
  private resolveDrawPool;
3646
3531
  /** Internal: structured warn for the one path that can't price a drawn job's pool. */
3647
3532
  private warnDrawPool;
3648
3533
  /**
3649
3534
  * Issue the signed receipt for a job that has reached a terminal status
3650
- * (internal-review). Idempotent and safe to call from every terminal path — the
3535
+ * Idempotent and safe to call from every terminal path — the
3651
3536
  * store owns both the sequence allocation and the write-once persist, so
3652
3537
  * two machines racing on the same job converge on identical bytes and burn
3653
3538
  * exactly one sequence number.
@@ -3663,10 +3548,10 @@ declare class JobManager<State, InputSchema extends ZodLike | undefined> {
3663
3548
  /** Build the common settle/release args, adding the hosted release outbox when wired. */
3664
3549
  private drawResolutionArgs;
3665
3550
  /**
3666
- * Settle or release a terminal job's credit draw (internal-review): `completed`
3551
+ * Settle or release a terminal job's credit draw: `completed`
3667
3552
  * settles (the hold becomes a real debit); `failed`/`cancelled` releases
3668
3553
  * (the hold evaporates — "no debit on job failure", mechanically
3669
- * superseding the internal-review/974 no-op refund for credit-paid jobs, including
3554
+ * superseding the 974 no-op refund for credit-paid jobs, including
3670
3555
  * the `ctx.fail` path and the stale-sweeper reap). Idempotent — a replayed
3671
3556
  * resolution returns the recorded state. Returns the `ReceiptCredit` block
3672
3557
  * for the receipt: `balance_after` is the recorded draw trajectory for a
@@ -3674,7 +3559,7 @@ declare class JobManager<State, InputSchema extends ZodLike | undefined> {
3674
3559
  */
3675
3560
  private resolveCreditDraw;
3676
3561
  /**
3677
- * The one place a terminal job's status becomes a ledger verb (internal-review):
3562
+ * The one place a terminal job's status becomes a ledger verb:
3678
3563
  * `completed` settles the hold into a real debit, `failed`/`cancelled`
3679
3564
  * release it. Read by the in-line funnel (`resolveCreditDraw`) and by the
3680
3565
  * late reconciler (`reconcileTerminalDraw`) — two paths that must never
@@ -3688,32 +3573,26 @@ declare class JobManager<State, InputSchema extends ZodLike | undefined> {
3688
3573
  */
3689
3574
  private attachReceipt;
3690
3575
  /**
3691
- * Read-path repair for a terminal job carrying no receipt (internal-review), for
3576
+ * Read-path repair for a terminal job carrying no receipt, for
3692
3577
  * either an in-memory job or a store record. Free in the steady state — it
3693
3578
  * returns on the `receipt` check without touching the store — so it costs
3694
3579
  * only on the cases it exists for:
3695
3580
  *
3696
3581
  * - **A crash between the two store calls.** `claimReceiptSeq` commits the
3697
- * sequence number to the job row before `saveReceipt` writes the bytes; a
3698
- * process death in that window would otherwise strand that number
3699
- * forever, and a permanent gap is indistinguishable from the deliberate
3700
- * suppression `seq` exists to expose. Re-issuing here reuses the already
3701
- * committed number (the claim is idempotent per job) rather than
3702
- * allocating a second one.
3582
+ * sequence number to the job row before `saveReceipt` writes the bytes; a
3583
+ * process death in that window would otherwise strand that number
3584
+ * forever, and a permanent gap is indistinguishable from the deliberate
3585
+ * suppression `seq` exists to expose. Re-issuing here reuses the already
3586
+ * committed number (the claim is idempotent per job) rather than
3587
+ * allocating a second one.
3703
3588
  * - **A transient store failure** at the terminal: `issueReceipt` logs
3704
- * `receipt_issue_failed` and returns nothing rather than failing the job,
3705
- * so the next read retries.
3589
+ * `receipt_issue_failed` and returns nothing rather than failing the job,
3590
+ * so the next read retries.
3706
3591
  * - **Jobs that terminated before the DVM had a receipt key.** They pick one
3707
- * up on first read, with `issued_at` reflecting when it was signed.
3592
+ * up on first read, with `issued_at` reflecting when it was signed.
3708
3593
  */
3709
3594
  ensureReceipt(target: ServerJob | JobRecord): Promise<void>;
3710
- /**
3711
- * Close out a terminal job whose caller hasn't already persisted it: sign
3712
- * the receipt, then save the snapshot. The snapshot save never writes the
3713
- * receipt column, so ordering only affects how soon a reader sees the
3714
- * receipt — this way a caller polling immediately after the terminal
3715
- * already finds it.
3716
- */
3595
+ /** Commit the terminal snapshot before resolving money and signing its durable evidence. */
3717
3596
  private finalizeTerminal;
3718
3597
  /**
3719
3598
  * Issue a receipt for a job this process doesn't hold in `activeJobs` — a
@@ -3724,9 +3603,12 @@ declare class JobManager<State, InputSchema extends ZodLike | undefined> {
3724
3603
  issueReceiptForStoredJob(jobId: string): Promise<JobReceipt | undefined>;
3725
3604
  /**
3726
3605
  * Finish accounting for a terminal written directly to the store — the
3727
- * stale reaper and a cancel handled on a different machine (internal-review).
3606
+ * stale reaper and a cancel handled on a different machine.
3728
3607
  */
3729
3608
  finalizeStoredTerminal(jobId: string): Promise<JobReceipt | undefined>;
3609
+ private reportTerminalJob;
3610
+ private terminalReportRecoveryCursor?;
3611
+ private recoverTerminalReports;
3730
3612
  /** Handle job reaching terminal state (completed, failed, cancelled). */
3731
3613
  private handleJobTerminal;
3732
3614
  /**
@@ -3744,11 +3626,11 @@ declare class JobManager<State, InputSchema extends ZodLike | undefined> {
3744
3626
  /** Report the latest declared-cost state only when no revenue event carried it. */
3745
3627
  private reportJobCost;
3746
3628
  /**
3747
- * Report a completed paid job's revenue (internal-review, re-keyed by internal-review).
3629
+ * Report a completed paid job's revenue under its durable job identity.
3748
3630
  * Fire-and-forget — the `RevenueReporter` owns persistence and retry.
3749
3631
  *
3750
3632
  * For a **credit-backed** job the revenue event is the *settled draw* (spec
3751
- * §10), and since internal-review the sats figure corrects the job's mirror of that
3633
+ * §10), and since the behavior was introduced the sats figure corrects the job's mirror of that
3752
3634
  * draw against the draw itself: `withDrawBasis` stamps the job when the
3753
3635
  * payment lands, but a Bitcoin credit's settle re-prices the draw against
3754
3636
  * the funding lots it consumed. The correction is a delta, because a job's
@@ -3763,7 +3645,7 @@ declare class JobManager<State, InputSchema extends ZodLike | undefined> {
3763
3645
  * whose price couldn't be fiat-denominated) nothing changes: the pre-credits
3764
3646
  * payload is reported verbatim.
3765
3647
  *
3766
- * Takes the fields rather than a `ServerJob` so the internal-review reconciler — a
3648
+ * Takes the fields rather than a `ServerJob` so the reconciler — a
3767
3649
  * background sweep that holds no in-process job — books through this exact
3768
3650
  * path off the row it read. `paymentTxHash` is passed **verbatim**, never
3769
3651
  * recomputed as a `drawSettlementRef`: it is the same column the in-line
@@ -3780,7 +3662,7 @@ declare class JobManager<State, InputSchema extends ZodLike | undefined> {
3780
3662
  * DVM with no reporter). Every drop that costs a booking logs first.
3781
3663
  *
3782
3664
  * The rail check sits **below** the draw re-read, not in the entry guard
3783
- * (internal-review): a settled draw the terminal can't report under is a real debit
3665
+ * a settled draw the terminal can't report under is a real debit
3784
3666
  * with no revenue event, permanently overstating outstanding liability
3785
3667
  * (`deposits − draw revenue`), and it used to return here in silence. Placed
3786
3668
  * after the re-read, `revenue_skipped_no_rail` can name the draw and its
@@ -3801,7 +3683,7 @@ interface LightningRailHealth {
3801
3683
  refresh?(): Promise<void>;
3802
3684
  }
3803
3685
 
3804
- /** Builder-facing wiring for the Lightning receive leg (internal-review). */
3686
+ /** Builder-facing wiring for the Lightning receive leg. */
3805
3687
  interface LightningReceiveConfig {
3806
3688
  /**
3807
3689
  * Receive-only NWC connection URI (`DVMKIT_NWC_RECEIVE_URI`). Validated at
@@ -3835,27 +3717,26 @@ interface LightningReceiveConfig {
3835
3717
  declare const DEFAULT_INVOICE_TTL_SECONDS = 900;
3836
3718
  /**
3837
3719
  * Floor on the invoice lifetime: twice the signed-request drift window, so the
3838
- * bolt11 always outlives the funding negotiation that produced it (the issue's
3839
- * "invoice expiry ≥ the funding-negotiation window"). A shorter one would
3720
+ * bolt11 always outlives the funding negotiation that produced it. A shorter one would
3840
3721
  * expire inside the caller's own retry budget and strand them mid-top-up.
3841
3722
  */
3842
3723
  declare const MIN_INVOICE_TTL_SECONDS = 600;
3843
3724
  /**
3844
- * The builder-side Lightning receive leg (internal-review, credits spec §4).
3725
+ * The builder-side Lightning receive leg for funding prepaid credit.
3845
3726
  *
3846
3727
  * Issues a bolt11 over a **receive-only** NWC connection while the DVM is
3847
3728
  * awake serving the 402, and credits the ledger when a later request observes
3848
3729
  * settlement. Two properties are load-bearing:
3849
3730
  *
3850
3731
  * - **It never holds a send credential.** `pay_invoice` on this connection is
3851
- * refused at construction, so a compromised DVM can mint invoices and
3852
- * nothing else. The drain/refund sender (internal-review) is a separate, budgeted
3853
- * connection by rule.
3732
+ * refused at construction, so a compromised DVM can mint invoices and
3733
+ * nothing else. The drain/refund sender is a separate, budgeted
3734
+ * connection by rule.
3854
3735
  * - **Crediting is pull-based — there is no settlement watcher.** The caller's
3855
- * next request drives `lookup_invoice`, which is what makes this work on a
3856
- * suspend-to-zero fleet: a machine that is asleep has nothing to miss.
3857
- * Wallet downtime at that moment delays crediting; it never loses money,
3858
- * because the invoice→credit binding is a durable row.
3736
+ * next request drives `lookup_invoice`, which is what makes this work on a
3737
+ * suspend-to-zero fleet: a machine that is asleep has nothing to miss.
3738
+ * Wallet downtime at that moment delays crediting; it never loses money,
3739
+ * because the invoice→credit binding is a durable row.
3859
3740
  *
3860
3741
  * Reachability is **cached**, never probed per request: the funding menu is
3861
3742
  * assembled on every quote and every 402, so a live NIP-47 round trip there
@@ -3897,7 +3778,7 @@ declare class LightningReceive {
3897
3778
  * Issue (or re-issue) the bolt11 funding `(creditId, fundId)`.
3898
3779
  *
3899
3780
  * The invoice is minted **for** the credit and amount named in the caller's
3900
- * signed body — that binding is the internal-review condition-3 commitment on this
3781
+ * signed body — that binding is the condition-3 commitment on this
3901
3782
  * rail, and it is why no artifact hash rides the request: there is no
3902
3783
  * caller-supplied artifact to hash. A re-poll returns the stored row rather
3903
3784
  * than minting again; a second bolt11 for one `fund_id` would leave two
@@ -3913,7 +3794,7 @@ declare class LightningReceive {
3913
3794
  description?: string;
3914
3795
  }): Promise<CreditInvoiceRecord>;
3915
3796
  /**
3916
- * Ask the wallet whether one payment hash is paid, and when (internal-review).
3797
+ * Ask the wallet whether one payment hash is paid, and when.
3917
3798
  *
3918
3799
  * The operator's reconcile verb runs this before it credits anything. A
3919
3800
  * `blocked` row implies payment — {@link applyOne} returns above the block
@@ -4019,7 +3900,7 @@ declare class LightningReceive {
4019
3900
  }
4020
3901
 
4021
3902
  /**
4022
- * Owner display identity surfaced on `/v1/info#owner` (internal-review). Personal orgs
3903
+ * Owner display identity surfaced on `/v1/info#owner`. Personal orgs
4023
3904
  * resolve to the owner builder's profile; shared orgs resolve to the org's own
4024
3905
  * profile. Container DVMs read from env vars; isolate DVMs resolve from Postgres.
4025
3906
  */
@@ -4035,16 +3916,16 @@ interface BuilderIdentity {
4035
3916
  name?: string;
4036
3917
  url?: string;
4037
3918
  /**
4038
- * Builder identity x-only secp256k1 pubkey (internal-review). When populated, the
3919
+ * Builder identity x-only secp256k1 pubkey. When populated, the
4039
3920
  * `/v1/info#builder` block also carries `attestation` + `signature` so
4040
3921
  * consumers can verify the deploy was signed by the holder of this key.
4041
3922
  * Populated at deploy time from `DVMKIT_BUILDER_PUBKEY` (Fly secret); the
4042
3923
  * SDK never re-signs at runtime.
4043
3924
  */
4044
3925
  pubkey?: string;
4045
- /** Canonical deploy-time attestation payload (internal-review). Served verbatim. */
3926
+ /** Canonical deploy-time attestation payload. Served verbatim. */
4046
3927
  attestation?: AttestationPayload;
4047
- /** Schnorr signature over `canonicaliseForSigning(attestation)` (internal-review). */
3928
+ /** Schnorr signature over `canonicaliseForSigning(attestation)`. */
4048
3929
  signature?: string;
4049
3930
  }
4050
3931
  /** Platform reporter overrides — the host falls back to env when omitted. */
@@ -4061,21 +3942,24 @@ interface DVMServeResult {
4061
3942
  /** Boot snapshot for each mount; configured but unusable rails remain payment-required. */
4062
3943
  paymentModes: PaymentMode[];
4063
3944
  }
4064
- /** Options for {@link createDVMHost}. */
4065
3945
  interface DVMHostOpts {
4066
3946
  /**
4067
3947
  * Postgres connection string. Defaults to `DATABASE_URL` env.
4068
- * Required at runtime (internal-review). Boot fails when missing unless `jobStore`
3948
+ * Required at runtime. Boot fails when missing unless `jobStore`
4069
3949
  * is explicitly supplied or `devMode` is true (test/dev escape hatches).
4070
3950
  */
4071
3951
  database?: string;
4072
3952
  /** Listen port. Defaults to `PORT` env or 8080. */
4073
3953
  port?: number;
4074
- /** Environment variables. Defaults to `process.env`. */
3954
+ /**
3955
+ * Environment variables. Defaults to `process.env` when omitted. A supplied
3956
+ * object is the complete host configuration: absent fields do not fall back
3957
+ * to ambient process variables.
3958
+ */
4075
3959
  env?: Record<string, string>;
4076
3960
  /** Builder identity for `/v1/info` (forward-compatible). */
4077
3961
  builder?: BuilderIdentity;
4078
- /** Owner display identity for `/v1/info#owner` (internal-review). Falls back to env vars. */
3962
+ /** Owner display identity for `/v1/info#owner`. Falls back to env vars. */
4079
3963
  owner?: OwnerDisplay;
4080
3964
  /** Platform reporter overrides. Defaults to env-derived values. */
4081
3965
  platformReporter?: PlatformReporterOpts;
@@ -4093,7 +3977,7 @@ interface DVMHostOpts {
4093
3977
  jobStore?: JobStore;
4094
3978
  /**
4095
3979
  * Existing Postgres pool to reuse instead of opening one from `database`
4096
- * (internal-review test seam). When set, the host builds its JobStore / KVStore /
3980
+ * (also useful as a test seam). When set, the host builds its JobStore / KVStore /
4097
3981
  * cashu accumulator on this pool and leaves it open at shutdown — the caller
4098
3982
  * owns it. Lets the e2e harness run DVMs in `p2pk-accumulator` mode against
4099
3983
  * its single shared pool rather than spawning a pool per DVM.
@@ -4110,7 +3994,7 @@ interface DVMHostOpts {
4110
3994
  /** Payment methods override. Defaults to derived from configured rails. */
4111
3995
  paymentMethods?: PaymentMethod[];
4112
3996
  /**
4113
- * Lightning receive leg for credit funding (internal-review). Defaults to the
3997
+ * Lightning receive leg for credit funding. Defaults to the
4114
3998
  * env-resolved `DVMKIT_NWC_RECEIVE_URI` /
4115
3999
  * `DVMKIT_NWC_RECEIVE_INVOICE_TTL_SECONDS`. Pass `backend` to inject a
4116
4000
  * wallet directly — a test seam that skips the connect-time probe, so
@@ -4144,7 +4028,7 @@ interface MountOpts {
4144
4028
  /** Path prefix for this DVM's protocol routes (e.g. `/delete-feed`). */
4145
4029
  prefix?: string;
4146
4030
  }
4147
- /** Live DVM host. Single wiring locus for the SDK (internal-review). */
4031
+ /** Live DVM host. Single wiring locus for the SDK. */
4148
4032
  interface DVMHost {
4149
4033
  /**
4150
4034
  * Underlying Hono app for custom non-protocol routes that belong to the
@@ -4155,15 +4039,15 @@ interface DVMHost {
4155
4039
  /**
4156
4040
  * Resolved Postgres pool — undefined before `host.serve()` completes
4157
4041
  * database resolution, set thereafter. Exposed so DVM-local Postgres
4158
- * consumers (e.g. scrape's `ScrapeDb` per-fetch event store, internal-review)
4042
+ * consumers (e.g. scrape's `ScrapeDb` per-fetch event store)
4159
4043
  * can reuse the host's pool rather than constructing their own. Wire
4160
4044
  * inside descriptor `onBoot` (fires after pool init, before listener opens).
4161
4045
  */
4162
4046
  readonly pool: Pool | undefined;
4163
4047
  /**
4164
- * Money-safe credit ledger (internal-review) — undefined before `host.serve()`
4048
+ * Money-safe credit ledger — undefined before `host.serve()`
4165
4049
  * resolves stores, set thereafter. Postgres-backed when a pool exists;
4166
- * pool-less hosts get a shared in-memory ledger so the internal-review fund+draw
4050
+ * pool-less hosts get a shared in-memory ledger so the fund+draw
4167
4051
  * semantics hold everywhere. Same wiring window as `pool` (descriptor
4168
4052
  * `onBoot` fires after init, before the listener opens).
4169
4053
  */
@@ -4181,7 +4065,7 @@ interface DVMHost {
4181
4065
  shutdown(): Promise<void>;
4182
4066
  }
4183
4067
  /**
4184
- * Single wiring locus for SDK-side construction (internal-review). Replaces both the
4068
+ * Single wiring locus for SDK-side construction. Replaces both the
4185
4069
  * `serve()` wrapper and the `createDVMServer` direct path. Reads env once,
4186
4070
  * resolves payment rails, owns the Postgres pool, and mounts each DVM
4187
4071
  * descriptor as a Hono sub-app on `host.app`.
@@ -4190,13 +4074,12 @@ declare function createDVMHost(opts?: DVMHostOpts): DVMHost;
4190
4074
 
4191
4075
  /**
4192
4076
  * Cached liveness signal for the platform's central Tempo close observer
4193
- * (internal-review).
4194
4077
  *
4195
4078
  * A TIP-1034 session channel is only safe to accept while something is
4196
4079
  * watching the chain for its close: without that, a caller can consume value,
4197
4080
  * request a close, wait out the 900-second grace period and withdraw. So this
4198
4081
  * gate is **fail-closed**, which is the opposite of `lightning-rail-health.ts`
4199
- * — there, withholding a rail over an outage costs a sale; here, advertising
4082
+ * there, withholding a rail over an outage costs a sale; here, advertising
4200
4083
  * one costs the money. `tempo/charge` is untouched either way: a charge is an
4201
4084
  * ordinary payment with no channel and no close to watch.
4202
4085
  */
@@ -4219,7 +4102,7 @@ interface TempoObserverHealth {
4219
4102
  refresh?(): Promise<void>;
4220
4103
  /**
4221
4104
  * Register a mount's `tempo/session` **capability** so the poll can carry it
4222
- * back to the platform (internal-review).
4105
+ * back to the platform.
4223
4106
  *
4224
4107
  * The platform's `dvms.tempo_session_advertised_at` — the only filter on the
4225
4108
  * close observer's payee-fallback rung 2 — was written once per container
@@ -4230,7 +4113,7 @@ interface TempoObserverHealth {
4230
4113
  *
4231
4114
  * The reader must answer from **configuration**, never from
4232
4115
  * {@link TempoObserverHealth.available} — a fail-closed gate blip must not
4233
- * de-stamp the DVM, which is the internal-review failure through a new door.
4116
+ * de-stamp the DVM, which is the failure through a new door.
4234
4117
  *
4235
4118
  * Returns a disposer the mount calls on shutdown, so a torn-down capability
4236
4119
  * stops voting in the OR below.
@@ -4352,7 +4235,7 @@ declare class TempoSettlementReadiness {
4352
4235
  }
4353
4236
 
4354
4237
  /**
4355
- * Options for the revenue reporter readiness assertion (internal-review).
4238
+ * Options for the revenue reporter readiness assertion.
4356
4239
  *
4357
4240
  * The check branches on `platformUrl` presence — that's the unambiguous
4358
4241
  * "platform-hosted" signal. `failFast` stays on the opts as a general SDK
@@ -4361,13 +4244,13 @@ declare class TempoSettlementReadiness {
4361
4244
  interface RevenueBootCheckOpts {
4362
4245
  /**
4363
4246
  * General SDK strict-mode flag, sourced from `DVMKIT_FAIL_FAST` at the host
4364
- * boundary (internal-review). Reserved for future warning-vs-fatal SDK checks; the
4365
- * reporter check itself ignores it (internal-review), hence optional.
4247
+ * boundary. Reserved for future warning-vs-fatal SDK checks; the
4248
+ * reporter check itself ignores it, hence optional.
4366
4249
  */
4367
4250
  failFast?: boolean;
4368
4251
  /**
4369
4252
  * The SDK's canonical "this is a dev/test run" signal. Exempts the boot from
4370
- * the platform-hosted wiring requirement (internal-review) — see below.
4253
+ * the platform-hosted wiring requirement — see below.
4371
4254
  */
4372
4255
  devMode?: boolean;
4373
4256
  platformToken: string | undefined;
@@ -4376,63 +4259,38 @@ interface RevenueBootCheckOpts {
4376
4259
  hasPgPool: boolean;
4377
4260
  }
4378
4261
  /**
4379
- * Assert that revenue reporting is correctly configured at boot (internal-review).
4380
- *
4381
- * Platform-hosted DVMs (signalled by `DVMKIT_PLATFORM_URL`) unconditionally
4382
- * require `DVMKIT_PLATFORM_TOKEN`, `DVMKIT_DVM_ID`, and a database connection.
4383
- * Partial wiring is always fatal — there's no legitimate "platform set my URL
4384
- * but didn't finish wiring" case, and `DVMKIT_FAIL_FAST` has no effect here.
4385
- *
4386
- * Self-hosted DVMs (no `DVMKIT_PLATFORM_URL`) have no platform reporter
4387
- * contract to enforce — the SDK skips validation entirely.
4388
- *
4389
- * `devMode` boots are exempt (internal-review), mirroring the test-mint guard's
4390
- * exemption in `createDVMHost` (internal-review, `host.ts`). `devMode` is set by
4391
- * `dvmctl dev`, `standalone development tooling`, the money-loop, and the e2e/smoke
4392
- * harnesses — all of which spread `...process.env`, so a builder whose shell
4393
- * exports `DVMKIT_PLATFORM_URL` for their `dvmctl` platform commands would
4394
- * otherwise hit this FATAL on a dev server that reports no revenue anyway (no
4395
- * payment, no auth, no DB). Production boots never set it: first-party
4396
- * container entrypoints and `dvmctl serve` (`buildServeOpts`) both leave it
4397
- * unset — asserted in
4398
- * `__tests__/revenue-reporter-boot.test.ts`, not just claimed here.
4262
+ * Hosted boots (a platform URL is set) require a token, DVM ID and database;
4263
+ * partial wiring is fatal regardless of `failFast`. Self-hosted and `devMode`
4264
+ * boots skip this assertion. The exemption does not disable an already wired
4265
+ * reporter; the banner separately describes whether reporting is active.
4399
4266
  */
4400
4267
  declare function assertRevenueReporterReady(opts: RevenueBootCheckOpts): void;
4401
4268
  /** What the host's boot banner knows about the revenue reporter's wiring. */
4402
4269
  interface ReporterBannerOpts {
4403
4270
  /** `DVMKIT_PLATFORM_URL` — the platform-hosted signal. */
4404
4271
  platformUrl: string | undefined;
4405
- /** Whether `DVMKIT_PLATFORM_TOKEN` resolved — never the token itself (internal-review). */
4272
+ /** Whether `DVMKIT_PLATFORM_TOKEN` resolved — never the token itself. */
4406
4273
  hasPlatformToken: boolean;
4407
4274
  /** Whether `DVMKIT_DVM_ID` resolved. */
4408
4275
  hasDvmId: boolean;
4409
- /** Whether a Postgres pool is wired. */
4410
4276
  databaseConnected: boolean;
4411
- /** Dev/test boot — exempt from the wiring assertion above (internal-review). */
4412
4277
  devMode: boolean;
4413
4278
  }
4414
4279
  /**
4415
- * Render the boot banner's `Platform rep.` line (internal-review).
4280
+ * Render the boot banner's `Platform rep.` line.
4416
4281
  *
4417
4282
  * Lives here, next to the assertion, because `active` has to mirror the
4418
4283
  * reporter's own wiring gate in `createDVMServer` below — token **and** dvmId
4419
4284
  * **and** database. Miss one and the banner claims a reporter that was never
4420
4285
  * constructed.
4421
4286
  *
4422
- * On a production boot the assertion throws before the banner prints, so only
4423
- * `(self-hosted)` and `active` are reachable there. A `devMode` boot skips the
4424
- * assertion (internal-review), making it the one path where partial wiring reaches
4425
- * this line — say so plainly rather than shouting `misconfigured` at a builder
4426
- * whose shell merely exports the platform URL.
4287
+ * Partial dev wiring reaches the banner because the boot assertion is exempt;
4288
+ * it reports a dev status rather than a production configuration failure.
4427
4289
  */
4428
4290
  declare function revenueReporterBannerState(s: ReporterBannerOpts): string;
4429
- /** Options for creating the SDK server app. */
4430
4291
  interface SDKServerOpts {
4431
- /** Environment variables for ctx.env. */
4432
4292
  env: Record<string, string>;
4433
- /** KV store for ctx.store. */
4434
4293
  store: KVStore;
4435
- /** Cashu mints accepted for payment. */
4436
4294
  mints?: string[];
4437
4295
  /** Persistent backing store for job records. Default: in-memory. */
4438
4296
  jobStore?: JobStore;
@@ -4440,7 +4298,6 @@ interface SDKServerOpts {
4440
4298
  devMode?: boolean;
4441
4299
  /** Payment methods this DVM accepts. Default: derived from configured rails — adds "cashu" when `mints` is set, "x402" when `x402` is set, "tempo" when `tempo` is set. */
4442
4300
  paymentMethods?: PaymentMethod[];
4443
- /** x402 stablecoin payment configuration. */
4444
4301
  x402?: X402Config;
4445
4302
  /** Live facilitator capability gate. Hosts wire this after probing `/supported`. */
4446
4303
  x402FacilitatorHealth?: X402FacilitatorHealthLike;
@@ -4449,13 +4306,13 @@ interface SDKServerOpts {
4449
4306
  /**
4450
4307
  * Tracks already-consumed upfront-flow MPP credentials so the same
4451
4308
  * credential can't satisfy `POST /v1/job` twice within its `expires`
4452
- * window (internal-review). Default: in-memory, bounded, per-process. Swap for a
4309
+ * window. Default: in-memory, bounded, per-process. Swap for a
4453
4310
  * shared backend before deploying multiple replicas.
4454
4311
  */
4455
4312
  consumedCredentialStore?: ConsumedCredentialStore;
4456
4313
  /**
4457
4314
  * Tracks already-consumed admin-endpoint nonces so a signed P2PK challenge
4458
- * can't be replayed within the 5-minute sliding window (internal-review). Default:
4315
+ * can't be replayed within the 5-minute sliding window. Default:
4459
4316
  * in-memory, bounded, per-process. Swap for a shared backend before
4460
4317
  * deploying multiple replicas.
4461
4318
  */
@@ -4469,14 +4326,14 @@ interface SDKServerOpts {
4469
4326
  * registration order.
4470
4327
  */
4471
4328
  healthHandler?: (c: Context<AppEnv>) => Response | Promise<Response>;
4472
- /** Cashu receive mode (internal-review). */
4329
+ /** Cashu receive mode. */
4473
4330
  cashuMode?: CashuMode;
4474
4331
  /**
4475
- * Builder's NUT-11 P2PK lock pubkey (internal-review). Used as the seed pubkey for
4332
+ * Builder's NUT-11 P2PK lock pubkey. Used as the seed pubkey for
4476
4333
  * `seedLockPubkeyState` on first boot, as the admin-auth identity, and as
4477
4334
  * part of the gate for whether `/v1/info` advertises `cashu`. After first
4478
4335
  * boot, the authoritative `[current, ...retired]` state lives in the DVM's
4479
- * Postgres via `dvm_lock_pubkeys`; rotations (internal-review) mutate that store
4336
+ * Postgres via `dvm_lock_pubkeys`; rotations mutate that store
4480
4337
  * directly.
4481
4338
  */
4482
4339
  lockPubkey?: string;
@@ -4485,12 +4342,11 @@ interface SDKServerOpts {
4485
4342
  /**
4486
4343
  * Rotation grace window (seconds) — retired pubkeys remain advertised on
4487
4344
  * `cashu.lock_pubkeys` and accepted by the receive path until they age out.
4488
- * Default 24h (`DEFAULT_LOCK_PUBKEY_GRACE_SECONDS`); operators tune via
4489
- * `BUILDER_LOCK_PUBKEY_GRACE_SECONDS` env (internal-review).
4345
+ * Defaults to 24h.
4490
4346
  */
4491
4347
  lockPubkeyGraceSeconds?: number;
4492
4348
  /**
4493
- * Per-DVM canonical identifier (internal-review). Advertised on `/v1/info` as
4349
+ * Per-DVM canonical identifier. Advertised on `/v1/info` as
4494
4350
  * `cashu.canonical_id` so agents can derive the matching per-DVM refund
4495
4351
  * subkey at `m/1789'/2'/hashed(canonical_dvm_id)'`. Defaults to `dvmId`
4496
4352
  * (the platform's DVM UUID) when unset — keeps `/v1/info` self-consistent
@@ -4500,30 +4356,25 @@ interface SDKServerOpts {
4500
4356
  /** Postgres pool for builder admin state and wallet accumulator persistence. */
4501
4357
  db?: Pool;
4502
4358
  /**
4503
- * General SDK strict-mode flag (internal-review), sourced from `DVMKIT_FAIL_FAST` at
4359
+ * General SDK strict-mode flag, sourced from `DVMKIT_FAIL_FAST` at
4504
4360
  * the host boundary. Reserved for future warning-vs-fatal SDK checks; the
4505
4361
  * revenue-reporter boot check is gated on platform context, not on this
4506
- * flag (internal-review).
4362
+ * flag.
4507
4363
  */
4508
4364
  failFast?: boolean;
4509
- /** Agent-wallet (internal-review): per-DVM identifier — drives the monitor advisory lock + replay key. */
4365
+ /** Agent-wallet: per-DVM identifier — drives the monitor advisory lock + replay key. */
4510
4366
  dvmId?: string;
4511
4367
  /**
4512
- * Runtime mint-health tracker (internal-review). When omitted, the server builds a
4513
- * fresh one whenever `mints?.length > 0`. Sick mints are dropped from
4514
- * `/v1/info`'s advertised list and rejected at receive time. Tests pass an
4515
- * instance with `runOnce`-driven state instead of relying on the timer.
4368
+ * Runtime mint-health tracker. When omitted, the server builds a
4369
+ * fresh one whenever `mints?.length > 0`. Healthy mints are preferred in
4370
+ * `/v1/info`; when none are healthy, transiently sick mints remain advertised.
4371
+ * NUT-incompatible mints are excluded even from that fallback.
4516
4372
  */
4517
4373
  mintHealthTracker?: MintHealthTracker;
4518
- /**
4519
- * Shared fx fetcher used to translate USD descriptor prices and fiat-form
4520
- * `ctx.requestPayment` calls into sats (internal-review). When omitted, the server
4521
- * builds one from `env.DVMKIT_FX_SOURCE` (or the bundled CoinGecko default).
4522
- * Tests pass a deterministic stub.
4523
- */
4374
+ /** Shared upfront/mid-job fiat conversion fetcher. Defaults to `DVMKIT_FX_SOURCE` or CoinGecko. */
4524
4375
  fxFetcher?: FxFetcher;
4525
4376
  /**
4526
- * Platform API token for revenue reporting (internal-review). Read from
4377
+ * Platform API token for revenue reporting. Read from
4527
4378
  * `opts.env.DVMKIT_PLATFORM_TOKEN` when not set explicitly. When both
4528
4379
  * `platformToken` and `platformUrl` are present alongside `db` and `dvmId`,
4529
4380
  * the SDK auto-constructs a `RevenueReporter` and wires it into the
@@ -4531,35 +4382,32 @@ interface SDKServerOpts {
4531
4382
  */
4532
4383
  platformToken?: string;
4533
4384
  /**
4534
- * Platform API URL for revenue reporting (internal-review). Read from
4385
+ * Platform API URL for revenue reporting. Read from
4535
4386
  * `opts.env.DVMKIT_PLATFORM_URL` when not set explicitly.
4536
4387
  */
4537
4388
  platformUrl?: string;
4538
- /**
4539
- * Advanced override: callback fired when a paid job completes (internal-review).
4540
- * When set, bypasses the SDK's automatic `RevenueReporter` wiring — the
4541
- * caller assumes full responsibility for revenue tracking. Intended for
4542
- * tests and advanced integrations only.
4543
- */
4389
+ /** Observes completed jobs with a positive settled draw; failures are logged and swallowed. */
4544
4390
  onPaidJobCompleted?: (event: PaidJobCompletion) => void | Promise<void>;
4545
4391
  paymentMode?: PaymentMode;
4392
+ /** Overrides automatic RevenueReporter wiring; the caller owns revenue delivery. */
4546
4393
  onJobCompleted?: JobManagerOpts["onJobCompleted"];
4547
4394
  /**
4548
4395
  * Advanced override for a declared cost on a terminal job that emitted no
4549
- * revenue report (internal-review). Auto-wired to the reporter's durable
4396
+ * revenue report. Auto-wired to the reporter's durable
4550
4397
  * job-cost path; intended for tests and advanced integrations only.
4551
4398
  */
4552
4399
  onJobCost?: JobManagerOpts["onJobCost"];
4400
+ onJobTerminal?: JobManagerOpts["onJobTerminal"];
4553
4401
  /**
4554
4402
  * Advanced override: callback fired when the stale-job reaper force-fails a
4555
- * *paid* job (internal-review). Auto-wired to the `RevenueReporter`'s paid-job-death
4403
+ * *paid* job. Auto-wired to the `RevenueReporter`'s paid-job-death
4556
4404
  * report alongside `onJobCompleted`; set explicitly only for tests / advanced
4557
4405
  * integrations that own their own reporting.
4558
4406
  */
4559
4407
  onPaidJobDeath?: JobManagerOpts["onPaidJobDeath"];
4560
4408
  /**
4561
4409
  * Advanced override: callback fired when a settled credit draw could not
4562
- * book revenue because its rail was unavailable (internal-review). Auto-wired to
4410
+ * book revenue because its rail was unavailable. Auto-wired to
4563
4411
  * the platform reporter alongside the completion and paid-job-death paths.
4564
4412
  */
4565
4413
  onRevenueSkippedNoRail?: (info: RevenueSkippedNoRailPayload) => void | Promise<void>;
@@ -4568,22 +4416,22 @@ interface SDKServerOpts {
4568
4416
  /** Advanced clear-on-recovery callback for clean job-retention passes. */
4569
4417
  onJobRetentionSweepRecovered?: JobManagerOpts["onJobRetentionSweepRecovered"];
4570
4418
  /**
4571
- * Advanced override: callback fired when a payment funds a credit (internal-review).
4419
+ * Advanced override: callback fired when a payment funds a credit.
4572
4420
  * Auto-wired to the `RevenueReporter`'s deposit report alongside
4573
4421
  * `onJobCompleted`; set explicitly only for tests / advanced integrations
4574
4422
  * that own their own reporting. Fundings are deposits — a liability until
4575
- * drawn — reported separately from the draws that become revenue (spec §10).
4423
+ * drawn — reported separately from the draws that become revenue (the deposit-accounting rule).
4576
4424
  */
4577
4425
  onCreditFunded?: (info: CreditDepositPayload) => void | Promise<void>;
4578
4426
  /**
4579
4427
  * Grace window (ms) a reactivating machine waits for a live original handler
4580
4428
  * to win the single-execution claim before replaying an `awaiting-input` job
4581
- * (internal-review). Defaults to the JobManager's built-in value; exposed as an ops
4429
+ * Defaults to the JobManager's built-in value; exposed as an ops
4582
4430
  * override and a test seam.
4583
4431
  */
4584
4432
  reactivationClaimGraceMs?: JobManagerOpts["reactivationClaimGraceMs"];
4585
4433
  /**
4586
- * Builder identity for `/v1/info#builder` (internal-review). Inline alternative
4434
+ * Builder identity for `/v1/info#builder`. Inline alternative
4587
4435
  * to the `DVMKIT_BUILDER_PUBKEY` / `_ATTESTATION` / `_SIGNATURE` env vars
4588
4436
  * the platform's deploy pipeline injects as Fly secrets. When set,
4589
4437
  * `builder.{pubkey, attestation, signature}` take per-field precedence
@@ -4591,10 +4439,10 @@ interface SDKServerOpts {
4591
4439
  * `/v1/info#builder` block to be emitted.
4592
4440
  */
4593
4441
  builder?: BuilderIdentity;
4594
- /** Owner display identity for `/v1/info#owner` (internal-review). Falls back to env vars. */
4442
+ /** Owner display identity for `/v1/info#owner`. Falls back to env vars. */
4595
4443
  owner?: OwnerDisplay;
4596
4444
  /**
4597
- * Per-DVM receipt-signing secret, 32 bytes hex (internal-review). Resolved at the
4445
+ * Per-DVM receipt-signing secret, 32 bytes hex. Resolved at the
4598
4446
  * host boundary from `DVMKIT_RECEIPT_KEY` — the deploy pipeline provisions
4599
4447
  * it as a Fly secret, derived one-way from the builder identity key and
4600
4448
  * bound into the deploy attestation's `receipt_pubkey`.
@@ -4605,25 +4453,25 @@ interface SDKServerOpts {
4605
4453
  */
4606
4454
  receiptKey?: string;
4607
4455
  /**
4608
- * Credit ledger every payment funds and draws through (internal-review). The host
4456
+ * Credit ledger every payment funds and draws through. The host
4609
4457
  * passes the Postgres `CreditLedger` when a pool exists; standalone /
4610
4458
  * pool-less setups default to a per-server `MemoryCreditLedger` so the
4611
4459
  * fund+draw semantics (and receipts' credit block) hold everywhere.
4612
4460
  */
4613
4461
  creditLedger?: CreditLedgerLike;
4614
4462
  /**
4615
- * Durable x402/mpp processed-payment markers (internal-review). Defaults to the
4463
+ * Durable x402/mpp processed-payment markers. Defaults to the
4616
4464
  * in-memory store; the host passes the Postgres one alongside the ledger.
4617
4465
  */
4618
4466
  processedPayments?: ProcessedPaymentStore;
4619
4467
  /**
4620
- * Lightning credit-funding receive leg (internal-review), when the host resolved a
4468
+ * Lightning credit-funding receive leg, when the host resolved a
4621
4469
  * receive-only NWC connection. Absent ⇒ `lightning` never appears on the
4622
4470
  * funding menu and `POST /v1/credit` refuses the method.
4623
4471
  */
4624
4472
  lightningReceive?: LightningReceive;
4625
4473
  /**
4626
- * Liveness of the platform's Tempo close observer (internal-review). Absent ⇒ this
4474
+ * Liveness of the platform's Tempo close observer. Absent ⇒ this
4627
4475
  * DVM is self-hosted and answers for its own close watching, so nothing is
4628
4476
  * withheld. Present and unhealthy ⇒ `tempo/session` is withheld while
4629
4477
  * `tempo/charge` stays available.
@@ -4632,20 +4480,16 @@ interface SDKServerOpts {
4632
4480
  /** Platform-hosted operator fee-token readiness; absent outside hosted sessions. */
4633
4481
  tempoSettlementReadiness?: TempoSettlementReadiness;
4634
4482
  /**
4635
- * Tuning for the credit-expiry sweep (internal-review). Omitted, the sweep runs on
4483
+ * Tuning for the credit-expiry sweep. Omitted, the sweep runs on
4636
4484
  * its own defaults whenever the ledger supports it; tests pass `intervalMs: 0`
4637
4485
  * and `bootDelayMs: 0` to hold the clock still and drive `runOnce` by hand.
4638
4486
  */
4639
4487
  creditExpirySweep?: CreditExpirySweepOpts;
4640
4488
  }
4641
4489
  /**
4642
- * Per-descriptor server construction — internal to the SDK after host
4643
- * consolidation (internal-review). Public callers use `createDVMHost` instead; this
4644
- * function is what the host invokes per `host.mount(dvm)`.
4645
- *
4646
4490
  * Builds a Hono sub-app for one DVM descriptor, wires payment verification,
4647
4491
  * auto-wires `RevenueReporter` when platform env + db + dvmId are present, and
4648
- * runs the platform-hosted partial-wiring assertion (internal-review) — gated on
4492
+ * runs the platform-hosted partial-wiring assertion — gated on
4649
4493
  * `DVMKIT_PLATFORM_URL` presence, independent of `DVMKIT_FAIL_FAST`.
4650
4494
  */
4651
4495
  declare function createDVMServer<State, InputSchema extends ZodLike | undefined>(descriptor: DVMDescriptor<State, InputSchema>, opts: SDKServerOpts): Promise<{
@@ -4654,13 +4498,13 @@ declare function createDVMServer<State, InputSchema extends ZodLike | undefined>
4654
4498
  shutdown: () => Promise<void>;
4655
4499
  jobManager: JobManager<State, InputSchema>;
4656
4500
  revenueReporterActive: boolean;
4657
- /** The payout reporter (internal-review), for the host to attach its Tempo readers to. */
4501
+ /** The payout reporter, for the host to attach its Tempo readers to. */
4658
4502
  payoutReporter?: PayoutReporter;
4659
4503
  }>;
4660
4504
  /**
4661
4505
  * Hono env for the SDK's DVM app. `unknownRoute` is set by
4662
4506
  * {@link unknownRouteNotFound} so the `dvm.request` span can classify a 404 as
4663
- * scanner-probe noise vs a registered route's own 404 (internal-review).
4507
+ * scanner-probe noise vs a registered route's own 404.
4664
4508
  *
4665
4509
  * Exported as a type only, for route modules split out of this file
4666
4510
  * (`credit-routes.ts`) — a type-only import erases at compile time, so it
@@ -4676,7 +4520,7 @@ interface AppEnv {
4676
4520
  /**
4677
4521
  * `notFound` handler for paths that match no registered route — scanner probes
4678
4522
  * (`GET /robots.txt`, `/.env`, …). Tags the request context so the `dvm.request`
4679
- * span downgrades the 404 to `warn`-level probe noise (internal-review) instead of
4523
+ * span downgrades the 404 to `warn`-level probe noise instead of
4680
4524
  * crowding out real errors in a `--level error` sweep, and returns a
4681
4525
  * machine-parseable JSON 404 (Hono's default is plain text). Registered on both
4682
4526
  * the DVM app (standalone `createDVMServer`) and the host app (mounted path):
@@ -4731,21 +4575,21 @@ interface CreditTerms {
4731
4575
  lightning_min_micro?: number;
4732
4576
  }
4733
4577
  /**
4734
- * The **funding menu** a DVM advertises on `/v1/quote` and in every 402
4735
- * (internal-review, credits spec §4/§6). Snake_case: this is the wire shape.
4578
+ * The **funding menu** a DVM advertises on `/v1/quote` and in every 402;
4579
+ * this is the snake_case wire shape.
4736
4580
  *
4737
4581
  * `min_micro` / `max_micro` / `ttl_ms` are the DVM's sizing terms — `max_micro`
4738
4582
  * binds the **residual balance**, not a funding amount, so a job priced above
4739
4583
  * it still clears as fund-and-immediately-draw. `funding` is the rail list a
4740
4584
  * top-up may arrive on — a {@link FundingMethod}, not a `PaymentMethod`, since
4741
- * `lightning` funds a credit without ever being an attached-proof wire method
4742
- * (internal-review). It degrades per spec §4: a rail whose backing wallet is
4743
- * unreachable drops out and the sale survives on the others.
4585
+ * `lightning` funds a credit without ever being an attached-proof wire method.
4586
+ * A rail whose backing wallet is unreachable drops out and the sale survives
4587
+ * on the others.
4744
4588
  *
4745
4589
  * The `credit_id` / `balance_micro` / `remaining_micro` / `expiry_ms` echo
4746
4590
  * appears only for an authenticated caller who already holds a live credit —
4747
4591
  * so one round trip answers "what does this cost, and what do I have left?"
4748
- * (spec §7).
4592
+ * through the signed credit endpoint.
4749
4593
  */
4750
4594
  interface CreditMenu extends CreditTerms {
4751
4595
  /**
@@ -4753,7 +4597,7 @@ interface CreditMenu extends CreditTerms {
4753
4597
  * available.
4754
4598
  *
4755
4599
  * `withheld` names an instrument this DVM is configured for and is not
4756
- * offering at this instant, with the reason (internal-review). Two audiences read
4600
+ * offering at this instant, with the reason. Two audiences read
4757
4601
  * it. An agent gets to relay *why* `tempo/session` vanished instead of
4758
4602
  * inferring the DVM never had it. And the platform's deploy probe reads
4759
4603
  * capability from `methods ∪ withheld`, so a deploy landing during an
@@ -4764,14 +4608,14 @@ interface CreditMenu extends CreditTerms {
4764
4608
  */
4765
4609
  /**
4766
4610
  * Which x402 flavours a top-up may arrive on, and the chain each rides
4767
- * (internal-review). Present exactly when `funding` lists `x402`. Reusable
4611
+ * Present exactly when `funding` lists `x402`. Reusable
4768
4612
  * `batch-settlement` is admitted by default; one-payment `exact` appears
4769
4613
  * only when the builder explicitly accepts its manual refund obligation.
4770
4614
  */
4771
4615
  /**
4772
4616
  * Smallest funding the `lightning` rail accepts, in 1e-6 units of
4773
4617
  * `currency`. Present only when `funding` lists `lightning`. This is the
4774
- * deployment's sats-physical receive floor (internal-review) rendered into fiat
4618
+ * deployment's sats-physical receive floor rendered into fiat
4775
4619
  * with a ×{@link LIGHTNING_FLOOR_FX_MARGIN} margin absorbing rate drift
4776
4620
  * between menu fetch and funding — issuance enforces the *raw* floor at
4777
4621
  * request-time rates, so funding exactly this figure always clears. Rails
@@ -4798,7 +4642,7 @@ interface BuildCreditMenuArgs {
4798
4642
  /**
4799
4643
  * Currency the menu — and the credit it funds — denominates in: the DVM's
4800
4644
  * declared `DVMConfig.currency`, which every call site reads off the single
4801
- * `DVMServer.creditCurrency()` (internal-review). Deliberately *not* the currency of
4645
+ * `DVMServer.creditCurrency()`. Deliberately *not* the currency of
4802
4646
  * the response this menu rides on: a quote priced elsewhere is refused before
4803
4647
  * it reaches here, so the two agree, and sourcing it from the response is
4804
4648
  * what left `POST /v1/credit` — which has no response to read — funding in
@@ -4819,7 +4663,7 @@ interface BuildCreditMenuArgs {
4819
4663
  reason: string;
4820
4664
  }[];
4821
4665
  /**
4822
- * x402 flavours this DVM can actually accept a top-up on (internal-review) — one
4666
+ * x402 flavours this DVM can actually accept a top-up on — one
4823
4667
  * server read, so what the sub-block advertises is what `/v1/credit` will
4824
4668
  * answer a 402 with.
4825
4669
  */
@@ -4837,7 +4681,7 @@ interface BuildCreditMenuArgs {
4837
4681
  lightningFundingMinSats?: number;
4838
4682
  /**
4839
4683
  * Whether this DVM has at least one accepted Cashu mint configured
4840
- * (internal-review). Without one, no Bitcoin funding rail may be advertised — see
4684
+ * Without one, no Bitcoin funding rail may be advertised — see
4841
4685
  * the filter in {@link buildCreditMenu}.
4842
4686
  *
4843
4687
  * Read off the **configured** mint list, never the health-filtered
@@ -4859,23 +4703,23 @@ interface BuildCreditMenuArgs {
4859
4703
  * advertise credit. **The refusal ladder is the feature**; each rung exists
4860
4704
  * because advertising anyway would misadvertise:
4861
4705
  *
4862
- * 1. **Isolate runtime** (credits spec §3) — checked first and unconditionally,
4863
- * before config is even read. Isolate DVMs have no Postgres of their own;
4864
- * their only DVM-side persistence is the last-write-wins callback KV, which
4865
- * spec §2 condition 2 prohibits for credit state. Until [internal-review] resolves
4866
- * the gate they run implicit N=1 only, and their quote simply never offers
4867
- * credit so nothing is misadvertised.
4706
+ * 1. **Isolate runtime** (the isolate-runtime rule) — checked first and unconditionally,
4707
+ * before config is even read. Isolate DVMs have no Postgres of their own;
4708
+ * their only DVM-side persistence is the last-write-wins callback KV, which
4709
+ * the durable-ledger requirement prohibits for credit state. Until isolate
4710
+ * runtimes have durable credit storage, they run implicit N=1 only and their quote never offers
4711
+ * credit so nothing is misadvertised.
4868
4712
  * 2. **Not opted in** — no `credit` block on `configureDVM`.
4869
4713
  * 3. **No descriptor auth** — a credit belongs to a verified secp256k1 pubkey.
4870
- * Without auth the ledger's funder identity degrades to the requester id or
4871
- * `"anonymous"` (see `resolveLedgerContext`), which would pool every
4872
- * anonymous caller's money into one balance. Advertising a per-caller
4873
- * balance on such a DVM would be a lie at best and a disclosure at worst.
4714
+ * Without auth the ledger's funder identity degrades to the requester id or
4715
+ * `"anonymous"` (see `resolveLedgerContext`), which would pool every
4716
+ * anonymous caller's money into one balance. Advertising a per-caller
4717
+ * balance on such a DVM would be a lie at best and a disclosure at worst.
4874
4718
  * 4. **Non-durable ledger outside devMode** — a `MemoryCreditLedger` is
4875
- * per-process, so a caller funding on machine A and drawing on machine B
4876
- * gets `credit_not_found`. Advertise only what survives the fleet.
4719
+ * per-process, so a caller funding on machine A and drawing on machine B
4720
+ * gets `credit_not_found`. Advertise only what survives the fleet.
4877
4721
  * 5. **Bounds not expressible in `currency`** — an fx outage, or a currency the
4878
- * snapshot doesn't carry. Omit rather than quote a number we can't state.
4722
+ * snapshot doesn't carry. Omit rather than quote a number we can't state.
4879
4723
  *
4880
4724
  * The balance echo is added only when a verified `callerPubkey` holds a live,
4881
4725
  * same-currency credit.
@@ -4892,7 +4736,7 @@ declare function buildCreditMenu(args: BuildCreditMenuArgs): Promise<CreditMenu
4892
4736
  * Live, same-currency credits with something left in them; largest spendable
4893
4737
  * balance wins, newest breaks a tie. That is the credit a caller would in fact
4894
4738
  * draw against next. A failed job's released hold leaves a positive implicit
4895
- * balance, which is real caller money (spec §1, no debit on failure) and is
4739
+ * balance, which is real caller money (the credit lifecycle contract, no debit on failure) and is
4896
4740
  * echoed like any other.
4897
4741
  *
4898
4742
  * **Requires a verified pubkey.** Never call this with a requester id or