xytara 2.5.0 → 2.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. package/.env.example +29 -0
  2. package/BSV_TERANODE_SETUP.md +43 -0
  3. package/README.md +66 -7
  4. package/REAL_PAYMENT_SETUP.md +61 -0
  5. package/RELEASE_NOTES.md +12 -6
  6. package/SERVICE_CONTRACT.md +31 -0
  7. package/START_HERE.md +107 -6
  8. package/TREASURY_DESTINATIONS.example.json +66 -0
  9. package/TREASURY_DESTINATIONS.production.template.json +108 -0
  10. package/adapters/examples/langchain-reference-execution-adapter.js +81 -0
  11. package/adapters/examples/langchain-reference-execution-adapter.manifest.json +79 -0
  12. package/adapters/examples/langgraph-reference-execution-adapter.js +81 -0
  13. package/adapters/examples/langgraph-reference-execution-adapter.manifest.json +79 -0
  14. package/bin/xytara-first-run.js +244 -0
  15. package/bin/xytara.js +30 -5
  16. package/integrations/dispatch.js +7 -2
  17. package/integrations/registry.js +123 -2
  18. package/lib/activity_audit_contract.js +322 -0
  19. package/lib/adapter_depth_contract.js +156 -0
  20. package/lib/bolt_lane_contract.js +55 -0
  21. package/lib/bolt_payment_front.js +172 -0
  22. package/lib/capability_execution_truth.js +269 -0
  23. package/lib/capability_registry.js +39 -2
  24. package/lib/checkout_event_security.js +142 -0
  25. package/lib/command_flow.js +169 -36
  26. package/lib/commerce_artifacts.js +23 -4
  27. package/lib/commerce_checkout.js +134 -4
  28. package/lib/commerce_client.js +20 -0
  29. package/lib/commerce_economics.js +109 -9
  30. package/lib/commerce_runtime.js +38 -2
  31. package/lib/commerce_shell.js +4 -2
  32. package/lib/external_execution_runtime.js +132 -0
  33. package/lib/go_live_operator_pack.js +339 -0
  34. package/lib/http_transport.js +32 -0
  35. package/lib/integration_matrix_contract.js +6 -0
  36. package/lib/l402_lane_contract.js +55 -0
  37. package/lib/l402_payment_front.js +192 -0
  38. package/lib/network_transport.js +110 -0
  39. package/lib/operator_intelligence.js +215 -1
  40. package/lib/payment_config.js +80 -3
  41. package/lib/payment_front_registry.js +53 -0
  42. package/lib/payment_protocol_contract.js +165 -0
  43. package/lib/payment_verification.js +23 -3
  44. package/lib/pricing_optimization_contract.js +556 -0
  45. package/lib/release_history.js +15 -0
  46. package/lib/request_rate_limit.js +144 -0
  47. package/lib/runtime_bridge.js +10 -2
  48. package/lib/runtime_operations_worker.js +282 -0
  49. package/lib/settlement_bsv_live.js +79 -4
  50. package/lib/stripe_mpp_lane_contract.js +3 -0
  51. package/lib/stripe_mpp_payment_front.js +158 -0
  52. package/lib/treasury_destinations_contract.js +543 -0
  53. package/lib/treasury_egress_policy_contract.js +91 -0
  54. package/package.json +14 -21
  55. package/server.js +627 -88
  56. package/OPERATIONS_RUNBOOK.md +0 -66
  57. package/OPERATOR_START_HERE.md +0 -63
  58. package/PROGRAM_COMPLETE_RELEASE.md +0 -63
  59. package/PROGRAM_STATUS.md +0 -57
  60. package/PUBLISH_PLAN.md +0 -14
  61. package/RELEASE_CHECKLIST.md +0 -16
