@decionis/mcp 0.2.0 → 0.3.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.
@@ -42279,6 +42279,19 @@ var FinalizationEffectEvidenceSchema = external_exports.union([
42279
42279
  EffectEvidenceSchema,
42280
42280
  ExecutionEffectEvidenceSchema
42281
42281
  ]);
42282
+ var EffectReceiptRecordSchema = external_exports.object({
42283
+ token: external_exports.string().min(1).max(2e4),
42284
+ token_digest: external_exports.string().regex(/^sha256:[0-9a-f]{64}$/),
42285
+ verified: external_exports.boolean(),
42286
+ verification_code: external_exports.string().min(1).max(100),
42287
+ provider_key_id: external_exports.string().min(1).max(200).nullable(),
42288
+ issuer: external_exports.string().min(1).max(500).nullable(),
42289
+ receipt_jti: external_exports.string().min(1).max(200).nullable(),
42290
+ effect_status: external_exports.enum(["EFFECTED", "REFUSED", "INDETERMINATE"]).nullable(),
42291
+ effect_digest: external_exports.string().regex(/^sha256:[0-9a-f]{64}$/).nullable(),
42292
+ effect_reference: external_exports.string().min(1).max(2e3).nullable(),
42293
+ effected_at: external_exports.string().datetime().nullable()
42294
+ }).strict();
42282
42295
  function validateExecutionEffectEvidence(input) {
42283
42296
  if (!input.expected_request_digest) return "EFFECT_REQUEST_BINDING_UNAVAILABLE";
42284
42297
  if (input.effect_evidence.request_digest !== input.expected_request_digest) {
@@ -42302,6 +42315,7 @@ var ExecutionCommitEvidenceSchema = external_exports.object({
42302
42315
  recorded_at: external_exports.string().datetime(),
42303
42316
  downstream_evidence_digest: external_exports.string().regex(/^sha256:[0-9a-f]{64}$/),
42304
42317
  effect_evidence: FinalizationEffectEvidenceSchema.nullable().optional(),
42318
+ effect_receipt: EffectReceiptRecordSchema.nullable().optional(),
42305
42319
  evidence_hash: external_exports.string().regex(/^sha256:[0-9a-f]{64}$/)
42306
42320
  }).strict().superRefine((evidence, context) => {
42307
42321
  const expectedClaimState = evidence.commit_outcome === "COMMITTED" ? "FINALIZED" : evidence.commit_outcome === "FAILED" ? "FAILED" : "INDETERMINATE";
@@ -42673,10 +42687,22 @@ var AuthorityVerificationRequirementsSchema = external_exports.object({
42673
42687
  });
42674
42688
  }
42675
42689
  });
42690
+ var AuthorityApprovalTierSchema = external_exports.object({
42691
+ priority: external_exports.number().int().min(1).max(5),
42692
+ principal_ids: external_exports.array(external_exports.string().min(1).max(200)).min(1).max(10)
42693
+ }).strict();
42676
42694
  var AuthorityResolutionPolicySchema = external_exports.object({
42677
42695
  quorum: external_exports.literal(1),
42678
42696
  delegation: external_exports.enum(["DISALLOWED", "REQUIREMENT_REFRESH"]),
42679
- fallback_role_ids: external_exports.array(external_exports.string().regex(/^[A-Z][A-Z0-9_]{1,63}$/)).max(10).default([])
42697
+ fallback_role_ids: external_exports.array(external_exports.string().regex(/^[A-Z][A-Z0-9_]{1,63}$/)).max(10).default([]),
42698
+ /**
42699
+ * An approval chain. Absent, the requirement is one ceremony by one subject
42700
+ * (`quorum` 1). Present, the policy names who approves in priority tiers and
42701
+ * the requirement is met only by one valid proof from every tier; Decionis
42702
+ * keeps no chain state — the orchestrator (or Presence) runs it and Decionis
42703
+ * verifies each proof against the tier it comes from.
42704
+ */
42705
+ tiers: external_exports.array(AuthorityApprovalTierSchema).min(1).max(5).optional()
42680
42706
  }).strict().superRefine((policy, context) => {
42681
42707
  if (new Set(policy.fallback_role_ids).size !== policy.fallback_role_ids.length) {
42682
42708
  context.addIssue({
@@ -42685,6 +42711,24 @@ var AuthorityResolutionPolicySchema = external_exports.object({
42685
42711
  message: "fallback role ids must be unique"
42686
42712
  });
42687
42713
  }
42714
+ if (policy.tiers) {
42715
+ const priorities = policy.tiers.map((tier) => tier.priority);
42716
+ if (priorities.some((priority, index) => index > 0 && priority <= priorities[index - 1])) {
42717
+ context.addIssue({
42718
+ code: external_exports.ZodIssueCode.custom,
42719
+ path: ["tiers"],
42720
+ message: "tier priorities must be unique and ascending"
42721
+ });
42722
+ }
42723
+ const principals = policy.tiers.flatMap((tier) => tier.principal_ids);
42724
+ if (new Set(principals).size !== principals.length) {
42725
+ context.addIssue({
42726
+ code: external_exports.ZodIssueCode.custom,
42727
+ path: ["tiers"],
42728
+ message: "a principal belongs to one tier only"
42729
+ });
42730
+ }
42731
+ }
42688
42732
  });
42689
42733
  var AuthorityRequirementOriginatorSchema = external_exports.object({
42690
42734
  organization_id: external_exports.string().min(1).max(200),
@@ -42750,6 +42794,13 @@ var AuthorityRequirementSchema = external_exports.object({
42750
42794
  message: "fallback roles must not repeat the primary role"
42751
42795
  });
42752
42796
  }
42797
+ if (requirement.resolution.tiers && requirement.selector.kind !== "ROLE") {
42798
+ context.addIssue({
42799
+ code: external_exports.ZodIssueCode.custom,
42800
+ path: ["resolution", "tiers"],
42801
+ message: "an approval chain names its members' trusted role through a ROLE selector"
42802
+ });
42803
+ }
42753
42804
  if (requirement.orchestration?.mode === "MANAGED" && requirement.selector.kind === "PRINCIPAL" && requirement.selector.role_id === void 0) {
42754
42805
  context.addIssue({
42755
42806
  code: external_exports.ZodIssueCode.custom,
@@ -45891,17 +45942,21 @@ var connectors = [
45891
45942
  // ── Enterprise ────────────────────────────────────────────────────────
45892
45943
  {
45893
45944
  // SAP PartnerEdge Solution Review approved 2026-06-22 (solution id
45894
- // 2004368, docs/marketplace/sap/solution-hub-listing.md). The PartnerEdge
45945
+ // 2004368; listing evidence now lives in decionis/Commerce
45946
+ // docs/marketplace/sap/solution-hub-listing.md). The PartnerEdge
45895
45947
  // solution URL is partner-gated (anonymous fetch 404s — sweep
45896
- // 2026-08-10), so it is deliberately NOT an install channel here; the
45897
- // customer-deployable BTP deployment kit ships next. Dual-gate wording
45898
- // from the owning listing copy.
45948
+ // 2026-08-10), so it is deliberately NOT an install channel here.
45949
+ // The CAP application and the customer-deployable BTP kit are
45950
+ // Commerce-owned (decionis/Commerce apps/sap + commerce-dashboard): the
45951
+ // decionis.com channel URLs below 301 to commerce.decionis.com like every
45952
+ // other Commerce-owned row, and this repo no longer ships the kit
45953
+ // artifacts or pins their version (drift-gated in Commerce, not here).
45954
+ // Dual-gate wording from the owning listing copy.
45899
45955
  slug: "sap",
45900
45956
  name: "Decionis Governed Execution Gate for SAP",
45901
45957
  vendor: "SAP",
45902
45958
  category: "enterprise",
45903
45959
  status: "validated",
45904
- version: "0.1.0",
45905
45960
  summary: "Dual-gate governed execution for SAP S/4HANA, BTP, and CAP-side workflows \u2014 vendor payment release, procurement approval, and finance controls checked before they execute, with a signed Decision Dossier written back to the governed document.",
45906
45961
  capabilities: [
45907
45962
  "dual-gate-execution",
@@ -45918,20 +45973,14 @@ var connectors = [
45918
45973
  installation: [
45919
45974
  {
45920
45975
  // Customer-deployed BTP kit (curated CAP source, mbt build →
45921
- // cf deploy) — shipped in the same change that makes the URL resolve
45922
- // (rule 1.1 by construction).
45976
+ // cf deploy). The kit page, zip, checksum, manifest and SBOM are
45977
+ // served by Commerce; this URL resolves through the reviewed 301 in
45978
+ // CommerceOwnership.mjs (rule 1.1 by redirect, not by local file).
45923
45979
  kind: "hosted_download",
45924
45980
  url: `${SITE}/marketplace/sap/deployment-kit`,
45925
45981
  label: "SAP BTP deployment kit (customer-deployed)"
45926
45982
  }
45927
45983
  ],
45928
- package: {
45929
- artifact: "/marketplace/sap/deployment-kit/decionis-sap-deployment-kit-0.1.0.zip",
45930
- sha256Path: "/marketplace/sap/deployment-kit/decionis-sap-deployment-kit-0.1.0.sha256.txt",
45931
- manifestPath: "/marketplace/sap/deployment-kit/manifest.json",
45932
- sbomPath: "/marketplace/sap/deployment-kit/SBOM.json",
45933
- format: "sap-mta-deployment-kit"
45934
- },
45935
45984
  documentation: `${SITE}/marketplace/sap`,
45936
45985
  verification: {
45937
45986
  validatedBy: "SAP PartnerEdge Solution Review",
@@ -50322,7 +50371,8 @@ var AuthorityPolicyParser = class _AuthorityPolicyParser {
50322
50371
  const verification = _AuthorityPolicyParser.parseVerification(record.verification_requirements);
50323
50372
  const resolution = _AuthorityPolicyParser.parseResolution(record.resolution, selector);
50324
50373
  const expiresInSeconds = asNumber(record.expires_in_seconds);
50325
- if (!reasonCodes || !selector || !verification || !resolution || expiresInSeconds == null || !Number.isInteger(expiresInSeconds) || expiresInSeconds < 60 || expiresInSeconds > 3600) {
50374
+ const maxExpiresInSeconds = resolution?.tiers === void 0 ? _AuthorityPolicyParser.MAX_CEREMONY_SECONDS : _AuthorityPolicyParser.MAX_CHAIN_SECONDS;
50375
+ if (!reasonCodes || !selector || !verification || !resolution || expiresInSeconds == null || !Number.isInteger(expiresInSeconds) || expiresInSeconds < 60 || expiresInSeconds > maxExpiresInSeconds) {
50326
50376
  return null;
50327
50377
  }
50328
50378
  return {
@@ -50333,6 +50383,8 @@ var AuthorityPolicyParser = class _AuthorityPolicyParser {
50333
50383
  expires_in_seconds: expiresInSeconds
50334
50384
  };
50335
50385
  }
50386
+ static MAX_CEREMONY_SECONDS = 3600;
50387
+ static MAX_CHAIN_SECONDS = 7 * 24 * 3600;
50336
50388
  static policyKeys = /* @__PURE__ */ new Set([
50337
50389
  "reason_codes",
50338
50390
  "selector",
@@ -50414,7 +50466,7 @@ var AuthorityPolicyParser = class _AuthorityPolicyParser {
50414
50466
  const record = asRecord3(input);
50415
50467
  if (!_AuthorityPolicyParser.hasOnlyKeys(
50416
50468
  record,
50417
- /* @__PURE__ */ new Set(["quorum", "delegation", "fallback_role_ids"])
50469
+ /* @__PURE__ */ new Set(["quorum", "delegation", "fallback_role_ids", "tiers"])
50418
50470
  ) || record.quorum !== 1 || record.delegation !== "DISALLOWED" && record.delegation !== "REQUIREMENT_REFRESH" || !Array.isArray(record.fallback_role_ids) || record.fallback_role_ids.length > 10) {
50419
50471
  return null;
50420
50472
  }
@@ -50424,12 +50476,46 @@ var AuthorityPolicyParser = class _AuthorityPolicyParser {
50424
50476
  if (fallbackRoles.length !== record.fallback_role_ids.length || new Set(fallbackRoles).size !== fallbackRoles.length || selector?.kind === "ROLE" && fallbackRoles.includes(selector.role_id)) {
50425
50477
  return null;
50426
50478
  }
50479
+ const tiers = _AuthorityPolicyParser.parseTiers(record.tiers);
50480
+ if (record.tiers !== void 0 && tiers === null) return null;
50481
+ if (tiers && selector?.kind !== "ROLE") return null;
50427
50482
  return {
50428
50483
  quorum: 1,
50429
50484
  delegation: record.delegation,
50430
- fallback_role_ids: fallbackRoles
50485
+ fallback_role_ids: fallbackRoles,
50486
+ ...tiers ? { tiers } : {}
50431
50487
  };
50432
50488
  }
50489
+ /** Priority tiers of principals; unique ascending priorities, a principal in one tier only. */
50490
+ static parseTiers(input) {
50491
+ if (input === void 0) return null;
50492
+ if (!Array.isArray(input) || input.length < 1 || input.length > 5) return null;
50493
+ const tiers = [];
50494
+ const seen = /* @__PURE__ */ new Set();
50495
+ for (const value of input) {
50496
+ const tier = asRecord3(value);
50497
+ if (!_AuthorityPolicyParser.hasOnlyKeys(tier, /* @__PURE__ */ new Set(["priority", "principal_ids"]))) {
50498
+ return null;
50499
+ }
50500
+ const priority = asNumber(tier.priority);
50501
+ if (priority == null || !Number.isInteger(priority) || priority < 1 || priority > 5 || tiers.length > 0 && priority <= tiers[tiers.length - 1].priority) {
50502
+ return null;
50503
+ }
50504
+ if (!Array.isArray(tier.principal_ids) || tier.principal_ids.length < 1 || tier.principal_ids.length > 10) {
50505
+ return null;
50506
+ }
50507
+ const principalIds = tier.principal_ids.filter(
50508
+ (id) => typeof id === "string" && id.length >= 1 && id.length <= 200
50509
+ );
50510
+ if (principalIds.length !== tier.principal_ids.length) return null;
50511
+ for (const id of principalIds) {
50512
+ if (seen.has(id)) return null;
50513
+ seen.add(id);
50514
+ }
50515
+ tiers.push({ priority, principal_ids: principalIds });
50516
+ }
50517
+ return tiers;
50518
+ }
50433
50519
  static parseRegions(input) {
50434
50520
  if (input === void 0) return null;
50435
50521
  if (!Array.isArray(input) || input.length < 1 || input.length > 100) return null;
@@ -52765,6 +52851,19 @@ var AgentTaskGatewayRoutes = class {
52765
52851
  var PROTOCOL_SERVICE = "decionis-protocol";
52766
52852
  var PROTOCOL_VERSION = "1.0.0";
52767
52853
 
52854
+ // ../protocol/src/discovery/GlamaClaimRoutes.ts
52855
+ var GlamaClaimRoutes = class {
52856
+ register(app) {
52857
+ app.get(
52858
+ "/.well-known/glama.json",
52859
+ async (_request, reply) => reply.header("cache-control", "public, max-age=300").send({
52860
+ $schema: "https://glama.ai/mcp/schemas/connector.json",
52861
+ claim: "glama_claim_BUHrLznF-9qs1cZEwwb2AN5CkXK7tNjS"
52862
+ })
52863
+ );
52864
+ }
52865
+ };
52866
+
52768
52867
  // ../protocol/src/health/HealthRoutes.ts
52769
52868
  function registerHealthRoutes(app, deps) {
52770
52869
  const { store } = deps;
@@ -53684,6 +53783,27 @@ var policy_bundle_schema_default = {
53684
53783
  maxItems: 10,
53685
53784
  uniqueItems: true,
53686
53785
  items: { type: "string", pattern: "^[A-Z][A-Z0-9_]{1,63}$" }
53786
+ },
53787
+ tiers: {
53788
+ type: "array",
53789
+ minItems: 1,
53790
+ maxItems: 5,
53791
+ description: "An approval chain: priority tiers of principals, asked at once; one valid proof from every tier satisfies the requirement. Requires a ROLE selector naming the members' trusted role.",
53792
+ items: {
53793
+ type: "object",
53794
+ additionalProperties: false,
53795
+ properties: {
53796
+ priority: { type: "integer", minimum: 1, maximum: 5 },
53797
+ principal_ids: {
53798
+ type: "array",
53799
+ minItems: 1,
53800
+ maxItems: 10,
53801
+ uniqueItems: true,
53802
+ items: { type: "string", minLength: 1, maxLength: 200 }
53803
+ }
53804
+ },
53805
+ required: ["priority", "principal_ids"]
53806
+ }
53687
53807
  }
53688
53808
  },
53689
53809
  required: ["quorum", "delegation", "fallback_role_ids"]
@@ -53707,7 +53827,8 @@ var policy_bundle_schema_default = {
53707
53827
  expires_in_seconds: {
53708
53828
  type: "integer",
53709
53829
  minimum: 60,
53710
- maximum: 3600
53830
+ maximum: 604800,
53831
+ description: "How long the requirement lives. At most 3600 for one ceremony; a requirement whose resolution names tiers is an approval chain and may run to a week."
53711
53832
  }
53712
53833
  },
53713
53834
  required: [
@@ -54993,6 +55114,171 @@ var affiliateRewardsVerticalPack = {
54993
55114
  }
54994
55115
  };
54995
55116
 
55117
+ // ../protocol/src/verticals/commerce/CommercePack.ts
55118
+ var commerceVerticalPack = {
55119
+ key: "commerce",
55120
+ display_name: "Commerce Gate",
55121
+ description: "Governance for storefront and marketplace decisions \u2014 price and promotion changes, inventory mutations, order acceptance and release, and refunds \u2014 against the merchant's margin, inventory and refund floors.",
55122
+ workflow_keys: [
55123
+ "commerce",
55124
+ "commerce_order_release",
55125
+ "commerce_refund_approve",
55126
+ "commerce_refund_request",
55127
+ "commerce_price_change",
55128
+ "commerce_promotion_change",
55129
+ "commerce_inventory_mutation",
55130
+ "commerce_order_acceptance"
55131
+ ],
55132
+ default_domain: "COMMERCE",
55133
+ signal_mappings: [
55134
+ { domain: "COMMERCE", metric_name: "net_margin_percent", source_hint: "commerce_connector" },
55135
+ { domain: "COMMERCE", metric_name: "available_inventory", source_hint: "commerce_connector" },
55136
+ { domain: "COMMERCE", metric_name: "refund_amount", source_hint: "commerce_connector" }
55137
+ ],
55138
+ policy_bundle: {
55139
+ version: "commerce-v1",
55140
+ rules: [
55141
+ {
55142
+ rule_id: "reject_refund_above_refundable",
55143
+ name: "Reject refunds above the refundable balance",
55144
+ decision_domain: "COMMERCE",
55145
+ when: {
55146
+ all: [{ field: "signals.refund_exceeds_refundable", operator: "EQ", value: true }]
55147
+ },
55148
+ then: { action: "AUTO_REJECT", severity: "urgent", sla_minutes: 60 },
55149
+ priority: 400,
55150
+ enabled: true,
55151
+ rationale: "A refund that exceeds what the order has left to refund is never sent."
55152
+ },
55153
+ {
55154
+ rule_id: "escalate_order_release",
55155
+ name: "A held order is released only by an approver",
55156
+ decision_domain: "COMMERCE",
55157
+ when: {
55158
+ all: [{ field: "workflow_key", operator: "EQ", value: "commerce_order_release" }]
55159
+ },
55160
+ then: { action: "ESCALATE", severity: "elevated", sla_minutes: 240 },
55161
+ priority: 360,
55162
+ enabled: true,
55163
+ rationale: "Releasing an order the gate held is its own decision and needs an approver to prove who made it."
55164
+ },
55165
+ {
55166
+ rule_id: "escalate_large_refund",
55167
+ name: "Escalate refunds above the unattended limit",
55168
+ decision_domain: "COMMERCE",
55169
+ when: { all: [{ field: "signals.refund_amount", operator: "GT", value: 1e3 }] },
55170
+ then: { action: "ESCALATE", severity: "elevated", sla_minutes: 240 },
55171
+ priority: 350,
55172
+ enabled: true,
55173
+ rationale: "A refund above the unattended limit needs a named approver before it is sent."
55174
+ },
55175
+ {
55176
+ rule_id: "review_repeat_refund",
55177
+ name: "Review a second refund on the same line",
55178
+ decision_domain: "COMMERCE",
55179
+ when: { all: [{ field: "signals.prior_refund_count", operator: "GT", value: 0 }] },
55180
+ then: { action: "REQUIRE_REVIEW", severity: "elevated", sla_minutes: 240 },
55181
+ priority: 340,
55182
+ enabled: true,
55183
+ rationale: "A refund on an order line that was already refunded is the double-refund case."
55184
+ },
55185
+ {
55186
+ rule_id: "review_margin_floor",
55187
+ name: "Protect minimum margin",
55188
+ decision_domain: "COMMERCE",
55189
+ when: { all: [{ field: "signals.net_margin_percent", operator: "LT", value: 12 }] },
55190
+ then: { action: "REQUIRE_REVIEW", severity: "elevated", sla_minutes: 240 },
55191
+ priority: 300,
55192
+ enabled: true,
55193
+ rationale: "Review commerce actions that would take net margin below the merchant floor."
55194
+ },
55195
+ {
55196
+ rule_id: "review_inventory_floor",
55197
+ name: "Protect low inventory",
55198
+ decision_domain: "COMMERCE",
55199
+ when: { all: [{ field: "signals.available_inventory", operator: "LT", value: 10 }] },
55200
+ then: { action: "REQUIRE_REVIEW", severity: "elevated", sla_minutes: 240 },
55201
+ priority: 250,
55202
+ enabled: true,
55203
+ rationale: "Review fulfilment when source-of-truth inventory is below the safety floor."
55204
+ },
55205
+ {
55206
+ rule_id: "review_discount_stacking",
55207
+ name: "Review stacked promotions",
55208
+ decision_domain: "COMMERCE",
55209
+ when: { all: [{ field: "signals.discount_count", operator: "GT", value: 1 }] },
55210
+ then: { action: "REQUIRE_REVIEW", severity: "elevated", sla_minutes: 240 },
55211
+ priority: 200,
55212
+ enabled: true,
55213
+ rationale: "Review carts that combine more discount sources than the merchant allows."
55214
+ },
55215
+ {
55216
+ rule_id: "approve_routine_commerce",
55217
+ name: "Approve routine commerce actions",
55218
+ decision_domain: "COMMERCE",
55219
+ when: { all: [{ field: "decision_type", operator: "EXISTS", value: true }] },
55220
+ then: { action: "AUTO_APPROVE", severity: "routine", sla_minutes: 30 },
55221
+ priority: 10,
55222
+ enabled: true,
55223
+ rationale: "A storefront action proceeds when no floor is breached and nothing is held."
55224
+ }
55225
+ ]
55226
+ },
55227
+ resolver_overrides: {
55228
+ // Whatever engine scored it, a storefront decision is a commerce decision.
55229
+ domain_by_engine: {
55230
+ finance: "COMMERCE",
55231
+ software: "COMMERCE",
55232
+ procure: "COMMERCE",
55233
+ hiring: "COMMERCE"
55234
+ },
55235
+ intent_domain_hints: [
55236
+ {
55237
+ domain: "COMMERCE",
55238
+ keywords: [
55239
+ "commerce",
55240
+ "order",
55241
+ "refund",
55242
+ "price",
55243
+ "promotion",
55244
+ "discount",
55245
+ "inventory",
55246
+ "listing",
55247
+ "cart",
55248
+ "checkout",
55249
+ "merchant",
55250
+ "storefront",
55251
+ "marketplace"
55252
+ ]
55253
+ }
55254
+ ],
55255
+ evidence_required_keywords: ["refund", "release"],
55256
+ missing_evidence_fields: ["purchase_order_id"],
55257
+ base_confidence: 0.6,
55258
+ attachment_confidence_bonus: 0.08,
55259
+ intake_confidence_bonus: 0.02,
55260
+ missing_evidence_penalty: 0.2
55261
+ },
55262
+ execution_templates: {
55263
+ SUCCEEDED: [
55264
+ "Apply the storefront change",
55265
+ "Record the decision dossier",
55266
+ "Notify the merchant"
55267
+ ],
55268
+ NEEDS_EVIDENCE: ["Attach cost or refund evidence", "Confirm the approver", "Re-run evaluation"],
55269
+ FAILED: [
55270
+ "Hold the order or change",
55271
+ "Escalate to the merchant's approver",
55272
+ "Capture the override reason"
55273
+ ]
55274
+ },
55275
+ ui_copy: {
55276
+ recommendation_success: "Proceed with the {domain} action; the merchant's floors hold.",
55277
+ recommendation_needs_evidence: "Attach the cost or refund evidence {domain} needs before approval.",
55278
+ recommendation_failed: "Hold the {domain} action for the merchant's approver."
55279
+ }
55280
+ };
55281
+
54996
55282
  // ../protocol/src/verticals/core/CorePack.ts
54997
55283
  var coreVerticalPack = {
54998
55284
  key: "core",
@@ -57790,6 +58076,7 @@ var DEFAULT_VERTICAL_PACK_KEY = "core";
57790
58076
  var packRegistry = new Map([
57791
58077
  [coreVerticalPack.key, coreVerticalPack],
57792
58078
  [affiliateRewardsVerticalPack.key, affiliateRewardsVerticalPack],
58079
+ [commerceVerticalPack.key, commerceVerticalPack],
57793
58080
  [devopsVerticalPack.key, devopsVerticalPack],
57794
58081
  [financeVerticalPack.key, financeVerticalPack],
57795
58082
  [hospitalityVerticalPack.key, hospitalityVerticalPack],
@@ -60962,6 +61249,7 @@ function appendEvaluateDecisionLedgerEvent(store, input) {
60962
61249
  // ../protocol/src/authority/AuthorityRequirementIssuer.ts
60963
61250
  import { randomBytes, randomUUID as randomUUID9 } from "crypto";
60964
61251
  var AuthorityRequirementIssuer = class _AuthorityRequirementIssuer {
61252
+ static MANAGED_CEREMONY_LIFETIME_MS = 5 * 6e4;
60965
61253
  requirementId;
60966
61254
  nonce;
60967
61255
  constructor(dependencies = {}) {
@@ -60993,10 +61281,12 @@ var AuthorityRequirementIssuer = class _AuthorityRequirementIssuer {
60993
61281
  const intentExpiresAtMs = Date.parse(
60994
61282
  typeof agentSafe.expires_at === "string" ? agentSafe.expires_at : ""
60995
61283
  );
61284
+ const chained = authorityPolicy.resolution.tiers !== void 0;
60996
61285
  const expiresAt = new Date(
60997
61286
  Math.min(
60998
61287
  issuedAtMs + authorityPolicy.expires_in_seconds * 1e3,
60999
- Number.isFinite(intentExpiresAtMs) ? intentExpiresAtMs : Number.POSITIVE_INFINITY
61288
+ Number.isFinite(intentExpiresAtMs) ? intentExpiresAtMs : Number.POSITIVE_INFINITY,
61289
+ managedEscalationId && !chained ? issuedAtMs + _AuthorityRequirementIssuer.MANAGED_CEREMONY_LIFETIME_MS : Number.POSITIVE_INFINITY
61000
61290
  )
61001
61291
  ).toISOString();
61002
61292
  return AuthorityRequirementSchema.parse({
@@ -61020,7 +61310,13 @@ var AuthorityRequirementIssuer = class _AuthorityRequirementIssuer {
61020
61310
  },
61021
61311
  resolution: {
61022
61312
  ...authorityPolicy.resolution,
61023
- fallback_role_ids: [...authorityPolicy.resolution.fallback_role_ids]
61313
+ fallback_role_ids: [...authorityPolicy.resolution.fallback_role_ids],
61314
+ ...authorityPolicy.resolution.tiers ? {
61315
+ tiers: authorityPolicy.resolution.tiers.map((tier) => ({
61316
+ priority: tier.priority,
61317
+ principal_ids: [...tier.principal_ids]
61318
+ }))
61319
+ } : {}
61024
61320
  },
61025
61321
  originator: {
61026
61322
  organization_id: input.request.org_id,
@@ -62973,161 +63269,6 @@ function resolveSalesforceMode(payload) {
62973
63269
  return SalesforceSurface.resolveMode(payload);
62974
63270
  }
62975
63271
 
62976
- // ../protocol/src/verticals/salesforce/SapCostBasis.ts
62977
- var FETCH_TIMEOUT_MS = 2500;
62978
- var DEFAULTS = {
62979
- servicePath: "/sap/opu/odata/sap/API_PRODUCT_SRV",
62980
- entitySet: "A_ProductValuationArea",
62981
- skuProperty: "Product",
62982
- costProperty: "StandardPrice"
62983
- };
62984
- var SapCostBasis = class _SapCostBasis {
62985
- /**
62986
- * Resolve the S/4HANA OData cost destination. With `orgId`, a per-org override in
62987
- * `DECIONIS_SAP_SOR_BY_ORG` wins (multi-tenant); otherwise the global env destination
62988
- * is used. Returns null when neither is configured.
62989
- */
62990
- static resolveConfig(env = process.env, orgId) {
62991
- const o = _SapCostBasis.readPerOrgCostOverride(env, orgId);
62992
- const baseUrl = String(o?.url ?? env.DECIONIS_SAP_SOR_URL ?? "").trim();
62993
- if (!baseUrl) return null;
62994
- return {
62995
- baseUrl: baseUrl.replace(/\/$/, ""),
62996
- token: String(o?.token ?? env.DECIONIS_SAP_SOR_TOKEN ?? "").trim() || null,
62997
- servicePath: String(
62998
- o?.servicePath ?? env.DECIONIS_SAP_SOR_SERVICE_PATH ?? DEFAULTS.servicePath
62999
- ).replace(/\/$/, ""),
63000
- entitySet: String(o?.entitySet ?? env.DECIONIS_SAP_SOR_ENTITY ?? DEFAULTS.entitySet),
63001
- skuProperty: String(
63002
- o?.skuProperty ?? env.DECIONIS_SAP_SOR_SKU_PROPERTY ?? DEFAULTS.skuProperty
63003
- ),
63004
- costProperty: String(
63005
- o?.costProperty ?? env.DECIONIS_SAP_SOR_COST_PROPERTY ?? DEFAULTS.costProperty
63006
- )
63007
- };
63008
- }
63009
- /** The destination is operator-configured, but require TLS and reject internal hosts. */
63010
- static isSafeUrl(rawUrl) {
63011
- let url;
63012
- try {
63013
- url = new URL(rawUrl);
63014
- } catch {
63015
- return false;
63016
- }
63017
- if (url.protocol !== "https:") return false;
63018
- const h = url.hostname.toLowerCase().replace(/^\[|\]$/g, "");
63019
- if (h === "localhost" || h === "127.0.0.1" || h === "::1" || h === "169.254.169.254" || // cloud metadata
63020
- h.endsWith(".local") || h.endsWith(".internal") || h.startsWith("10.") || h.startsWith("192.168.") || /^172\.(1[6-9]|2\d|3[01])\./.test(h)) {
63021
- return false;
63022
- }
63023
- return true;
63024
- }
63025
- static buildCostQueryUrl(config, skus) {
63026
- const filter = skus.map((sku) => `${config.skuProperty} eq ${_SapCostBasis.odataString(sku)}`).join(" or ");
63027
- const params = new URLSearchParams({
63028
- $select: `${config.skuProperty},${config.costProperty}`,
63029
- $filter: filter,
63030
- $format: "json"
63031
- });
63032
- return `${config.baseUrl}${config.servicePath}/${config.entitySet}?${params.toString()}`;
63033
- }
63034
- /**
63035
- * Returns SKU → SAP cost (or null when SAP can't confirm it). Every requested SKU
63036
- * is present in the map. Fail-safe: returns all-null on SSRF rejection, missing
63037
- * transport, non-2xx, or error.
63038
- */
63039
- static async fetchCostBasis(config, skus, options = {}) {
63040
- const result = /* @__PURE__ */ new Map();
63041
- const unique = [...new Set(skus.filter(Boolean))];
63042
- for (const sku of unique) result.set(sku, null);
63043
- if (unique.length === 0) return result;
63044
- if (!_SapCostBasis.isSafeUrl(config.baseUrl)) return result;
63045
- const transport = options.transport ?? globalThis.fetch;
63046
- if (!transport) return result;
63047
- const controller = new AbortController();
63048
- const timer = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);
63049
- try {
63050
- const res = await transport(_SapCostBasis.buildCostQueryUrl(config, unique), {
63051
- method: "GET",
63052
- headers: {
63053
- accept: "application/json",
63054
- ...config.token ? { authorization: `Bearer ${config.token}` } : {}
63055
- },
63056
- signal: controller.signal
63057
- });
63058
- if (!res.ok) return result;
63059
- const rows = _SapCostBasis.extractRows(await res.json());
63060
- for (const row of rows) {
63061
- const sku = row[config.skuProperty];
63062
- if (typeof sku !== "string" || !result.has(sku)) continue;
63063
- const cost = Number(row[config.costProperty]);
63064
- result.set(sku, Number.isFinite(cost) ? cost : null);
63065
- }
63066
- } catch {
63067
- } finally {
63068
- clearTimeout(timer);
63069
- }
63070
- return result;
63071
- }
63072
- /**
63073
- * Override each order line's `cost_basis` with the SAP cost when available; lines
63074
- * SAP can't confirm keep their existing (payload) cost. Pure.
63075
- */
63076
- static applyCostBasis(payload, costMap) {
63077
- const items = Array.isArray(payload.order_items) ? payload.order_items : [];
63078
- return {
63079
- ...payload,
63080
- order_items: items.map((it) => {
63081
- const matnr = String(it.matnr ?? "");
63082
- const sapCost = matnr ? costMap.get(matnr) : null;
63083
- return sapCost != null ? { ...it, cost_basis: sapCost } : it;
63084
- })
63085
- };
63086
- }
63087
- /** True when at least one SKU got an authoritative SAP cost. */
63088
- static hasResolvedCost(costMap) {
63089
- for (const value of costMap.values()) if (value != null) return true;
63090
- return false;
63091
- }
63092
- /** Per-org SAP destination override from `DECIONIS_SAP_SOR_BY_ORG` (JSON keyed by org id). */
63093
- static readPerOrgCostOverride(env, orgId) {
63094
- if (!orgId) return null;
63095
- const raw = env.DECIONIS_SAP_SOR_BY_ORG;
63096
- if (!raw) return null;
63097
- try {
63098
- const map = JSON.parse(raw);
63099
- const entry = map && typeof map === "object" ? map[orgId] : null;
63100
- return entry && typeof entry === "object" ? entry : null;
63101
- } catch {
63102
- return null;
63103
- }
63104
- }
63105
- static odataString(value) {
63106
- return `'${value.replace(/'/g, "''")}'`;
63107
- }
63108
- /** OData v2 (`d.results`) and v4 (`value`) both supported. */
63109
- static extractRows(json) {
63110
- if (!json || typeof json !== "object") return [];
63111
- const v2 = json.d?.results;
63112
- if (Array.isArray(v2)) return v2;
63113
- const v4 = json.value;
63114
- if (Array.isArray(v4)) return v4;
63115
- return [];
63116
- }
63117
- };
63118
- function resolveSapCostConfig(env = process.env, orgId) {
63119
- return SapCostBasis.resolveConfig(env, orgId);
63120
- }
63121
- async function fetchSapCostBasis(config, skus, options = {}) {
63122
- return SapCostBasis.fetchCostBasis(config, skus, options);
63123
- }
63124
- function applySapCostBasis(payload, costMap) {
63125
- return SapCostBasis.applyCostBasis(payload, costMap);
63126
- }
63127
- function hasResolvedCost(costMap) {
63128
- return SapCostBasis.hasResolvedCost(costMap);
63129
- }
63130
-
63131
63272
  // ../protocol/src/surface-verify/SalesforceVerifyRoutes.ts
63132
63273
  function registerSalesforceVerifyRoutes(app, deps) {
63133
63274
  const { store } = deps;
@@ -63170,26 +63311,10 @@ function registerSalesforceVerifyRoutes(app, deps) {
63170
63311
  const candidateOrg = authedOrgId || asString2(ctx.org_id)?.trim() || process.env.DECIONIS_SALESFORCE_ORG_ID?.trim() || SAP_DEFAULT_ORG_ID;
63171
63312
  const orgId = isLikelyUuid(candidateOrg) ? candidateOrg : SAP_DEFAULT_ORG_ID;
63172
63313
  await ensureSalesforcePolicyBundle(orgId);
63173
- let evalPayload = payload;
63174
- let costBasisSource = "payload";
63175
- if (gate === "execution_authority") {
63176
- const costConfig = resolveSapCostConfig(process.env, orgId);
63177
- if (costConfig) {
63178
- try {
63179
- const skus = (payload.order_items ?? []).map((it) => String(it.matnr ?? "").trim()).filter(Boolean);
63180
- const costMap = await fetchSapCostBasis(costConfig, skus);
63181
- if (hasResolvedCost(costMap)) {
63182
- evalPayload = applySapCostBasis(payload, costMap);
63183
- costBasisSource = "sap";
63184
- }
63185
- } catch {
63186
- }
63187
- }
63188
- }
63189
63314
  const evalRes = await injectInternalProtocolRoute(app, {
63190
63315
  method: "POST",
63191
63316
  url: "/v1/protocol/evaluate-decision",
63192
- payload: buildSalesforceEvaluateRequest(evalPayload, gate, orgId)
63317
+ payload: buildSalesforceEvaluateRequest(payload, gate, orgId)
63193
63318
  });
63194
63319
  if (evalRes.statusCode !== 200) {
63195
63320
  return reply.code(502).send({
@@ -63230,11 +63355,19 @@ function registerSalesforceVerifyRoutes(app, deps) {
63230
63355
  ledger_entry_hash: response.ledger_entry_hash ?? null,
63231
63356
  decision_chain: response.decision_chain ?? null,
63232
63357
  idempotent_replay: Boolean(response.idempotent_replay),
63233
- cost_basis_source: costBasisSource,
63358
+ cost_basis_source: "payload",
63234
63359
  federated: true,
63235
63360
  pipeline: true
63236
63361
  });
63237
63362
  };
63363
+ app.post(
63364
+ "/v1/protocol/surfaces/salesforce/state-admission/verify",
63365
+ (req, reply) => handleSalesforceGate("state_admission", req, reply)
63366
+ );
63367
+ app.post(
63368
+ "/v1/protocol/surfaces/salesforce/execution-authority/verify",
63369
+ (req, reply) => handleSalesforceGate("execution_authority", req, reply)
63370
+ );
63238
63371
  app.post(
63239
63372
  "/salesforce/state-admission/verify",
63240
63373
  (req, reply) => handleSalesforceGate("state_admission", req, reply)
@@ -68926,6 +69059,7 @@ function buildProtocolApp(options) {
68926
69059
  const protocolAuthLookup = options?.mcpAuthLookup ?? null;
68927
69060
  registerInternalAccessGuard(app, process.env, protocolAuthLookup);
68928
69061
  registerHealthRoutes(app, { store });
69062
+ new GlamaClaimRoutes().register(app);
68929
69063
  registerFinanceOverrideRoutes(app, { store });
68930
69064
  registerEvaluateDecisionRoutes(app, { store });
68931
69065
  registerWebexRoutes(app, { store });