@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.
@@ -6766,6 +6766,19 @@ var FinalizationEffectEvidenceSchema = external_exports.union([
6766
6766
  EffectEvidenceSchema,
6767
6767
  ExecutionEffectEvidenceSchema
6768
6768
  ]);
6769
+ var EffectReceiptRecordSchema = external_exports.object({
6770
+ token: external_exports.string().min(1).max(2e4),
6771
+ token_digest: external_exports.string().regex(/^sha256:[0-9a-f]{64}$/),
6772
+ verified: external_exports.boolean(),
6773
+ verification_code: external_exports.string().min(1).max(100),
6774
+ provider_key_id: external_exports.string().min(1).max(200).nullable(),
6775
+ issuer: external_exports.string().min(1).max(500).nullable(),
6776
+ receipt_jti: external_exports.string().min(1).max(200).nullable(),
6777
+ effect_status: external_exports.enum(["EFFECTED", "REFUSED", "INDETERMINATE"]).nullable(),
6778
+ effect_digest: external_exports.string().regex(/^sha256:[0-9a-f]{64}$/).nullable(),
6779
+ effect_reference: external_exports.string().min(1).max(2e3).nullable(),
6780
+ effected_at: external_exports.string().datetime().nullable()
6781
+ }).strict();
6769
6782
  function validateExecutionEffectEvidence(input) {
6770
6783
  if (!input.expected_request_digest) return "EFFECT_REQUEST_BINDING_UNAVAILABLE";
6771
6784
  if (input.effect_evidence.request_digest !== input.expected_request_digest) {
@@ -6789,6 +6802,7 @@ var ExecutionCommitEvidenceSchema = external_exports.object({
6789
6802
  recorded_at: external_exports.string().datetime(),
6790
6803
  downstream_evidence_digest: external_exports.string().regex(/^sha256:[0-9a-f]{64}$/),
6791
6804
  effect_evidence: FinalizationEffectEvidenceSchema.nullable().optional(),
6805
+ effect_receipt: EffectReceiptRecordSchema.nullable().optional(),
6792
6806
  evidence_hash: external_exports.string().regex(/^sha256:[0-9a-f]{64}$/)
6793
6807
  }).strict().superRefine((evidence, context) => {
6794
6808
  const expectedClaimState = evidence.commit_outcome === "COMMITTED" ? "FINALIZED" : evidence.commit_outcome === "FAILED" ? "FAILED" : "INDETERMINATE";
@@ -7160,10 +7174,22 @@ var AuthorityVerificationRequirementsSchema = external_exports.object({
7160
7174
  });
7161
7175
  }
7162
7176
  });
7177
+ var AuthorityApprovalTierSchema = external_exports.object({
7178
+ priority: external_exports.number().int().min(1).max(5),
7179
+ principal_ids: external_exports.array(external_exports.string().min(1).max(200)).min(1).max(10)
7180
+ }).strict();
7163
7181
  var AuthorityResolutionPolicySchema = external_exports.object({
7164
7182
  quorum: external_exports.literal(1),
7165
7183
  delegation: external_exports.enum(["DISALLOWED", "REQUIREMENT_REFRESH"]),
7166
- fallback_role_ids: external_exports.array(external_exports.string().regex(/^[A-Z][A-Z0-9_]{1,63}$/)).max(10).default([])
7184
+ fallback_role_ids: external_exports.array(external_exports.string().regex(/^[A-Z][A-Z0-9_]{1,63}$/)).max(10).default([]),
7185
+ /**
7186
+ * An approval chain. Absent, the requirement is one ceremony by one subject
7187
+ * (`quorum` 1). Present, the policy names who approves in priority tiers and
7188
+ * the requirement is met only by one valid proof from every tier; Decionis
7189
+ * keeps no chain state — the orchestrator (or Presence) runs it and Decionis
7190
+ * verifies each proof against the tier it comes from.
7191
+ */
7192
+ tiers: external_exports.array(AuthorityApprovalTierSchema).min(1).max(5).optional()
7167
7193
  }).strict().superRefine((policy, context) => {
7168
7194
  if (new Set(policy.fallback_role_ids).size !== policy.fallback_role_ids.length) {
7169
7195
  context.addIssue({
@@ -7172,6 +7198,24 @@ var AuthorityResolutionPolicySchema = external_exports.object({
7172
7198
  message: "fallback role ids must be unique"
7173
7199
  });
7174
7200
  }
7201
+ if (policy.tiers) {
7202
+ const priorities = policy.tiers.map((tier) => tier.priority);
7203
+ if (priorities.some((priority, index) => index > 0 && priority <= priorities[index - 1])) {
7204
+ context.addIssue({
7205
+ code: external_exports.ZodIssueCode.custom,
7206
+ path: ["tiers"],
7207
+ message: "tier priorities must be unique and ascending"
7208
+ });
7209
+ }
7210
+ const principals = policy.tiers.flatMap((tier) => tier.principal_ids);
7211
+ if (new Set(principals).size !== principals.length) {
7212
+ context.addIssue({
7213
+ code: external_exports.ZodIssueCode.custom,
7214
+ path: ["tiers"],
7215
+ message: "a principal belongs to one tier only"
7216
+ });
7217
+ }
7218
+ }
7175
7219
  });
7176
7220
  var AuthorityRequirementOriginatorSchema = external_exports.object({
7177
7221
  organization_id: external_exports.string().min(1).max(200),
@@ -7237,6 +7281,13 @@ var AuthorityRequirementSchema = external_exports.object({
7237
7281
  message: "fallback roles must not repeat the primary role"
7238
7282
  });
7239
7283
  }
7284
+ if (requirement.resolution.tiers && requirement.selector.kind !== "ROLE") {
7285
+ context.addIssue({
7286
+ code: external_exports.ZodIssueCode.custom,
7287
+ path: ["resolution", "tiers"],
7288
+ message: "an approval chain names its members' trusted role through a ROLE selector"
7289
+ });
7290
+ }
7240
7291
  if (requirement.orchestration?.mode === "MANAGED" && requirement.selector.kind === "PRINCIPAL" && requirement.selector.role_id === void 0) {
7241
7292
  context.addIssue({
7242
7293
  code: external_exports.ZodIssueCode.custom,
@@ -10378,17 +10429,21 @@ var connectors = [
10378
10429
  // ── Enterprise ────────────────────────────────────────────────────────
10379
10430
  {
10380
10431
  // SAP PartnerEdge Solution Review approved 2026-06-22 (solution id
10381
- // 2004368, docs/marketplace/sap/solution-hub-listing.md). The PartnerEdge
10432
+ // 2004368; listing evidence now lives in decionis/Commerce
10433
+ // docs/marketplace/sap/solution-hub-listing.md). The PartnerEdge
10382
10434
  // solution URL is partner-gated (anonymous fetch 404s — sweep
10383
- // 2026-08-10), so it is deliberately NOT an install channel here; the
10384
- // customer-deployable BTP deployment kit ships next. Dual-gate wording
10385
- // from the owning listing copy.
10435
+ // 2026-08-10), so it is deliberately NOT an install channel here.
10436
+ // The CAP application and the customer-deployable BTP kit are
10437
+ // Commerce-owned (decionis/Commerce apps/sap + commerce-dashboard): the
10438
+ // decionis.com channel URLs below 301 to commerce.decionis.com like every
10439
+ // other Commerce-owned row, and this repo no longer ships the kit
10440
+ // artifacts or pins their version (drift-gated in Commerce, not here).
10441
+ // Dual-gate wording from the owning listing copy.
10386
10442
  slug: "sap",
10387
10443
  name: "Decionis Governed Execution Gate for SAP",
10388
10444
  vendor: "SAP",
10389
10445
  category: "enterprise",
10390
10446
  status: "validated",
10391
- version: "0.1.0",
10392
10447
  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.",
10393
10448
  capabilities: [
10394
10449
  "dual-gate-execution",
@@ -10405,20 +10460,14 @@ var connectors = [
10405
10460
  installation: [
10406
10461
  {
10407
10462
  // Customer-deployed BTP kit (curated CAP source, mbt build →
10408
- // cf deploy) — shipped in the same change that makes the URL resolve
10409
- // (rule 1.1 by construction).
10463
+ // cf deploy). The kit page, zip, checksum, manifest and SBOM are
10464
+ // served by Commerce; this URL resolves through the reviewed 301 in
10465
+ // CommerceOwnership.mjs (rule 1.1 by redirect, not by local file).
10410
10466
  kind: "hosted_download",
10411
10467
  url: `${SITE}/marketplace/sap/deployment-kit`,
10412
10468
  label: "SAP BTP deployment kit (customer-deployed)"
10413
10469
  }
10414
10470
  ],
10415
- package: {
10416
- artifact: "/marketplace/sap/deployment-kit/decionis-sap-deployment-kit-0.1.0.zip",
10417
- sha256Path: "/marketplace/sap/deployment-kit/decionis-sap-deployment-kit-0.1.0.sha256.txt",
10418
- manifestPath: "/marketplace/sap/deployment-kit/manifest.json",
10419
- sbomPath: "/marketplace/sap/deployment-kit/SBOM.json",
10420
- format: "sap-mta-deployment-kit"
10421
- },
10422
10471
  documentation: `${SITE}/marketplace/sap`,
10423
10472
  verification: {
10424
10473
  validatedBy: "SAP PartnerEdge Solution Review",
@@ -14809,7 +14858,8 @@ var AuthorityPolicyParser = class _AuthorityPolicyParser {
14809
14858
  const verification = _AuthorityPolicyParser.parseVerification(record.verification_requirements);
14810
14859
  const resolution = _AuthorityPolicyParser.parseResolution(record.resolution, selector);
14811
14860
  const expiresInSeconds = asNumber(record.expires_in_seconds);
14812
- if (!reasonCodes || !selector || !verification || !resolution || expiresInSeconds == null || !Number.isInteger(expiresInSeconds) || expiresInSeconds < 60 || expiresInSeconds > 3600) {
14861
+ const maxExpiresInSeconds = resolution?.tiers === void 0 ? _AuthorityPolicyParser.MAX_CEREMONY_SECONDS : _AuthorityPolicyParser.MAX_CHAIN_SECONDS;
14862
+ if (!reasonCodes || !selector || !verification || !resolution || expiresInSeconds == null || !Number.isInteger(expiresInSeconds) || expiresInSeconds < 60 || expiresInSeconds > maxExpiresInSeconds) {
14813
14863
  return null;
14814
14864
  }
14815
14865
  return {
@@ -14820,6 +14870,8 @@ var AuthorityPolicyParser = class _AuthorityPolicyParser {
14820
14870
  expires_in_seconds: expiresInSeconds
14821
14871
  };
14822
14872
  }
14873
+ static MAX_CEREMONY_SECONDS = 3600;
14874
+ static MAX_CHAIN_SECONDS = 7 * 24 * 3600;
14823
14875
  static policyKeys = /* @__PURE__ */ new Set([
14824
14876
  "reason_codes",
14825
14877
  "selector",
@@ -14901,7 +14953,7 @@ var AuthorityPolicyParser = class _AuthorityPolicyParser {
14901
14953
  const record = asRecord3(input);
14902
14954
  if (!_AuthorityPolicyParser.hasOnlyKeys(
14903
14955
  record,
14904
- /* @__PURE__ */ new Set(["quorum", "delegation", "fallback_role_ids"])
14956
+ /* @__PURE__ */ new Set(["quorum", "delegation", "fallback_role_ids", "tiers"])
14905
14957
  ) || record.quorum !== 1 || record.delegation !== "DISALLOWED" && record.delegation !== "REQUIREMENT_REFRESH" || !Array.isArray(record.fallback_role_ids) || record.fallback_role_ids.length > 10) {
14906
14958
  return null;
14907
14959
  }
@@ -14911,12 +14963,46 @@ var AuthorityPolicyParser = class _AuthorityPolicyParser {
14911
14963
  if (fallbackRoles.length !== record.fallback_role_ids.length || new Set(fallbackRoles).size !== fallbackRoles.length || selector?.kind === "ROLE" && fallbackRoles.includes(selector.role_id)) {
14912
14964
  return null;
14913
14965
  }
14966
+ const tiers = _AuthorityPolicyParser.parseTiers(record.tiers);
14967
+ if (record.tiers !== void 0 && tiers === null) return null;
14968
+ if (tiers && selector?.kind !== "ROLE") return null;
14914
14969
  return {
14915
14970
  quorum: 1,
14916
14971
  delegation: record.delegation,
14917
- fallback_role_ids: fallbackRoles
14972
+ fallback_role_ids: fallbackRoles,
14973
+ ...tiers ? { tiers } : {}
14918
14974
  };
14919
14975
  }
14976
+ /** Priority tiers of principals; unique ascending priorities, a principal in one tier only. */
14977
+ static parseTiers(input) {
14978
+ if (input === void 0) return null;
14979
+ if (!Array.isArray(input) || input.length < 1 || input.length > 5) return null;
14980
+ const tiers = [];
14981
+ const seen = /* @__PURE__ */ new Set();
14982
+ for (const value of input) {
14983
+ const tier = asRecord3(value);
14984
+ if (!_AuthorityPolicyParser.hasOnlyKeys(tier, /* @__PURE__ */ new Set(["priority", "principal_ids"]))) {
14985
+ return null;
14986
+ }
14987
+ const priority = asNumber(tier.priority);
14988
+ if (priority == null || !Number.isInteger(priority) || priority < 1 || priority > 5 || tiers.length > 0 && priority <= tiers[tiers.length - 1].priority) {
14989
+ return null;
14990
+ }
14991
+ if (!Array.isArray(tier.principal_ids) || tier.principal_ids.length < 1 || tier.principal_ids.length > 10) {
14992
+ return null;
14993
+ }
14994
+ const principalIds = tier.principal_ids.filter(
14995
+ (id) => typeof id === "string" && id.length >= 1 && id.length <= 200
14996
+ );
14997
+ if (principalIds.length !== tier.principal_ids.length) return null;
14998
+ for (const id of principalIds) {
14999
+ if (seen.has(id)) return null;
15000
+ seen.add(id);
15001
+ }
15002
+ tiers.push({ priority, principal_ids: principalIds });
15003
+ }
15004
+ return tiers;
15005
+ }
14920
15006
  static parseRegions(input) {
14921
15007
  if (input === void 0) return null;
14922
15008
  if (!Array.isArray(input) || input.length < 1 || input.length > 100) return null;
@@ -17252,6 +17338,19 @@ var AgentTaskGatewayRoutes = class {
17252
17338
  var PROTOCOL_SERVICE = "decionis-protocol";
17253
17339
  var PROTOCOL_VERSION = "1.0.0";
17254
17340
 
17341
+ // ../protocol/src/discovery/GlamaClaimRoutes.ts
17342
+ var GlamaClaimRoutes = class {
17343
+ register(app) {
17344
+ app.get(
17345
+ "/.well-known/glama.json",
17346
+ async (_request, reply) => reply.header("cache-control", "public, max-age=300").send({
17347
+ $schema: "https://glama.ai/mcp/schemas/connector.json",
17348
+ claim: "glama_claim_BUHrLznF-9qs1cZEwwb2AN5CkXK7tNjS"
17349
+ })
17350
+ );
17351
+ }
17352
+ };
17353
+
17255
17354
  // ../protocol/src/health/HealthRoutes.ts
17256
17355
  function registerHealthRoutes(app, deps) {
17257
17356
  const { store } = deps;
@@ -18171,6 +18270,27 @@ var policy_bundle_schema_default = {
18171
18270
  maxItems: 10,
18172
18271
  uniqueItems: true,
18173
18272
  items: { type: "string", pattern: "^[A-Z][A-Z0-9_]{1,63}$" }
18273
+ },
18274
+ tiers: {
18275
+ type: "array",
18276
+ minItems: 1,
18277
+ maxItems: 5,
18278
+ 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.",
18279
+ items: {
18280
+ type: "object",
18281
+ additionalProperties: false,
18282
+ properties: {
18283
+ priority: { type: "integer", minimum: 1, maximum: 5 },
18284
+ principal_ids: {
18285
+ type: "array",
18286
+ minItems: 1,
18287
+ maxItems: 10,
18288
+ uniqueItems: true,
18289
+ items: { type: "string", minLength: 1, maxLength: 200 }
18290
+ }
18291
+ },
18292
+ required: ["priority", "principal_ids"]
18293
+ }
18174
18294
  }
18175
18295
  },
18176
18296
  required: ["quorum", "delegation", "fallback_role_ids"]
@@ -18194,7 +18314,8 @@ var policy_bundle_schema_default = {
18194
18314
  expires_in_seconds: {
18195
18315
  type: "integer",
18196
18316
  minimum: 60,
18197
- maximum: 3600
18317
+ maximum: 604800,
18318
+ 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."
18198
18319
  }
18199
18320
  },
18200
18321
  required: [
@@ -19480,6 +19601,171 @@ var affiliateRewardsVerticalPack = {
19480
19601
  }
19481
19602
  };
19482
19603
 
19604
+ // ../protocol/src/verticals/commerce/CommercePack.ts
19605
+ var commerceVerticalPack = {
19606
+ key: "commerce",
19607
+ display_name: "Commerce Gate",
19608
+ 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.",
19609
+ workflow_keys: [
19610
+ "commerce",
19611
+ "commerce_order_release",
19612
+ "commerce_refund_approve",
19613
+ "commerce_refund_request",
19614
+ "commerce_price_change",
19615
+ "commerce_promotion_change",
19616
+ "commerce_inventory_mutation",
19617
+ "commerce_order_acceptance"
19618
+ ],
19619
+ default_domain: "COMMERCE",
19620
+ signal_mappings: [
19621
+ { domain: "COMMERCE", metric_name: "net_margin_percent", source_hint: "commerce_connector" },
19622
+ { domain: "COMMERCE", metric_name: "available_inventory", source_hint: "commerce_connector" },
19623
+ { domain: "COMMERCE", metric_name: "refund_amount", source_hint: "commerce_connector" }
19624
+ ],
19625
+ policy_bundle: {
19626
+ version: "commerce-v1",
19627
+ rules: [
19628
+ {
19629
+ rule_id: "reject_refund_above_refundable",
19630
+ name: "Reject refunds above the refundable balance",
19631
+ decision_domain: "COMMERCE",
19632
+ when: {
19633
+ all: [{ field: "signals.refund_exceeds_refundable", operator: "EQ", value: true }]
19634
+ },
19635
+ then: { action: "AUTO_REJECT", severity: "urgent", sla_minutes: 60 },
19636
+ priority: 400,
19637
+ enabled: true,
19638
+ rationale: "A refund that exceeds what the order has left to refund is never sent."
19639
+ },
19640
+ {
19641
+ rule_id: "escalate_order_release",
19642
+ name: "A held order is released only by an approver",
19643
+ decision_domain: "COMMERCE",
19644
+ when: {
19645
+ all: [{ field: "workflow_key", operator: "EQ", value: "commerce_order_release" }]
19646
+ },
19647
+ then: { action: "ESCALATE", severity: "elevated", sla_minutes: 240 },
19648
+ priority: 360,
19649
+ enabled: true,
19650
+ rationale: "Releasing an order the gate held is its own decision and needs an approver to prove who made it."
19651
+ },
19652
+ {
19653
+ rule_id: "escalate_large_refund",
19654
+ name: "Escalate refunds above the unattended limit",
19655
+ decision_domain: "COMMERCE",
19656
+ when: { all: [{ field: "signals.refund_amount", operator: "GT", value: 1e3 }] },
19657
+ then: { action: "ESCALATE", severity: "elevated", sla_minutes: 240 },
19658
+ priority: 350,
19659
+ enabled: true,
19660
+ rationale: "A refund above the unattended limit needs a named approver before it is sent."
19661
+ },
19662
+ {
19663
+ rule_id: "review_repeat_refund",
19664
+ name: "Review a second refund on the same line",
19665
+ decision_domain: "COMMERCE",
19666
+ when: { all: [{ field: "signals.prior_refund_count", operator: "GT", value: 0 }] },
19667
+ then: { action: "REQUIRE_REVIEW", severity: "elevated", sla_minutes: 240 },
19668
+ priority: 340,
19669
+ enabled: true,
19670
+ rationale: "A refund on an order line that was already refunded is the double-refund case."
19671
+ },
19672
+ {
19673
+ rule_id: "review_margin_floor",
19674
+ name: "Protect minimum margin",
19675
+ decision_domain: "COMMERCE",
19676
+ when: { all: [{ field: "signals.net_margin_percent", operator: "LT", value: 12 }] },
19677
+ then: { action: "REQUIRE_REVIEW", severity: "elevated", sla_minutes: 240 },
19678
+ priority: 300,
19679
+ enabled: true,
19680
+ rationale: "Review commerce actions that would take net margin below the merchant floor."
19681
+ },
19682
+ {
19683
+ rule_id: "review_inventory_floor",
19684
+ name: "Protect low inventory",
19685
+ decision_domain: "COMMERCE",
19686
+ when: { all: [{ field: "signals.available_inventory", operator: "LT", value: 10 }] },
19687
+ then: { action: "REQUIRE_REVIEW", severity: "elevated", sla_minutes: 240 },
19688
+ priority: 250,
19689
+ enabled: true,
19690
+ rationale: "Review fulfilment when source-of-truth inventory is below the safety floor."
19691
+ },
19692
+ {
19693
+ rule_id: "review_discount_stacking",
19694
+ name: "Review stacked promotions",
19695
+ decision_domain: "COMMERCE",
19696
+ when: { all: [{ field: "signals.discount_count", operator: "GT", value: 1 }] },
19697
+ then: { action: "REQUIRE_REVIEW", severity: "elevated", sla_minutes: 240 },
19698
+ priority: 200,
19699
+ enabled: true,
19700
+ rationale: "Review carts that combine more discount sources than the merchant allows."
19701
+ },
19702
+ {
19703
+ rule_id: "approve_routine_commerce",
19704
+ name: "Approve routine commerce actions",
19705
+ decision_domain: "COMMERCE",
19706
+ when: { all: [{ field: "decision_type", operator: "EXISTS", value: true }] },
19707
+ then: { action: "AUTO_APPROVE", severity: "routine", sla_minutes: 30 },
19708
+ priority: 10,
19709
+ enabled: true,
19710
+ rationale: "A storefront action proceeds when no floor is breached and nothing is held."
19711
+ }
19712
+ ]
19713
+ },
19714
+ resolver_overrides: {
19715
+ // Whatever engine scored it, a storefront decision is a commerce decision.
19716
+ domain_by_engine: {
19717
+ finance: "COMMERCE",
19718
+ software: "COMMERCE",
19719
+ procure: "COMMERCE",
19720
+ hiring: "COMMERCE"
19721
+ },
19722
+ intent_domain_hints: [
19723
+ {
19724
+ domain: "COMMERCE",
19725
+ keywords: [
19726
+ "commerce",
19727
+ "order",
19728
+ "refund",
19729
+ "price",
19730
+ "promotion",
19731
+ "discount",
19732
+ "inventory",
19733
+ "listing",
19734
+ "cart",
19735
+ "checkout",
19736
+ "merchant",
19737
+ "storefront",
19738
+ "marketplace"
19739
+ ]
19740
+ }
19741
+ ],
19742
+ evidence_required_keywords: ["refund", "release"],
19743
+ missing_evidence_fields: ["purchase_order_id"],
19744
+ base_confidence: 0.6,
19745
+ attachment_confidence_bonus: 0.08,
19746
+ intake_confidence_bonus: 0.02,
19747
+ missing_evidence_penalty: 0.2
19748
+ },
19749
+ execution_templates: {
19750
+ SUCCEEDED: [
19751
+ "Apply the storefront change",
19752
+ "Record the decision dossier",
19753
+ "Notify the merchant"
19754
+ ],
19755
+ NEEDS_EVIDENCE: ["Attach cost or refund evidence", "Confirm the approver", "Re-run evaluation"],
19756
+ FAILED: [
19757
+ "Hold the order or change",
19758
+ "Escalate to the merchant's approver",
19759
+ "Capture the override reason"
19760
+ ]
19761
+ },
19762
+ ui_copy: {
19763
+ recommendation_success: "Proceed with the {domain} action; the merchant's floors hold.",
19764
+ recommendation_needs_evidence: "Attach the cost or refund evidence {domain} needs before approval.",
19765
+ recommendation_failed: "Hold the {domain} action for the merchant's approver."
19766
+ }
19767
+ };
19768
+
19483
19769
  // ../protocol/src/verticals/core/CorePack.ts
19484
19770
  var coreVerticalPack = {
19485
19771
  key: "core",
@@ -22277,6 +22563,7 @@ var DEFAULT_VERTICAL_PACK_KEY = "core";
22277
22563
  var packRegistry = new Map([
22278
22564
  [coreVerticalPack.key, coreVerticalPack],
22279
22565
  [affiliateRewardsVerticalPack.key, affiliateRewardsVerticalPack],
22566
+ [commerceVerticalPack.key, commerceVerticalPack],
22280
22567
  [devopsVerticalPack.key, devopsVerticalPack],
22281
22568
  [financeVerticalPack.key, financeVerticalPack],
22282
22569
  [hospitalityVerticalPack.key, hospitalityVerticalPack],
@@ -25449,6 +25736,7 @@ function appendEvaluateDecisionLedgerEvent(store, input) {
25449
25736
  // ../protocol/src/authority/AuthorityRequirementIssuer.ts
25450
25737
  import { randomBytes, randomUUID as randomUUID9 } from "crypto";
25451
25738
  var AuthorityRequirementIssuer = class _AuthorityRequirementIssuer {
25739
+ static MANAGED_CEREMONY_LIFETIME_MS = 5 * 6e4;
25452
25740
  requirementId;
25453
25741
  nonce;
25454
25742
  constructor(dependencies = {}) {
@@ -25480,10 +25768,12 @@ var AuthorityRequirementIssuer = class _AuthorityRequirementIssuer {
25480
25768
  const intentExpiresAtMs = Date.parse(
25481
25769
  typeof agentSafe.expires_at === "string" ? agentSafe.expires_at : ""
25482
25770
  );
25771
+ const chained = authorityPolicy.resolution.tiers !== void 0;
25483
25772
  const expiresAt = new Date(
25484
25773
  Math.min(
25485
25774
  issuedAtMs + authorityPolicy.expires_in_seconds * 1e3,
25486
- Number.isFinite(intentExpiresAtMs) ? intentExpiresAtMs : Number.POSITIVE_INFINITY
25775
+ Number.isFinite(intentExpiresAtMs) ? intentExpiresAtMs : Number.POSITIVE_INFINITY,
25776
+ managedEscalationId && !chained ? issuedAtMs + _AuthorityRequirementIssuer.MANAGED_CEREMONY_LIFETIME_MS : Number.POSITIVE_INFINITY
25487
25777
  )
25488
25778
  ).toISOString();
25489
25779
  return AuthorityRequirementSchema.parse({
@@ -25507,7 +25797,13 @@ var AuthorityRequirementIssuer = class _AuthorityRequirementIssuer {
25507
25797
  },
25508
25798
  resolution: {
25509
25799
  ...authorityPolicy.resolution,
25510
- fallback_role_ids: [...authorityPolicy.resolution.fallback_role_ids]
25800
+ fallback_role_ids: [...authorityPolicy.resolution.fallback_role_ids],
25801
+ ...authorityPolicy.resolution.tiers ? {
25802
+ tiers: authorityPolicy.resolution.tiers.map((tier) => ({
25803
+ priority: tier.priority,
25804
+ principal_ids: [...tier.principal_ids]
25805
+ }))
25806
+ } : {}
25511
25807
  },
25512
25808
  originator: {
25513
25809
  organization_id: input.request.org_id,
@@ -27460,161 +27756,6 @@ function resolveSalesforceMode(payload) {
27460
27756
  return SalesforceSurface.resolveMode(payload);
27461
27757
  }
27462
27758
 
27463
- // ../protocol/src/verticals/salesforce/SapCostBasis.ts
27464
- var FETCH_TIMEOUT_MS = 2500;
27465
- var DEFAULTS = {
27466
- servicePath: "/sap/opu/odata/sap/API_PRODUCT_SRV",
27467
- entitySet: "A_ProductValuationArea",
27468
- skuProperty: "Product",
27469
- costProperty: "StandardPrice"
27470
- };
27471
- var SapCostBasis = class _SapCostBasis {
27472
- /**
27473
- * Resolve the S/4HANA OData cost destination. With `orgId`, a per-org override in
27474
- * `DECIONIS_SAP_SOR_BY_ORG` wins (multi-tenant); otherwise the global env destination
27475
- * is used. Returns null when neither is configured.
27476
- */
27477
- static resolveConfig(env = process.env, orgId) {
27478
- const o = _SapCostBasis.readPerOrgCostOverride(env, orgId);
27479
- const baseUrl = String(o?.url ?? env.DECIONIS_SAP_SOR_URL ?? "").trim();
27480
- if (!baseUrl) return null;
27481
- return {
27482
- baseUrl: baseUrl.replace(/\/$/, ""),
27483
- token: String(o?.token ?? env.DECIONIS_SAP_SOR_TOKEN ?? "").trim() || null,
27484
- servicePath: String(
27485
- o?.servicePath ?? env.DECIONIS_SAP_SOR_SERVICE_PATH ?? DEFAULTS.servicePath
27486
- ).replace(/\/$/, ""),
27487
- entitySet: String(o?.entitySet ?? env.DECIONIS_SAP_SOR_ENTITY ?? DEFAULTS.entitySet),
27488
- skuProperty: String(
27489
- o?.skuProperty ?? env.DECIONIS_SAP_SOR_SKU_PROPERTY ?? DEFAULTS.skuProperty
27490
- ),
27491
- costProperty: String(
27492
- o?.costProperty ?? env.DECIONIS_SAP_SOR_COST_PROPERTY ?? DEFAULTS.costProperty
27493
- )
27494
- };
27495
- }
27496
- /** The destination is operator-configured, but require TLS and reject internal hosts. */
27497
- static isSafeUrl(rawUrl) {
27498
- let url;
27499
- try {
27500
- url = new URL(rawUrl);
27501
- } catch {
27502
- return false;
27503
- }
27504
- if (url.protocol !== "https:") return false;
27505
- const h = url.hostname.toLowerCase().replace(/^\[|\]$/g, "");
27506
- if (h === "localhost" || h === "127.0.0.1" || h === "::1" || h === "169.254.169.254" || // cloud metadata
27507
- h.endsWith(".local") || h.endsWith(".internal") || h.startsWith("10.") || h.startsWith("192.168.") || /^172\.(1[6-9]|2\d|3[01])\./.test(h)) {
27508
- return false;
27509
- }
27510
- return true;
27511
- }
27512
- static buildCostQueryUrl(config, skus) {
27513
- const filter = skus.map((sku) => `${config.skuProperty} eq ${_SapCostBasis.odataString(sku)}`).join(" or ");
27514
- const params = new URLSearchParams({
27515
- $select: `${config.skuProperty},${config.costProperty}`,
27516
- $filter: filter,
27517
- $format: "json"
27518
- });
27519
- return `${config.baseUrl}${config.servicePath}/${config.entitySet}?${params.toString()}`;
27520
- }
27521
- /**
27522
- * Returns SKU → SAP cost (or null when SAP can't confirm it). Every requested SKU
27523
- * is present in the map. Fail-safe: returns all-null on SSRF rejection, missing
27524
- * transport, non-2xx, or error.
27525
- */
27526
- static async fetchCostBasis(config, skus, options = {}) {
27527
- const result = /* @__PURE__ */ new Map();
27528
- const unique = [...new Set(skus.filter(Boolean))];
27529
- for (const sku of unique) result.set(sku, null);
27530
- if (unique.length === 0) return result;
27531
- if (!_SapCostBasis.isSafeUrl(config.baseUrl)) return result;
27532
- const transport = options.transport ?? globalThis.fetch;
27533
- if (!transport) return result;
27534
- const controller = new AbortController();
27535
- const timer = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);
27536
- try {
27537
- const res = await transport(_SapCostBasis.buildCostQueryUrl(config, unique), {
27538
- method: "GET",
27539
- headers: {
27540
- accept: "application/json",
27541
- ...config.token ? { authorization: `Bearer ${config.token}` } : {}
27542
- },
27543
- signal: controller.signal
27544
- });
27545
- if (!res.ok) return result;
27546
- const rows = _SapCostBasis.extractRows(await res.json());
27547
- for (const row of rows) {
27548
- const sku = row[config.skuProperty];
27549
- if (typeof sku !== "string" || !result.has(sku)) continue;
27550
- const cost = Number(row[config.costProperty]);
27551
- result.set(sku, Number.isFinite(cost) ? cost : null);
27552
- }
27553
- } catch {
27554
- } finally {
27555
- clearTimeout(timer);
27556
- }
27557
- return result;
27558
- }
27559
- /**
27560
- * Override each order line's `cost_basis` with the SAP cost when available; lines
27561
- * SAP can't confirm keep their existing (payload) cost. Pure.
27562
- */
27563
- static applyCostBasis(payload, costMap) {
27564
- const items = Array.isArray(payload.order_items) ? payload.order_items : [];
27565
- return {
27566
- ...payload,
27567
- order_items: items.map((it) => {
27568
- const matnr = String(it.matnr ?? "");
27569
- const sapCost = matnr ? costMap.get(matnr) : null;
27570
- return sapCost != null ? { ...it, cost_basis: sapCost } : it;
27571
- })
27572
- };
27573
- }
27574
- /** True when at least one SKU got an authoritative SAP cost. */
27575
- static hasResolvedCost(costMap) {
27576
- for (const value of costMap.values()) if (value != null) return true;
27577
- return false;
27578
- }
27579
- /** Per-org SAP destination override from `DECIONIS_SAP_SOR_BY_ORG` (JSON keyed by org id). */
27580
- static readPerOrgCostOverride(env, orgId) {
27581
- if (!orgId) return null;
27582
- const raw = env.DECIONIS_SAP_SOR_BY_ORG;
27583
- if (!raw) return null;
27584
- try {
27585
- const map = JSON.parse(raw);
27586
- const entry = map && typeof map === "object" ? map[orgId] : null;
27587
- return entry && typeof entry === "object" ? entry : null;
27588
- } catch {
27589
- return null;
27590
- }
27591
- }
27592
- static odataString(value) {
27593
- return `'${value.replace(/'/g, "''")}'`;
27594
- }
27595
- /** OData v2 (`d.results`) and v4 (`value`) both supported. */
27596
- static extractRows(json) {
27597
- if (!json || typeof json !== "object") return [];
27598
- const v2 = json.d?.results;
27599
- if (Array.isArray(v2)) return v2;
27600
- const v4 = json.value;
27601
- if (Array.isArray(v4)) return v4;
27602
- return [];
27603
- }
27604
- };
27605
- function resolveSapCostConfig(env = process.env, orgId) {
27606
- return SapCostBasis.resolveConfig(env, orgId);
27607
- }
27608
- async function fetchSapCostBasis(config, skus, options = {}) {
27609
- return SapCostBasis.fetchCostBasis(config, skus, options);
27610
- }
27611
- function applySapCostBasis(payload, costMap) {
27612
- return SapCostBasis.applyCostBasis(payload, costMap);
27613
- }
27614
- function hasResolvedCost(costMap) {
27615
- return SapCostBasis.hasResolvedCost(costMap);
27616
- }
27617
-
27618
27759
  // ../protocol/src/surface-verify/SalesforceVerifyRoutes.ts
27619
27760
  function registerSalesforceVerifyRoutes(app, deps) {
27620
27761
  const { store } = deps;
@@ -27657,26 +27798,10 @@ function registerSalesforceVerifyRoutes(app, deps) {
27657
27798
  const candidateOrg = authedOrgId || asString2(ctx.org_id)?.trim() || process.env.DECIONIS_SALESFORCE_ORG_ID?.trim() || SAP_DEFAULT_ORG_ID;
27658
27799
  const orgId = isLikelyUuid(candidateOrg) ? candidateOrg : SAP_DEFAULT_ORG_ID;
27659
27800
  await ensureSalesforcePolicyBundle(orgId);
27660
- let evalPayload = payload;
27661
- let costBasisSource = "payload";
27662
- if (gate === "execution_authority") {
27663
- const costConfig = resolveSapCostConfig(process.env, orgId);
27664
- if (costConfig) {
27665
- try {
27666
- const skus = (payload.order_items ?? []).map((it) => String(it.matnr ?? "").trim()).filter(Boolean);
27667
- const costMap = await fetchSapCostBasis(costConfig, skus);
27668
- if (hasResolvedCost(costMap)) {
27669
- evalPayload = applySapCostBasis(payload, costMap);
27670
- costBasisSource = "sap";
27671
- }
27672
- } catch {
27673
- }
27674
- }
27675
- }
27676
27801
  const evalRes = await injectInternalProtocolRoute(app, {
27677
27802
  method: "POST",
27678
27803
  url: "/v1/protocol/evaluate-decision",
27679
- payload: buildSalesforceEvaluateRequest(evalPayload, gate, orgId)
27804
+ payload: buildSalesforceEvaluateRequest(payload, gate, orgId)
27680
27805
  });
27681
27806
  if (evalRes.statusCode !== 200) {
27682
27807
  return reply.code(502).send({
@@ -27717,11 +27842,19 @@ function registerSalesforceVerifyRoutes(app, deps) {
27717
27842
  ledger_entry_hash: response.ledger_entry_hash ?? null,
27718
27843
  decision_chain: response.decision_chain ?? null,
27719
27844
  idempotent_replay: Boolean(response.idempotent_replay),
27720
- cost_basis_source: costBasisSource,
27845
+ cost_basis_source: "payload",
27721
27846
  federated: true,
27722
27847
  pipeline: true
27723
27848
  });
27724
27849
  };
27850
+ app.post(
27851
+ "/v1/protocol/surfaces/salesforce/state-admission/verify",
27852
+ (req, reply) => handleSalesforceGate("state_admission", req, reply)
27853
+ );
27854
+ app.post(
27855
+ "/v1/protocol/surfaces/salesforce/execution-authority/verify",
27856
+ (req, reply) => handleSalesforceGate("execution_authority", req, reply)
27857
+ );
27725
27858
  app.post(
27726
27859
  "/salesforce/state-admission/verify",
27727
27860
  (req, reply) => handleSalesforceGate("state_admission", req, reply)
@@ -33413,6 +33546,7 @@ function buildProtocolApp(options) {
33413
33546
  const protocolAuthLookup = options?.mcpAuthLookup ?? null;
33414
33547
  registerInternalAccessGuard(app, process.env, protocolAuthLookup);
33415
33548
  registerHealthRoutes(app, { store });
33549
+ new GlamaClaimRoutes().register(app);
33416
33550
  registerFinanceOverrideRoutes(app, { store });
33417
33551
  registerEvaluateDecisionRoutes(app, { store });
33418
33552
  registerWebexRoutes(app, { store });
@@ -33929,4 +34063,4 @@ toad-cache/dist/toad-cache.cjs:
33929
34063
  * @version 3.7.0
33930
34064
  *)
33931
34065
  */
33932
- //# sourceMappingURL=chunk-NF5JL6QR.js.map
34066
+ //# sourceMappingURL=chunk-LIVLO4MV.js.map