@@ -0,0 +1,142 @@
1
+ "use strict";
2
+
3
+ const crypto = require("crypto");
4
+
5
+ function normalizeString(value) {
6
+ return typeof value === "string" ? value.trim() : "";
7
+ }
8
+
9
+ function parseBoolean(value, fallback) {
10
+ const normalized = normalizeString(value).toLowerCase();
11
+ if (!normalized) return fallback;
12
+ if (["1", "true", "yes", "on"].includes(normalized)) return true;
13
+ if (["0", "false", "no", "off"].includes(normalized)) return false;
14
+ return fallback;
15
+ }
16
+
17
+ function safeEqualHex(left, right) {
18
+ const leftNormalized = normalizeString(left).toLowerCase();
19
+ const rightNormalized = normalizeString(right).toLowerCase();
20
+ if (!leftNormalized || !rightNormalized || leftNormalized.length !== rightNormalized.length) return false;
21
+ try {
22
+ return crypto.timingSafeEqual(Buffer.from(leftNormalized, "hex"), Buffer.from(rightNormalized, "hex"));
23
+ } catch (_error) {
24
+ return false;
25
+ }
26
+ }
27
+
28
+ function loadCheckoutEventSecurityConfig() {
29
+ const secret = normalizeString(process.env.XYTARA_CHECKOUT_WEBHOOK_SECRET || process.env.XYTARA_HOSTED_CHECKOUT_WEBHOOK_SECRET);
30
+ const verificationRequired = parseBoolean(
31
+ process.env.XYTARA_CHECKOUT_WEBHOOK_VERIFICATION_REQUIRED,
32
+ secret.length > 0
33
+ );
34
+ const maxAgeSeconds = Math.max(30, Number(process.env.XYTARA_CHECKOUT_WEBHOOK_MAX_AGE_SECONDS || 300) || 300);
35
+ return {
36
+ secret: secret || null,
37
+ verification_required: verificationRequired,
38
+ max_age_seconds: maxAgeSeconds,
39
+ signature_header: "x-xytara-checkout-signature",
40
+ timestamp_header: "x-xytara-checkout-timestamp",
41
+ signature_mode: "hmac_sha256_timestamped"
42
+ };
43
+ }
44
+
45
+ function buildCheckoutEventSecuritySummary() {
46
+ const config = loadCheckoutEventSecurityConfig();
47
+ const blockers = [];
48
+ if (config.verification_required && !config.secret) blockers.push("checkout_webhook_secret_missing");
49
+ return {
50
+ ok: true,
51
+ category: "machine-commerce-checkout-event-security-summary",
52
+ summary_version: "xytara-checkout-event-security-summary-v1",
53
+ verification_required: config.verification_required,
54
+ secret_configured: Boolean(config.secret),
55
+ max_age_seconds: config.max_age_seconds,
56
+ signature_header: config.signature_header,
57
+ timestamp_header: config.timestamp_header,
58
+ signature_mode: config.signature_mode,
59
+ ready: blockers.length === 0,
60
+ blockers,
61
+ operator_guidance: config.verification_required
62
+ ? "sign checkout event payloads with the configured webhook secret before forwarding them into xytara"
63
+ : "configure XYTARA_CHECKOUT_WEBHOOK_SECRET and keep verification required when hosted checkout is live"
64
+ };
65
+ }
66
+
67
+ function buildCheckoutEventSignature(rawBody, secret, timestamp) {
68
+ return crypto.createHmac("sha256", secret).update(`${timestamp}.${rawBody}`).digest("hex");
69
+ }
70
+
71
+ function verifyCheckoutEventRequest(headers, rawBody) {
72
+ const config = loadCheckoutEventSecurityConfig();
73
+ const headerMap = headers && typeof headers === "object" ? headers : {};
74
+ const signature = normalizeString(headerMap[config.signature_header]);
75
+ const timestamp = normalizeString(headerMap[config.timestamp_header]);
76
+
77
+ if (!config.verification_required && !config.secret) {
78
+ return {
79
+ ok: true,
80
+ verification_mode: "verification_not_required",
81
+ signature_mode: config.signature_mode
82
+ };
83
+ }
84
+
85
+ if (!config.secret) {
86
+ return {
87
+ ok: false,
88
+ reason: "checkout_webhook_secret_missing"
89
+ };
90
+ }
91
+
92
+ if (!signature) {
93
+ return {
94
+ ok: false,
95
+ reason: "checkout_webhook_signature_missing"
96
+ };
97
+ }
98
+
99
+ if (!timestamp) {
100
+ return {
101
+ ok: false,
102
+ reason: "checkout_webhook_timestamp_missing"
103
+ };
104
+ }
105
+
106
+ const timestampMs = Date.parse(timestamp);
107
+ if (!Number.isFinite(timestampMs)) {
108
+ return {
109
+ ok: false,
110
+ reason: "checkout_webhook_timestamp_invalid"
111
+ };
112
+ }
113
+
114
+ const ageSeconds = Math.abs(Date.now() - timestampMs) / 1000;
115
+ if (ageSeconds > config.max_age_seconds) {
116
+ return {
117
+ ok: false,
118
+ reason: "checkout_webhook_timestamp_expired"
119
+ };
120
+ }
121
+
122
+ const expected = buildCheckoutEventSignature(rawBody, config.secret, timestamp);
123
+ if (!safeEqualHex(expected, signature)) {
124
+ return {
125
+ ok: false,
126
+ reason: "checkout_webhook_signature_invalid"
127
+ };
128
+ }
129
+
130
+ return {
131
+ ok: true,
132
+ verification_mode: "timestamped_hmac",
133
+ signature_mode: config.signature_mode
134
+ };
135
+ }
136
+
137
+ module.exports = {
138
+ buildCheckoutEventSecuritySummary,
139
+ buildCheckoutEventSignature,
140
+ loadCheckoutEventSecurityConfig,
141
+ verifyCheckoutEventRequest
142
+ };
@@ -5,10 +5,11 @@ const {
5
5
  createQuote,
6
6
  hydrateQuoteStates
7
7
  } = require("./commerce_runtime");
8
- const { consumeAccountCredits, buildUsageMeterPreview } = require("./commerce_economics");
8
+ const { consumeAccountCredits, buildUsageMeterPreview, previewCreditSpend } = require("./commerce_economics");
9
9
  const { resolveSpendCredential, evaluateAuthorityBindingAction } = require("./account_auth");
10
10
  const { validateIntegrationSelection } = require("../integrations/dispatch");
11
11
  const { markPaymentAccepted, verifyPaymentAcceptance } = require("./payment_verification");
12
+ const { executeExternalTarget, resolveExecutionTarget } = require("./external_execution_runtime");
12
13
 
13
14
  function hasPaymentHeaders(headers, requiredHeaders) {
14
15
  return requiredHeaders.every((headerName) => headers[headerName]);
@@ -22,7 +23,84 @@ function parseBearerToken(headers) {
22
23
  return match ? match[1].trim() : null;
23
24
  }
24
25
 
25
- function executeCommandRequest(state, payload, headers, options) {
26
+ function buildCreditCommitPayload(payload, quote, requiredUnits) {
27
+ return {
28
+ account_id: quote.account_id,
29
+ agent_id: payload.agent_id || null,
30
+ budget_id: payload.budget_id || null,
31
+ pack_id: payload.pack_id || null,
32
+ entitlement_id: payload.entitlement_id || null,
33
+ quote_id: quote.quote_id,
34
+ task_ref: payload.task_ref || null,
35
+ workflow_ref: payload.workflow_ref || null,
36
+ units: requiredUnits,
37
+ reason: "credit_first_execution"
38
+ };
39
+ }
40
+
41
+ function buildCreditRejectionResponse(creditDecision, quote) {
42
+ const failureReason = creditDecision && creditDecision.credit_spend_preview
43
+ ? creditDecision.credit_spend_preview.failure_reason
44
+ : null;
45
+ const reason = failureReason
46
+ || (creditDecision && creditDecision.policy_guard && creditDecision.policy_guard.reason)
47
+ || (creditDecision && creditDecision.entitlement_guard && creditDecision.entitlement_guard.reason)
48
+ || (creditDecision && creditDecision.reason)
49
+ || "credit_spend_not_allowed";
50
+
51
+ if (reason === "insufficient_credits") {
52
+ const preview = creditDecision && creditDecision.credit_spend_preview ? creditDecision.credit_spend_preview : {};
53
+ return {
54
+ status: 402,
55
+ payload: {
56
+ ok: false,
57
+ reason: "insufficient_credits",
58
+ insufficient_credits: {
59
+ account_id: quote.account_id,
60
+ required_units: preview.required_units,
61
+ available_units: preview.available_units,
62
+ recommended_next_surfaces: {
63
+ credits_topup: "/v1/checkout/purchase-intents",
64
+ direct_payment: "/v1/payment-quotes"
65
+ }
66
+ },
67
+ quote
68
+ }
69
+ };
70
+ }
71
+
72
+ return {
73
+ status: 403,
74
+ payload: {
75
+ ok: false,
76
+ reason,
77
+ account_id: quote.account_id,
78
+ policy_guard: creditDecision && creditDecision.policy_guard ? creditDecision.policy_guard : null,
79
+ entitlement_guard: creditDecision && creditDecision.entitlement_guard ? creditDecision.entitlement_guard : null,
80
+ quote
81
+ }
82
+ };
83
+ }
84
+
85
+ async function buildExternalExecutionOptions(payload, quote, authorizationContext) {
86
+ const executionTarget = resolveExecutionTarget(payload, quote);
87
+ if (!executionTarget) return {};
88
+ const execution = await executeExternalTarget(executionTarget, payload, quote, authorizationContext);
89
+ if (!execution || !execution.ok) {
90
+ return {
91
+ error: execution || {
92
+ ok: false,
93
+ status: 502,
94
+ reason: "external_execution_failed"
95
+ }
96
+ };
97
+ }
98
+ return {
99
+ externalExecution: execution
100
+ };
101
+ }
102
+
103
+ async function executeCommandRequest(state, payload, headers, options) {
26
104
  const opts = options || {};
27
105
  const requiredHeaders = Array.isArray(opts.requiredHeaders) && opts.requiredHeaders.length > 0
28
106
  ? opts.requiredHeaders
@@ -72,10 +150,12 @@ function executeCommandRequest(state, payload, headers, options) {
72
150
  }
73
151
  const quote = createQuote(state, payload);
74
152
  if (prefersCredits) {
75
- const meteringPreview = buildUsageMeterPreview(state, {
153
+ const creditPayload = {
76
154
  ...payload,
155
+ account_id: quote.account_id,
77
156
  quoted_units: Number.isFinite(Number(payload.quoted_units)) ? Number(payload.quoted_units) : undefined
78
- });
157
+ };
158
+ const meteringPreview = buildUsageMeterPreview(state, creditPayload);
79
159
  const requiredUnits = meteringPreview.usage_units;
80
160
  if (delegatedSpend.ok && delegatedSpend.binding) {
81
161
  const authorityDecision = evaluateAuthorityBindingAction(delegatedSpend.binding, "delegated_credit_spend", requiredUnits);
@@ -96,42 +176,65 @@ function executeCommandRequest(state, payload, headers, options) {
96
176
  };
97
177
  }
98
178
  }
99
- const creditSpend = consumeAccountCredits(state, {
100
- account_id: quote.account_id,
101
- agent_id: payload.agent_id || null,
102
- budget_id: payload.budget_id || null,
103
- pack_id: payload.pack_id || null,
104
- entitlement_id: payload.entitlement_id || null,
105
- quote_id: quote.quote_id,
106
- task_ref: payload.task_ref || null,
107
- workflow_ref: payload.workflow_ref || null,
108
- units: requiredUnits,
109
- reason: "credit_first_execution"
110
- });
179
+
180
+ const creditDecision = previewCreditSpend(state, creditPayload);
181
+ if (!creditDecision.ok || !creditDecision.credit_spend_preview || creditDecision.credit_spend_preview.executable_now !== true) {
182
+ return buildCreditRejectionResponse(creditDecision, quote);
183
+ }
184
+
185
+ const preCommitAuthorizationContext = delegatedSpend.ok
186
+ ? delegatedSpend.authorization_context
187
+ : {
188
+ ok: true,
189
+ verification_mode: "account_credits",
190
+ wallet_id: quote.account_id,
191
+ age_seconds: 0,
192
+ payment_payload: {
193
+ credit_spend_status: "precommit"
194
+ }
195
+ };
196
+ const externalExecutionOptions = await buildExternalExecutionOptions(payload, quote, preCommitAuthorizationContext);
197
+ if (externalExecutionOptions.error) {
198
+ return {
199
+ status: externalExecutionOptions.error.status || 502,
200
+ payload: {
201
+ ok: false,
202
+ reason: externalExecutionOptions.error.reason || "external_execution_failed",
203
+ details: externalExecutionOptions.error.details || null,
204
+ credit_spend_status: "not_committed",
205
+ credit_spend_preview: creditDecision.credit_spend_preview,
206
+ quote
207
+ }
208
+ };
209
+ }
210
+
211
+ const creditSpend = consumeAccountCredits(state, buildCreditCommitPayload(payload, quote, requiredUnits));
111
212
  if (creditSpend.ok) {
213
+ const paymentVerification = {
214
+ ...(delegatedSpend.ok
215
+ ? delegatedSpend.authorization_context
216
+ : {
217
+ ok: true,
218
+ verification_mode: "account_credits",
219
+ wallet_id: quote.account_id,
220
+ age_seconds: 0,
221
+ payment_payload: {}
222
+ }),
223
+ payment_payload: {
224
+ ...((delegatedSpend.ok && delegatedSpend.authorization_context && delegatedSpend.authorization_context.payment_payload) || {}),
225
+ credit_spend_id: creditSpend.credit_spend.credit_spend_id
226
+ }
227
+ };
112
228
  return {
113
229
  status: 200,
114
230
  payload: createCommandResult(state, {
115
231
  ...payload,
116
232
  payment_preference: "credits_first"
117
233
  }, quote, {
118
- paymentVerification: {
119
- ...(delegatedSpend.ok
120
- ? delegatedSpend.authorization_context
121
- : {
122
- ok: true,
123
- verification_mode: "account_credits",
124
- wallet_id: quote.account_id,
125
- age_seconds: 0,
126
- payment_payload: {}
127
- }),
128
- payment_payload: {
129
- ...((delegatedSpend.ok && delegatedSpend.authorization_context && delegatedSpend.authorization_context.payment_payload) || {}),
130
- credit_spend_id: creditSpend.credit_spend.credit_spend_id
131
- }
132
- },
234
+ paymentVerification,
133
235
  creditSpend: creditSpend.credit_spend,
134
- skipPaymentLedger: true
236
+ skipPaymentLedger: true,
237
+ externalExecution: externalExecutionOptions.externalExecution || null
135
238
  })
136
239
  };
137
240
  }
@@ -142,6 +245,7 @@ function executeCommandRequest(state, payload, headers, options) {
142
245
  ok: false,
143
246
  reason: creditSpend.reason,
144
247
  account_id: quote.account_id,
248
+ provider_execution_completed_but_credit_commit_failed: Boolean(externalExecutionOptions.externalExecution),
145
249
  policy_guard: {
146
250
  agent_id: creditSpend.agent_id || null,
147
251
  budget_id: creditSpend.budget_id || null,
@@ -161,6 +265,7 @@ function executeCommandRequest(state, payload, headers, options) {
161
265
  payload: {
162
266
  ok: false,
163
267
  reason: "insufficient_credits",
268
+ provider_execution_completed_but_credit_commit_failed: Boolean(externalExecutionOptions.externalExecution),
164
269
  insufficient_credits: {
165
270
  account_id: quote.account_id,
166
271
  required_units: creditSpend.required_units,
@@ -206,7 +311,10 @@ function executeCommandRequest(state, payload, headers, options) {
206
311
  };
207
312
  }
208
313
 
209
- const paymentVerification = verifyPaymentAcceptance(state, headers || {}, requiredHeaders, quote);
314
+ const paymentVerification = verifyPaymentAcceptance(state, headers || {}, requiredHeaders, quote, {
315
+ payment_protocol: opts.paymentProtocol || (payload && payload.payment_protocol) || null,
316
+ authorization_scheme: opts.authorizationScheme || null
317
+ });
210
318
  if (!paymentVerification.ok) {
211
319
  return {
212
320
  status: paymentVerification.status || 403,
@@ -219,16 +327,29 @@ function executeCommandRequest(state, payload, headers, options) {
219
327
  }
220
328
 
221
329
  markPaymentAccepted(state, paymentVerification);
330
+ const externalExecutionOptions = await buildExternalExecutionOptions(payload, quote, paymentVerification);
331
+ if (externalExecutionOptions.error) {
332
+ return {
333
+ status: externalExecutionOptions.error.status || 502,
334
+ payload: {
335
+ ok: false,
336
+ reason: externalExecutionOptions.error.reason || "external_execution_failed",
337
+ details: externalExecutionOptions.error.details || null,
338
+ quote
339
+ }
340
+ };
341
+ }
222
342
 
223
343
  return {
224
344
  status: 200,
225
345
  payload: createCommandResult(state, payload, quote, {
226
- paymentVerification
346
+ paymentVerification,
347
+ externalExecution: externalExecutionOptions.externalExecution || null
227
348
  })
228
349
  };
229
350
  }
230
351
 
231
- function executeAuthorizedCommandRequest(state, payload, authorizationContext) {
352
+ async function executeAuthorizedCommandRequest(state, payload, authorizationContext) {
232
353
  const validation = validateIntegrationSelection(payload);
233
354
  if (!validation.ok) {
234
355
  return {
@@ -258,11 +379,23 @@ function executeAuthorizedCommandRequest(state, payload, authorizationContext) {
258
379
  ? authorizationContext.payment_payload
259
380
  : null
260
381
  };
382
+ const externalExecutionOptions = await buildExternalExecutionOptions(payload, quote, paymentVerification);
383
+ if (externalExecutionOptions.error) {
384
+ return {
385
+ status: externalExecutionOptions.error.status || 502,
386
+ payload: {
387
+ ok: false,
388
+ reason: externalExecutionOptions.error.reason || "external_execution_failed",
389
+ details: externalExecutionOptions.error.details || null
390
+ }
391
+ };
392
+ }
261
393
 
262
394
  return {
263
395
  status: 200,
264
396
  payload: createCommandResult(state, payload, quote, {
265
- paymentVerification
397
+ paymentVerification,
398
+ externalExecution: externalExecutionOptions.externalExecution || null
266
399
  })
267
400
  };
268
401
  }
@@ -67,6 +67,12 @@ function createCommandArtifacts(payload, quote, options) {
67
67
  const normalizedBody = payload && payload.body && typeof payload.body === "object" && !Array.isArray(payload.body)
68
68
  ? payload.body
69
69
  : {};
70
+ const externalExecution = opts.externalExecution && typeof opts.externalExecution === "object"
71
+ ? opts.externalExecution
72
+ : null;
73
+ const externalResponse = externalExecution && externalExecution.target_response && typeof externalExecution.target_response === "object"
74
+ ? externalExecution.target_response
75
+ : null;
70
76
  const resultsByTaskId = Object.fromEntries(resultTasks.map((task, index) => [
71
77
  task.task_id,
72
78
  (() => {
@@ -164,7 +170,17 @@ function createCommandArtifacts(payload, quote, options) {
164
170
  if (task.task_ref === "adapter.mcp.invoke") {
165
171
  base.adapter_lane = "mcp";
166
172
  base.tool_name = normalizedBody.tool_name || null;
167
- base.invocation_status = "simulated";
173
+ base.invocation_status = externalExecution ? "provider_completed" : "simulated";
174
+ }
175
+ if (externalExecution) {
176
+ base.execution_provider = externalExecution.provider || null;
177
+ base.execution_target_id = externalExecution.target_id || null;
178
+ if (externalResponse && externalResponse.provider_job_id) base.provider_job_id = externalResponse.provider_job_id;
179
+ if (externalResponse && externalResponse.output_payload) base.output_payload = externalResponse.output_payload;
180
+ if (externalResponse && externalResponse.output_ref) base.output_ref = externalResponse.output_ref;
181
+ base.provider_status = externalResponse && externalResponse.provider_status
182
+ ? externalResponse.provider_status
183
+ : "completed";
168
184
  }
169
185
  return base;
170
186
  })()
@@ -263,7 +279,7 @@ function createCommandArtifacts(payload, quote, options) {
263
279
  quote_id: quote.quote_id,
264
280
  integration_ids: Array.isArray(quote.integration_ids) ? quote.integration_ids : [],
265
281
  protocols: Array.isArray(quote.protocols) ? quote.protocols : [],
266
- output_ref: `output_${transactionId}`,
282
+ output_ref: externalResponse && externalResponse.output_ref ? externalResponse.output_ref : `output_${transactionId}`,
267
283
  callback_url: payload.callback_url || null,
268
284
  capabilities: quote.capabilities,
269
285
  adapters: quote.adapters,
@@ -280,7 +296,10 @@ function createCommandArtifacts(payload, quote, options) {
280
296
  capability_scopes: capabilityScopes,
281
297
  adapters_used: adaptersUsed,
282
298
  integration_ids: Array.isArray(quote.execution_integration_ids) ? quote.execution_integration_ids : [],
283
- results_by_task_id: resultsByTaskId
299
+ results_by_task_id: resultsByTaskId,
300
+ provider: externalExecution ? externalExecution.provider || null : null,
301
+ provider_target_id: externalExecution ? externalExecution.target_id || null : null,
302
+ provider_job_id: externalResponse && externalResponse.provider_job_id ? externalResponse.provider_job_id : null
284
303
  },
285
304
  created_at_iso: startedAt.toISOString(),
286
305
  completed_at_iso: deferredCompletion ? null : completedAt.toISOString(),
@@ -304,7 +323,7 @@ function createCommandArtifacts(payload, quote, options) {
304
323
  ...defaultPath,
305
324
  status: deferredCompletion ? "pending_completion" : "recorded"
306
325
  },
307
- proof_ref: `proof_${receiptId}`,
326
+ proof_ref: externalResponse && externalResponse.proof_ref ? externalResponse.proof_ref : `proof_${receiptId}`,
308
327
  execution_summary: {
309
328
  command: payload.command || "command.execute",
310
329
  task_count: resultTasks.length,
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
 
3
- const { createRefund } = require("./commerce_cases");
4
- const { applyRailCredits } = require("./commerce_economics");
3
+ const { createRefund, createRemediationTicket } = require("./commerce_cases");
4
+ const { applyRailCredits, buildCreditBalanceSummary, reverseRailCredits } = require("./commerce_economics");
5
5
  const { dispatchRuntimeBridgeRequest } = require("./runtime_bridge");
6
6
 
7
7
  function normalizeString(value, fallback) {
@@ -142,6 +142,90 @@ function getHostedCheckoutEvent(state, eventId) {
142
142
  return state.checkoutEvents.get(eventId) || null;
143
143
  }
144
144
 
145
+ function getRuntimeBridgeDispatchByPurchaseIntent(state, purchaseIntentId) {
146
+ return Array.from(state.runtimeBridgeDispatches.values()).find((dispatch) =>
147
+ dispatch && dispatch.purchase_intent_id === purchaseIntentId
148
+ ) || null;
149
+ }
150
+
151
+ function createHostedCheckoutRemediationTicket(state, purchaseIntent, event, refund, reasonCode, note) {
152
+ return createRemediationTicket(state, {
153
+ transaction_id: null,
154
+ receipt_id: null,
155
+ reason_code: reasonCode,
156
+ action_code: "compensate_or_review",
157
+ note,
158
+ actor: { type: "system", role: "hosted_checkout_compensator" },
159
+ context: {
160
+ purchase_intent_id: purchaseIntent.purchase_intent_id,
161
+ refund_id: refund ? refund.refund_id : null,
162
+ provider_reference: event.provider_reference || null,
163
+ payment_status: event.payment_status || null,
164
+ source: "hosted_checkout_compensation"
165
+ }
166
+ });
167
+ }
168
+
169
+ function applyHostedCheckoutCompensation(state, purchaseIntent, event, refund) {
170
+ const balanceBefore = buildCreditBalanceSummary(state, purchaseIntent.account_id);
171
+ const currentAvailableUnits = Number(balanceBefore.available_units || 0);
172
+ const requiredUnits = Number(purchaseIntent.credits_units || 0);
173
+ const runtimeBridgeDispatch = getRuntimeBridgeDispatchByPurchaseIntent(state, purchaseIntent.purchase_intent_id);
174
+ const compensation = {
175
+ compensation_state: "review_required",
176
+ compensation_path: null,
177
+ reversal_credit_event_id: null,
178
+ remediation_ticket_id: null,
179
+ requires_manual_followup: true,
180
+ downstream_execution_detected: Boolean(runtimeBridgeDispatch),
181
+ insufficient_available_units: currentAvailableUnits < requiredUnits
182
+ };
183
+
184
+ if (purchaseIntent.fulfillment && purchaseIntent.fulfillment.credits_issued) {
185
+ const reversalResult = reverseRailCredits(state, {
186
+ account_id: purchaseIntent.account_id,
187
+ purchase_intent_id: purchaseIntent.purchase_intent_id,
188
+ provider_reference: event.provider_reference,
189
+ reason: event.payment_status === "chargeback"
190
+ ? "hosted_checkout_chargeback_compensation"
191
+ : "hosted_checkout_refund_compensation"
192
+ });
193
+ if (reversalResult.ok) {
194
+ compensation.reversal_credit_event_id = reversalResult.reversal.credit_event_id;
195
+ compensation.compensation_path = "credit_reversal";
196
+ compensation.compensation_state = (currentAvailableUnits >= requiredUnits && !runtimeBridgeDispatch)
197
+ ? "compensated"
198
+ : "remediation_required";
199
+ compensation.requires_manual_followup = compensation.compensation_state !== "compensated";
200
+ } else {
201
+ compensation.compensation_path = "credit_reversal_failed";
202
+ compensation.compensation_state = "compensation_failed";
203
+ }
204
+ } else if (purchaseIntent.fulfillment && purchaseIntent.fulfillment.execution_authorized) {
205
+ compensation.compensation_path = "execution_remediation";
206
+ compensation.compensation_state = "remediation_required";
207
+ }
208
+
209
+ if (compensation.compensation_state !== "compensated") {
210
+ const note = compensation.downstream_execution_detected
211
+ ? "Hosted checkout reversal landed after execution dispatch and needs remediation review"
212
+ : compensation.insufficient_available_units
213
+ ? "Hosted checkout reversal landed after funded capacity was partially or fully consumed"
214
+ : "Hosted checkout reversal requires explicit operator review";
215
+ const ticket = createHostedCheckoutRemediationTicket(
216
+ state,
217
+ purchaseIntent,
218
+ event,
219
+ refund,
220
+ event.payment_status === "chargeback" ? "chargeback_compensation_review_required" : "refund_compensation_review_required",
221
+ note
222
+ );
223
+ compensation.remediation_ticket_id = ticket.ticket_id;
224
+ }
225
+
226
+ return compensation;
227
+ }
228
+
145
229
  function listHostedCheckoutRefunds(state, purchaseIntentId) {
146
230
  const refunds = Array.from(state.refunds.values()).filter((refund) => refund && refund.purchase_intent_id);
147
231
  if (!purchaseIntentId) return refunds;
@@ -162,6 +246,9 @@ function buildHostedCheckoutOperatorSummary(state, accountId) {
162
246
  credits_issued_count: purchaseIntents.filter((entry) => entry.fulfillment && entry.fulfillment.credits_issued).length,
163
247
  execution_dispatched_count: bridgeDispatches.length,
164
248
  refund_review_required_count: purchaseIntents.filter((entry) => entry.customer_status === "refund_review_required" || entry.customer_status === "refund_review_requested").length,
249
+ auto_compensated_count: purchaseIntents.filter((entry) => entry && entry.compensation && entry.compensation.compensation_state === "compensated").length,
250
+ compensation_review_required_count: purchaseIntents.filter((entry) => entry && entry.compensation && entry.compensation.compensation_state === "remediation_required").length,
251
+ compensation_failed_count: purchaseIntents.filter((entry) => entry && entry.compensation && entry.compensation.compensation_state === "compensation_failed").length,
165
252
  refund_case_count: refunds.length,
166
253
  refund_status_counts: refunds.reduce((acc, refund) => {
167
254
  const key = refund && refund.status ? refund.status : "unknown";
@@ -202,7 +289,7 @@ function requestHostedCheckoutRefund(state, purchaseIntentId, body) {
202
289
  return refund;
203
290
  }
204
291
 
205
- function normalizeHostedCheckoutEvent(state, body) {
292
+ async function normalizeHostedCheckoutEvent(state, body) {
206
293
  const payload = ensureObject(body);
207
294
  const eventId = normalizeString(payload.event_id, null);
208
295
  if (eventId && state.checkoutEvents.has(eventId)) {
@@ -228,6 +315,7 @@ function normalizeHostedCheckoutEvent(state, body) {
228
315
  ? Number(payload.amount_received_minor)
229
316
  : purchaseIntent.price.amount_minor,
230
317
  currency: normalizeString(payload.currency, purchaseIntent.price.currency),
318
+ security_verification: ensureObject(payload.security_verification),
231
319
  timestamp,
232
320
  applied_status: "recorded",
233
321
  credits_event_id: null,
@@ -263,7 +351,7 @@ function normalizeHostedCheckoutEvent(state, body) {
263
351
  credits_issued: true
264
352
  };
265
353
  } else if (purchaseIntent.purchase_mode === "single_task_execution" || purchaseIntent.entitlement_mode === "execution_authorization") {
266
- const bridgeDispatch = dispatchRuntimeBridgeRequest(state, {
354
+ const bridgeDispatch = await dispatchRuntimeBridgeRequest(state, {
267
355
  request_id: `bridge_${purchaseIntent.purchase_intent_id}`,
268
356
  account_id: purchaseIntent.account_id,
269
357
  capability_id: purchaseIntent.capability_id,
@@ -315,6 +403,48 @@ function normalizeHostedCheckoutEvent(state, body) {
315
403
  }
316
404
  });
317
405
  nextIntent.latest_refund_id = refund.refund_id;
406
+ const compensation = applyHostedCheckoutCompensation(state, purchaseIntent, event, refund);
407
+ event.compensation = compensation;
408
+ nextIntent.compensation = compensation;
409
+ if (compensation.compensation_state === "compensated") {
410
+ refund.status = "completed";
411
+ refund.action_code = "auto_compensated";
412
+ refund.updated_at_iso = nowIso();
413
+ refund.history = [
414
+ ...(Array.isArray(refund.history) ? refund.history : []),
415
+ {
416
+ at_iso: refund.updated_at_iso,
417
+ event: "auto_compensated",
418
+ note: paymentStatus === "chargeback"
419
+ ? "Chargeback compensation applied automatically"
420
+ : "Refund compensation applied automatically",
421
+ reason_code: refund.reason_code,
422
+ action_code: "auto_compensated",
423
+ previous_status: "requested",
424
+ next_status: "completed",
425
+ actor: { type: "system", role: "hosted_checkout_compensator" },
426
+ context: {
427
+ purchase_intent_id: purchaseIntent.purchase_intent_id,
428
+ provider_reference: event.provider_reference,
429
+ reversal_credit_event_id: compensation.reversal_credit_event_id
430
+ }
431
+ }
432
+ ].slice(-20);
433
+ state.refunds.set(refund.refund_id, refund);
434
+ nextIntent.customer_status = paymentStatus === "chargeback" ? "chargeback_compensated" : "refund_compensated";
435
+ event.applied_status = "auto_compensated";
436
+ if (nextIntent.fulfillment) {
437
+ nextIntent.fulfillment = {
438
+ ...nextIntent.fulfillment,
439
+ credits_issued: false
440
+ };
441
+ }
442
+ } else {
443
+ nextIntent.customer_status = paymentStatus === "chargeback" ? "chargeback_review_required" : "refund_review_required";
444
+ event.applied_status = compensation.compensation_state === "compensation_failed"
445
+ ? "compensation_failed"
446
+ : "refund_review_required";
447
+ }
318
448
  }
319
449
 
320
450
  state.checkoutPurchaseIntents.set(purchaseIntentId, nextIntent);