@spottoai/types-package 1.0.2-dev1138.1 → 1.0.2-dev1138.3

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 (131) hide show
  1. package/dist/azure/financialAnalytics.d.ts +80 -8
  2. package/dist/azure/financialAnalytics.d.ts.map +1 -1
  3. package/dist/azure/financialAnalyticsDelivery.d.ts +72 -3
  4. package/dist/azure/financialAnalyticsDelivery.d.ts.map +1 -1
  5. package/dist/azure/financialAnalyticsDelivery.js +7 -1
  6. package/dist/azure/financialAnalyticsDelivery.js.map +1 -1
  7. package/dist/azure/financialAnalyticsDeliveryValidation.d.ts +9 -1
  8. package/dist/azure/financialAnalyticsDeliveryValidation.d.ts.map +1 -1
  9. package/dist/azure/financialAnalyticsDeliveryValidation.js +190 -10
  10. package/dist/azure/financialAnalyticsDeliveryValidation.js.map +1 -1
  11. package/dist/azure/financialAnalyticsDisplayKernel.d.ts +12 -0
  12. package/dist/azure/financialAnalyticsDisplayKernel.d.ts.map +1 -0
  13. package/dist/azure/financialAnalyticsDisplayKernel.js +144 -0
  14. package/dist/azure/financialAnalyticsDisplayKernel.js.map +1 -0
  15. package/dist/azure/financialAnalyticsValidation.d.ts.map +1 -1
  16. package/dist/azure/financialAnalyticsValidation.js +101 -19
  17. package/dist/azure/financialAnalyticsValidation.js.map +1 -1
  18. package/dist/azure/financialAuthorityView.d.ts +4 -0
  19. package/dist/azure/financialAuthorityView.d.ts.map +1 -1
  20. package/dist/azure/financialAuthorityView.js.map +1 -1
  21. package/dist/azure/financialAuthorityViewValidation.d.ts.map +1 -1
  22. package/dist/azure/financialAuthorityViewValidation.js +39 -0
  23. package/dist/azure/financialAuthorityViewValidation.js.map +1 -1
  24. package/dist/azure/financialChargeComposition.d.ts +81 -0
  25. package/dist/azure/financialChargeComposition.d.ts.map +1 -0
  26. package/dist/azure/financialChargeComposition.js +41 -0
  27. package/dist/azure/financialChargeComposition.js.map +1 -0
  28. package/dist/azure/financialChargeCompositionKernel.d.ts +3 -0
  29. package/dist/azure/financialChargeCompositionKernel.d.ts.map +1 -0
  30. package/dist/azure/financialChargeCompositionKernel.js +49 -0
  31. package/dist/azure/financialChargeCompositionKernel.js.map +1 -0
  32. package/dist/azure/financialChargeCompositionValidation.d.ts +8 -0
  33. package/dist/azure/financialChargeCompositionValidation.d.ts.map +1 -0
  34. package/dist/azure/financialChargeCompositionValidation.js +164 -0
  35. package/dist/azure/financialChargeCompositionValidation.js.map +1 -0
  36. package/dist/azure/financialDataflow.d.ts +45 -2
  37. package/dist/azure/financialDataflow.d.ts.map +1 -1
  38. package/dist/azure/financialDataflow.js.map +1 -1
  39. package/dist/azure/financialDataflowKernel.d.ts +31 -0
  40. package/dist/azure/financialDataflowKernel.d.ts.map +1 -0
  41. package/dist/azure/financialDataflowKernel.js +169 -0
  42. package/dist/azure/financialDataflowKernel.js.map +1 -0
  43. package/dist/azure/financialDataflowValidation.d.ts +5 -2
  44. package/dist/azure/financialDataflowValidation.d.ts.map +1 -1
  45. package/dist/azure/financialDataflowValidation.js +203 -30
  46. package/dist/azure/financialDataflowValidation.js.map +1 -1
  47. package/dist/azure/financialEvidenceAssessmentValidation.d.ts.map +1 -1
  48. package/dist/azure/financialEvidenceAssessmentValidation.js +7 -0
  49. package/dist/azure/financialEvidenceAssessmentValidation.js.map +1 -1
  50. package/dist/azure/financialPolicy.d.ts +19 -3
  51. package/dist/azure/financialPolicy.d.ts.map +1 -1
  52. package/dist/azure/financialPolicy.js.map +1 -1
  53. package/dist/azure/financialPolicyDelivery.d.ts +75 -1
  54. package/dist/azure/financialPolicyDelivery.d.ts.map +1 -1
  55. package/dist/azure/financialPolicyDelivery.js +5 -1
  56. package/dist/azure/financialPolicyDelivery.js.map +1 -1
  57. package/dist/azure/financialPolicyDeliveryValidation.d.ts +16 -2
  58. package/dist/azure/financialPolicyDeliveryValidation.d.ts.map +1 -1
  59. package/dist/azure/financialPolicyDeliveryValidation.js +238 -5
  60. package/dist/azure/financialPolicyDeliveryValidation.js.map +1 -1
  61. package/dist/azure/financialPolicyKernel.d.ts +38 -0
  62. package/dist/azure/financialPolicyKernel.d.ts.map +1 -0
  63. package/dist/azure/financialPolicyKernel.js +232 -0
  64. package/dist/azure/financialPolicyKernel.js.map +1 -0
  65. package/dist/azure/financialPolicyValidation.d.ts +1 -0
  66. package/dist/azure/financialPolicyValidation.d.ts.map +1 -1
  67. package/dist/azure/financialPolicyValidation.js +111 -16
  68. package/dist/azure/financialPolicyValidation.js.map +1 -1
  69. package/dist/azure/financialSavingsAuthority.d.ts +29 -0
  70. package/dist/azure/financialSavingsAuthority.d.ts.map +1 -1
  71. package/dist/azure/financialSavingsAuthority.js +2 -1
  72. package/dist/azure/financialSavingsAuthority.js.map +1 -1
  73. package/dist/azure/financialSavingsAuthorityValidation.d.ts.map +1 -1
  74. package/dist/azure/financialSavingsAuthorityValidation.js +3 -0
  75. package/dist/azure/financialSavingsAuthorityValidation.js.map +1 -1
  76. package/dist/azure/financialSavingsCoordinateValidation.d.ts.map +1 -1
  77. package/dist/azure/financialSavingsCoordinateValidation.js +36 -0
  78. package/dist/azure/financialSavingsCoordinateValidation.js.map +1 -1
  79. package/dist/azure/financialScope.d.ts +6 -0
  80. package/dist/azure/financialScope.d.ts.map +1 -1
  81. package/dist/azure/financialScope.js +6 -0
  82. package/dist/azure/financialScope.js.map +1 -1
  83. package/dist/azure/financialScopeBaseline.d.ts +8 -2
  84. package/dist/azure/financialScopeBaseline.d.ts.map +1 -1
  85. package/dist/azure/financialScopeBaseline.js +14 -1
  86. package/dist/azure/financialScopeBaseline.js.map +1 -1
  87. package/dist/azure/financialScopeBaselineValidation.d.ts.map +1 -1
  88. package/dist/azure/financialScopeBaselineValidation.js +15 -1
  89. package/dist/azure/financialScopeBaselineValidation.js.map +1 -1
  90. package/dist/azure/financialScopeEvidence.d.ts +1 -1
  91. package/dist/azure/financialScopeEvidence.d.ts.map +1 -1
  92. package/dist/azure/metrics.d.ts +2 -2
  93. package/dist/azure/metrics.d.ts.map +1 -1
  94. package/dist/azure/prices.d.ts +16 -3
  95. package/dist/azure/prices.d.ts.map +1 -1
  96. package/dist/azure/recommendations.d.ts +12 -4
  97. package/dist/azure/recommendations.d.ts.map +1 -1
  98. package/dist/azure/reports.d.ts +3 -2
  99. package/dist/azure/reports.d.ts.map +1 -1
  100. package/dist/azure/reports.js.map +1 -1
  101. package/dist/azure/resources.d.ts +12 -0
  102. package/dist/azure/resources.d.ts.map +1 -1
  103. package/dist/azure/subscriptions.d.ts +4 -2
  104. package/dist/azure/subscriptions.d.ts.map +1 -1
  105. package/dist/azure/views.d.ts +21 -5
  106. package/dist/azure/views.d.ts.map +1 -1
  107. package/dist/azure/views.js.map +1 -1
  108. package/dist/esm/azure/financialAnalyticsDelivery.js +5 -0
  109. package/dist/esm/azure/financialAnalyticsDeliveryValidation.js +184 -11
  110. package/dist/esm/azure/financialAnalyticsDisplayKernel.js +139 -0
  111. package/dist/esm/azure/financialAnalyticsValidation.js +101 -19
  112. package/dist/esm/azure/financialAuthorityViewValidation.js +39 -0
  113. package/dist/esm/azure/financialChargeComposition.js +36 -0
  114. package/dist/esm/azure/financialChargeCompositionKernel.js +44 -0
  115. package/dist/esm/azure/financialChargeCompositionValidation.js +155 -0
  116. package/dist/esm/azure/financialDataflowKernel.js +163 -0
  117. package/dist/esm/azure/financialDataflowValidation.js +199 -29
  118. package/dist/esm/azure/financialEvidenceAssessmentValidation.js +7 -0
  119. package/dist/esm/azure/financialPolicyDelivery.js +4 -0
  120. package/dist/esm/azure/financialPolicyDeliveryValidation.js +227 -7
  121. package/dist/esm/azure/financialPolicyKernel.js +225 -0
  122. package/dist/esm/azure/financialPolicyValidation.js +110 -16
  123. package/dist/esm/azure/financialSavingsAuthority.js +1 -0
  124. package/dist/esm/azure/financialSavingsAuthorityValidation.js +3 -0
  125. package/dist/esm/azure/financialSavingsCoordinateValidation.js +36 -0
  126. package/dist/esm/azure/financialScope.js +6 -0
  127. package/dist/esm/azure/financialScopeBaseline.js +12 -0
  128. package/dist/esm/azure/financialScopeBaselineValidation.js +15 -1
  129. package/dist/events/cost.d.ts +4 -0
  130. package/dist/events/cost.d.ts.map +1 -1
  131. package/package.json +3 -2
@@ -2,6 +2,9 @@ import { sha256Utf8 } from '../common/sha256.js';
2
2
  import { formatExactDecimalValue, sumCanonicalDecimals } from '../common/exactDecimal.js';
3
3
  import { toCanonicalEstimateLensV1 } from './costComposition.js';
4
4
  import { isCanonicalExactMoney } from './financialValidationPrimitives.js';
5
+ import { AZURE_BILLED_ALL_CHARGES_POLICY_V1, resolveFinancialChargeInclusionPolicyV1, } from './financialChargeComposition.js';
6
+ import { isFinancialChargeCompositionV1, selectFinancialChargesV1 } from './financialChargeCompositionValidation.js';
7
+ import { isCompleteFinancialBaselinePeriodV2 } from './financialScopeBaseline.js';
5
8
  import { isFinancialScopeBaselineEnvelopeV2 } from './financialScopeBaselineValidation.js';
6
9
  import { FINANCIAL_CURRENT_SPEND_COMPOSITION_CONTRACT_VERSION_V1, FINANCIAL_DATAFLOW_SCHEMA_VERSION_V1, } from './financialDataflow.js';
7
10
  import { isFinancialBaselinePeriodV2 } from './financialScopeBaselineValidation.js';
@@ -141,6 +144,14 @@ export const isFinancialDataflowIdentityV1 = (value) => typeof value === 'string
141
144
  export const isFinancialDataflowHashV1 = (value) => typeof value === 'string' && SHA256_ID.test(value);
142
145
  export const isFinancialDataflowCurrencyV1 = (value) => typeof value === 'string' && CURRENCY.test(value);
143
146
  export const isFinancialDataflowIsoInstantV1 = (value) => typeof value === 'string' && /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{3})?Z$/.test(value) && Number.isFinite(Date.parse(value));
147
+ export const isFinancialDataflowJsonGzipArtifactDescriptorV1 = (value) => isFinancialDataflowRecordV1(value) &&
148
+ hasFinancialDataflowExactFieldsV1(value, ['path', 'sha256', 'byteCount', 'mediaType', 'contentEncoding']) &&
149
+ isFinancialDataflowIdentityV1(value.path) &&
150
+ isFinancialDataflowHashV1(value.sha256) &&
151
+ Number.isSafeInteger(value.byteCount) &&
152
+ Number(value.byteCount) > 0 &&
153
+ value.mediaType === 'application/json' &&
154
+ value.contentEncoding === 'gzip';
144
155
  export const isFinancialDataflowCalendarDateV1 = (value) => {
145
156
  if (typeof value !== 'string' || !/^\d{4}-\d{2}-\d{2}$/.test(value))
146
157
  return false;
@@ -310,9 +321,60 @@ export const isFinancialDataflowScopeV1 = (value) => isFinancialDataflowRecordV1
310
321
  SCOPE_KINDS.has(value.kind) &&
311
322
  isFinancialDataflowIdentityV1(value.scopeId) &&
312
323
  isFinancialDataflowHashV1(value.scopeFingerprint);
324
+ export const isFinancialDataflowPeriodV1 = (value) => isFinancialDataflowRecordV1(value) &&
325
+ hasFinancialDataflowExactFieldsV1(value, ['windowKind', 'requested'], ['providerBillingPeriodId']) &&
326
+ isFinancialBaselinePeriodV2({ ...value, coverage: [], gaps: [] });
327
+ export const isFinancialDataflowScopeSelectorV1 = (value) => {
328
+ if (!isFinancialDataflowRecordV1(value) || typeof value.kind !== 'string' || !SCOPE_KINDS.has(value.kind))
329
+ return false;
330
+ if (value.kind === 'resource') {
331
+ return (hasFinancialDataflowExactFieldsV1(value, ['kind', 'resourceIds']) &&
332
+ isFinancialDataflowSortedUniqueStringsV1(value.resourceIds, FINANCIAL_DATAFLOW_LIMITS_V1.maximumMembers) &&
333
+ value.resourceIds.length === 1);
334
+ }
335
+ if (value.kind === 'resource-group') {
336
+ return (hasFinancialDataflowExactFieldsV1(value, ['kind', 'resourceGroupIds']) &&
337
+ isFinancialDataflowSortedUniqueStringsV1(value.resourceGroupIds, FINANCIAL_DATAFLOW_LIMITS_V1.maximumMembers) &&
338
+ value.resourceGroupIds.length === 1);
339
+ }
340
+ if (value.kind === 'subscription' || value.kind === 'multi-subscription') {
341
+ return (hasFinancialDataflowExactFieldsV1(value, ['kind', 'subscriptionIds']) &&
342
+ isFinancialDataflowSortedUniqueStringsV1(value.subscriptionIds, FINANCIAL_DATAFLOW_LIMITS_V1.maximumProviderAccounts) &&
343
+ value.subscriptionIds.length > 0 &&
344
+ (value.kind !== 'subscription' || value.subscriptionIds.length === 1));
345
+ }
346
+ if (!hasFinancialDataflowExactFieldsV1(value, ['kind', 'tags', 'tagMatch']) ||
347
+ (value.tagMatch !== 'any' && value.tagMatch !== 'all') ||
348
+ !Array.isArray(value.tags) ||
349
+ value.tags.length === 0 ||
350
+ value.tags.length > 256) {
351
+ return false;
352
+ }
353
+ const keys = value.tags.map(tag => {
354
+ if (!isFinancialDataflowRecordV1(tag) ||
355
+ !hasFinancialDataflowExactFieldsV1(tag, ['key', 'value']) ||
356
+ !isFinancialDataflowIdentityV1(tag.key) ||
357
+ !isFinancialDataflowIdentityV1(tag.value)) {
358
+ return undefined;
359
+ }
360
+ return `${tag.key}\u0000${tag.value}`;
361
+ });
362
+ return keys.every((key) => key !== undefined) && keys.every((key, index) => index === 0 || keys[index - 1] < key);
363
+ };
313
364
  export const isFinancialDataflowCoordinateV1 = (value) => {
314
365
  if (!isFinancialDataflowRecordV1(value) ||
315
- !hasFinancialDataflowExactFieldsV1(value, ['companyId', 'provider', 'providerAccountRefs', 'scope', 'periodRole', 'period', 'costBasis', 'estimateLens', 'accountingCurrency'], ['requestedCurrencyCode']) ||
366
+ !hasFinancialDataflowExactFieldsV1(value, [
367
+ 'companyId',
368
+ 'provider',
369
+ 'providerAccountRefs',
370
+ 'scope',
371
+ 'periodRole',
372
+ 'period',
373
+ 'costBasis',
374
+ 'estimateLens',
375
+ 'accountingCurrency',
376
+ 'chargeInclusionPolicyRef',
377
+ ], ['requestedCurrencyCode']) ||
316
378
  !isFinancialDataflowIdentityV1(value.companyId) ||
317
379
  value.provider !== 'azure' ||
318
380
  !isFinancialDataflowSortedUniqueStringsV1(value.providerAccountRefs, FINANCIAL_DATAFLOW_LIMITS_V1.maximumProviderAccounts) ||
@@ -320,13 +382,18 @@ export const isFinancialDataflowCoordinateV1 = (value) => {
320
382
  !isFinancialDataflowScopeV1(value.scope) ||
321
383
  typeof value.periodRole !== 'string' ||
322
384
  !PERIOD_ROLES.has(value.periodRole) ||
323
- !isFinancialBaselinePeriodV2(value.period) ||
385
+ !isFinancialDataflowPeriodV1(value.period) ||
324
386
  typeof value.costBasis !== 'string' ||
325
387
  !COST_BASES.has(value.costBasis) ||
326
388
  typeof value.estimateLens !== 'string' ||
327
389
  !ESTIMATE_LENSES.has(value.estimateLens) ||
328
390
  (value.requestedCurrencyCode !== undefined && !isFinancialDataflowCurrencyV1(value.requestedCurrencyCode)) ||
329
- !isFinancialDataflowRecordV1(value.accountingCurrency)) {
391
+ !isFinancialDataflowRecordV1(value.accountingCurrency) ||
392
+ !isFinancialDataflowRecordV1(value.chargeInclusionPolicyRef) ||
393
+ !hasFinancialDataflowExactFieldsV1(value.chargeInclusionPolicyRef, ['policyId', 'policyDigest']) ||
394
+ !isFinancialDataflowIdentityV1(value.chargeInclusionPolicyRef.policyId) ||
395
+ !isFinancialDataflowHashV1(value.chargeInclusionPolicyRef.policyDigest) ||
396
+ resolveFinancialChargeInclusionPolicyV1(value.chargeInclusionPolicyRef) === undefined) {
330
397
  return false;
331
398
  }
332
399
  if (value.accountingCurrency.status === 'resolved') {
@@ -354,7 +421,9 @@ const isMember = (value) => {
354
421
  if (!isFinancialDataflowRecordV1(value) || !isFinancialDataflowIdentityV1(value.memberScopeId))
355
422
  return false;
356
423
  if (value.status === 'included') {
357
- return hasFinancialDataflowExactFieldsV1(value, ['memberScopeId', 'baselineId', 'status']) && isFinancialDataflowHashV1(value.baselineId);
424
+ return (hasFinancialDataflowExactFieldsV1(value, ['memberScopeId', 'baselineId', 'chargeCompositionId', 'status']) &&
425
+ isFinancialDataflowHashV1(value.baselineId) &&
426
+ isFinancialDataflowHashV1(value.chargeCompositionId));
358
427
  }
359
428
  return (value.status === 'unavailable' &&
360
429
  hasFinancialDataflowExactFieldsV1(value, ['memberScopeId', 'status', 'reasonCode']) &&
@@ -372,15 +441,7 @@ export const canonicalizeCurrentSpendMembershipV1 = (members) => {
372
441
  export const createCurrentSpendMembershipDigestV1 = (members) => `sha256:${sha256Utf8(canonicalizeCurrentSpendMembershipV1(members))}`;
373
442
  const isCompositionIdentity = (value) => {
374
443
  if (!isFinancialDataflowRecordV1(value) ||
375
- !hasFinancialDataflowExactFieldsV1(value, [
376
- 'schemaVersion',
377
- 'contractVersion',
378
- 'coordinate',
379
- 'members',
380
- 'amount',
381
- 'membershipDigest',
382
- 'algorithmVersion',
383
- ]) ||
444
+ !hasFinancialDataflowExactFieldsV1(value, ['schemaVersion', 'contractVersion', 'coordinate', 'members', 'amount', 'membershipDigest', 'algorithmVersion'], ['chargeSelection']) ||
384
445
  value.schemaVersion !== FINANCIAL_DATAFLOW_SCHEMA_VERSION_V1 ||
385
446
  value.contractVersion !== FINANCIAL_CURRENT_SPEND_COMPOSITION_CONTRACT_VERSION_V1 ||
386
447
  !isFinancialDataflowCoordinateV1(value.coordinate) ||
@@ -396,11 +457,45 @@ const isCompositionIdentity = (value) => {
396
457
  return false;
397
458
  }
398
459
  const currency = value.coordinate.accountingCurrency.status === 'resolved' ? value.coordinate.accountingCurrency.currencyCode : undefined;
460
+ const isChargeSelection = (selection) => {
461
+ if (!isFinancialDataflowRecordV1(selection) ||
462
+ !hasFinancialDataflowExactFieldsV1(selection, [
463
+ 'status',
464
+ 'includedAmount',
465
+ 'excludedAmount',
466
+ 'withheldAmount',
467
+ 'forecastEligibleAmount',
468
+ 'oneTimeAmount',
469
+ 'unknownRecurrenceAmount',
470
+ 'forecastStatus',
471
+ 'currencyCode',
472
+ ], ['reasonCodes', 'forecastReasonCodes']) ||
473
+ (selection.status !== 'available' && selection.status !== 'partial') ||
474
+ (selection.forecastStatus !== 'available' && selection.forecastStatus !== 'partial') ||
475
+ !isFinancialDataflowCurrencyV1(selection.currencyCode) ||
476
+ ![
477
+ selection.includedAmount,
478
+ selection.excludedAmount,
479
+ selection.withheldAmount,
480
+ selection.forecastEligibleAmount,
481
+ selection.oneTimeAmount,
482
+ selection.unknownRecurrenceAmount,
483
+ ].every(amount => isCanonicalExactMoney({ amount, currencyCode: selection.currencyCode })))
484
+ return false;
485
+ return ((selection.status === 'available' ? selection.reasonCodes === undefined : isReasonCodes(selection.reasonCodes)) &&
486
+ (selection.forecastStatus === 'available'
487
+ ? selection.forecastReasonCodes === undefined
488
+ : isReasonCodes(selection.forecastReasonCodes)));
489
+ };
399
490
  if (value.amount.status === 'available') {
400
491
  return (currency !== undefined &&
401
492
  hasFinancialDataflowExactFieldsV1(value.amount, ['status', 'amount', 'currencyCode']) &&
402
493
  isCanonicalExactMoney({ amount: value.amount.amount, currencyCode: value.amount.currencyCode }) &&
403
494
  value.amount.currencyCode === currency &&
495
+ isChargeSelection(value.chargeSelection) &&
496
+ value.chargeSelection.status === 'available' &&
497
+ value.chargeSelection.currencyCode === currency &&
498
+ value.chargeSelection.includedAmount === value.amount.amount &&
404
499
  value.members.length > 0 &&
405
500
  value.members.every(member => member.status === 'included'));
406
501
  }
@@ -410,11 +505,17 @@ const isCompositionIdentity = (value) => {
410
505
  isCanonicalExactMoney({ amount: value.amount.knownAmount, currencyCode: value.amount.currencyCode }) &&
411
506
  value.amount.currencyCode === currency &&
412
507
  isReasonCodes(value.amount.reasonCodes) &&
508
+ isChargeSelection(value.chargeSelection) &&
509
+ value.chargeSelection.currencyCode === currency &&
510
+ value.chargeSelection.includedAmount === value.amount.knownAmount &&
413
511
  value.members.some(member => member.status === 'included') &&
414
- value.members.some(member => member.status === 'unavailable'));
512
+ (value.members.some(member => member.status === 'unavailable') ||
513
+ value.amount.reasonCodes.includes('coverage-incomplete') ||
514
+ value.chargeSelection.status === 'partial'));
415
515
  }
416
516
  const unresolvedCurrency = value.coordinate.accountingCurrency;
417
517
  return (value.amount.status === 'unavailable' &&
518
+ value.chargeSelection === undefined &&
418
519
  hasFinancialDataflowExactFieldsV1(value.amount, ['status', 'reasonCodes']) &&
419
520
  isReasonCodes(value.amount.reasonCodes) &&
420
521
  (currency !== undefined || (unresolvedCurrency.status === 'unresolved' && value.amount.reasonCodes.includes(unresolvedCurrency.reasonCode))));
@@ -431,6 +532,19 @@ export const canonicalizeCurrentSpendCompositionIdentityV1 = (value) => {
431
532
  },
432
533
  members: [...value.members].sort((left, right) => left.memberScopeId.localeCompare(right.memberScopeId)),
433
534
  amount: value.amount.status === 'available' ? value.amount : { ...value.amount, reasonCodes: [...value.amount.reasonCodes].sort() },
535
+ ...(value.chargeSelection === undefined
536
+ ? {}
537
+ : {
538
+ chargeSelection: {
539
+ ...value.chargeSelection,
540
+ ...(value.chargeSelection.reasonCodes === undefined
541
+ ? {}
542
+ : { reasonCodes: [...value.chargeSelection.reasonCodes].sort() }),
543
+ ...(value.chargeSelection.forecastReasonCodes === undefined
544
+ ? {}
545
+ : { forecastReasonCodes: [...value.chargeSelection.forecastReasonCodes].sort() }),
546
+ },
547
+ }),
434
548
  };
435
549
  return canonicalizeFinancialDataflowJsonV1(canonical);
436
550
  };
@@ -447,7 +561,7 @@ export const isCurrentSpendCompositionV1 = (value) => {
447
561
  'amount',
448
562
  'membershipDigest',
449
563
  'algorithmVersion',
450
- ])) {
564
+ ], ['chargeSelection'])) {
451
565
  return false;
452
566
  }
453
567
  const { compositionId, ...identity } = value;
@@ -462,62 +576,118 @@ const hasCompatibleBaselineCoordinate = (coordinate, baseline) => baseline.provi
462
576
  toCanonicalEstimateLensV1(baseline.estimateLens) === coordinate.estimateLens &&
463
577
  baseline.requestedCurrencyCode === coordinate.requestedCurrencyCode;
464
578
  /** Proves that composition membership and money reconcile to exact V2 baseline envelopes. */
465
- export const isCurrentSpendCompositionCompatibleV1 = (composition, baselines) => {
579
+ export const isCurrentSpendCompositionCompatibleV1 = (composition, baselines, chargeCompositions) => {
466
580
  if (!isCurrentSpendCompositionV1(composition) ||
467
581
  !Array.isArray(baselines) ||
468
582
  baselines.length !== composition.members.length ||
469
583
  baselines.length > FINANCIAL_DATAFLOW_LIMITS_V1.maximumMembers ||
470
- !baselines.every(isFinancialScopeBaselineEnvelopeV2)) {
584
+ !baselines.every(isFinancialScopeBaselineEnvelopeV2) ||
585
+ !Array.isArray(chargeCompositions) ||
586
+ !chargeCompositions.every(isFinancialChargeCompositionV1)) {
471
587
  return false;
472
588
  }
473
589
  const typedBaselines = baselines;
590
+ const typedChargeCompositions = chargeCompositions;
591
+ const chargeCompositionById = new Map(typedChargeCompositions.map(value => [value.chargeCompositionId, value]));
592
+ if (chargeCompositionById.size !== typedChargeCompositions.length)
593
+ return false;
474
594
  const baselineByScopeId = new Map(typedBaselines.map(baseline => [baseline.scopeId, baseline]));
475
595
  if (baselineByScopeId.size !== typedBaselines.length ||
476
596
  new Set(typedBaselines.filter(baseline => baseline.status === 'available').map(baseline => baseline.baselineId)).size !==
477
597
  typedBaselines.filter(baseline => baseline.status === 'available').length) {
478
598
  return false;
479
599
  }
480
- const includedAmounts = [];
600
+ const includedSelections = [];
481
601
  const expectedReasonCodes = new Set();
482
602
  for (const member of composition.members) {
483
603
  const baseline = baselineByScopeId.get(member.memberScopeId);
484
604
  if (baseline === undefined || !hasCompatibleBaselineCoordinate(composition.coordinate, baseline))
485
605
  return false;
486
606
  if (member.status === 'included') {
487
- if (baseline.status !== 'available' || member.baselineId !== baseline.baselineId)
607
+ if (baseline.status !== 'available' ||
608
+ baseline.baselineKind !== 'owner' ||
609
+ member.baselineId !== baseline.baselineId ||
610
+ canonicalizeFinancialDataflowJsonV1(baseline.chargeInclusionPolicyRef) !==
611
+ canonicalizeFinancialDataflowJsonV1(AZURE_BILLED_ALL_CHARGES_POLICY_V1.policyRef))
612
+ return false;
613
+ const chargeComposition = chargeCompositionById.get(member.chargeCompositionId);
614
+ if (chargeComposition === undefined ||
615
+ chargeComposition.baselineId !== baseline.baselineId ||
616
+ chargeComposition.ownerScopeId !== baseline.scopeId ||
617
+ chargeComposition.period.windowKind !== baseline.period.windowKind ||
618
+ canonicalizeFinancialDataflowJsonV1(chargeComposition.period.requested) !== canonicalizeFinancialDataflowJsonV1(baseline.period.requested) ||
619
+ chargeComposition.costBasis !== baseline.costBasis ||
620
+ chargeComposition.estimateLens !== baseline.estimateLens ||
621
+ chargeComposition.accountingCurrencyCode !== baseline.total.currencyCode ||
622
+ chargeComposition.reconciliation.sourceTotal !== baseline.total.amount)
488
623
  return false;
489
624
  if (composition.coordinate.accountingCurrency.status === 'resolved' &&
490
625
  baseline.total.currencyCode !== composition.coordinate.accountingCurrency.currencyCode) {
491
626
  return false;
492
627
  }
493
- includedAmounts.push(baseline.total.amount);
628
+ includedSelections.push(selectFinancialChargesV1(chargeComposition, composition.coordinate.chargeInclusionPolicyRef));
629
+ includedSelections[includedSelections.length - 1].reasonCodes?.forEach(reason => expectedReasonCodes.add(reason));
630
+ if (baseline.status === 'available' && !isCompleteFinancialBaselinePeriodV2(baseline.period)) {
631
+ expectedReasonCodes.add('coverage-incomplete');
632
+ }
494
633
  continue;
495
634
  }
496
- if (baseline.status !== 'unavailable' || member.reasonCode !== baseline.unavailableReason)
497
- return false;
498
- expectedReasonCodes.add(baseline.unavailableReason);
635
+ if (baseline.status === 'unavailable') {
636
+ if (member.reasonCode !== baseline.unavailableReason)
637
+ return false;
638
+ expectedReasonCodes.add(baseline.unavailableReason);
639
+ }
640
+ else {
641
+ const expectedDerivedReason = baseline.baselineKind === 'aggregate'
642
+ ? 'charge-composition-requires-owner-baseline'
643
+ : 'charge-composition-unavailable';
644
+ if (member.reasonCode !== expectedDerivedReason)
645
+ return false;
646
+ expectedReasonCodes.add(expectedDerivedReason);
647
+ }
499
648
  }
500
649
  if (composition.coordinate.accountingCurrency.status === 'unresolved') {
501
650
  expectedReasonCodes.add(composition.coordinate.accountingCurrency.reasonCode);
502
651
  }
652
+ if (typedChargeCompositions.length !== includedSelections.length)
653
+ return false;
503
654
  const hasExpectedReasonCodes = (reasonCodes) => reasonCodes.length === expectedReasonCodes.size && reasonCodes.every(reasonCode => expectedReasonCodes.has(reasonCode));
504
655
  if (composition.coordinate.accountingCurrency.status === 'unresolved') {
505
656
  return composition.amount.status === 'unavailable' && hasExpectedReasonCodes(composition.amount.reasonCodes);
506
657
  }
507
- if (includedAmounts.length === 0) {
658
+ if (includedSelections.length === 0) {
508
659
  return composition.amount.status === 'unavailable' && hasExpectedReasonCodes(composition.amount.reasonCodes);
509
660
  }
510
- let includedTotal;
661
+ let aggregateSelection;
511
662
  try {
512
- includedTotal = formatExactDecimalValue(sumCanonicalDecimals(includedAmounts));
663
+ const reasonCodes = new Set(includedSelections.flatMap(selection => selection.reasonCodes ?? []));
664
+ const forecastReasonCodes = new Set(includedSelections.flatMap(selection => selection.forecastReasonCodes ?? []));
665
+ aggregateSelection = {
666
+ status: includedSelections.some(selection => selection.status === 'partial') ? 'partial' : 'available',
667
+ includedAmount: formatExactDecimalValue(sumCanonicalDecimals(includedSelections.map(selection => selection.includedAmount))),
668
+ excludedAmount: formatExactDecimalValue(sumCanonicalDecimals(includedSelections.map(selection => selection.excludedAmount))),
669
+ withheldAmount: formatExactDecimalValue(sumCanonicalDecimals(includedSelections.map(selection => selection.withheldAmount))),
670
+ forecastEligibleAmount: formatExactDecimalValue(sumCanonicalDecimals(includedSelections.map(selection => selection.forecastEligibleAmount))),
671
+ oneTimeAmount: formatExactDecimalValue(sumCanonicalDecimals(includedSelections.map(selection => selection.oneTimeAmount))),
672
+ unknownRecurrenceAmount: formatExactDecimalValue(sumCanonicalDecimals(includedSelections.map(selection => selection.unknownRecurrenceAmount))),
673
+ forecastStatus: includedSelections.some(selection => selection.forecastStatus === 'partial') ? 'partial' : 'available',
674
+ currencyCode: composition.coordinate.accountingCurrency.currencyCode,
675
+ ...(reasonCodes.size === 0 ? {} : { reasonCodes: [...reasonCodes].sort() }),
676
+ ...(forecastReasonCodes.size === 0
677
+ ? {}
678
+ : { forecastReasonCodes: [...forecastReasonCodes].sort() }),
679
+ };
513
680
  }
514
681
  catch {
515
682
  return false;
516
683
  }
517
- if (includedAmounts.length === composition.members.length) {
518
- return composition.amount.status === 'available' && composition.amount.amount === includedTotal;
684
+ const sameSelection = canonicalizeFinancialDataflowJsonV1(composition.chargeSelection) === canonicalizeFinancialDataflowJsonV1(aggregateSelection);
685
+ if (!sameSelection)
686
+ return false;
687
+ if (includedSelections.length === composition.members.length && expectedReasonCodes.size === 0) {
688
+ return composition.amount.status === 'available' && composition.amount.amount === aggregateSelection.includedAmount;
519
689
  }
520
690
  return (composition.amount.status === 'partial' &&
521
- composition.amount.knownAmount === includedTotal &&
691
+ composition.amount.knownAmount === aggregateSelection.includedAmount &&
522
692
  hasExpectedReasonCodes(composition.amount.reasonCodes));
523
693
  };
@@ -12,6 +12,13 @@ const EVIDENCE_ROLES = new Set([
12
12
  'retail-rate',
13
13
  'commitment-quote',
14
14
  'fx-conversion',
15
+ 'commercial-arrangement',
16
+ 'provider-access-observation',
17
+ 'configuration-timeline',
18
+ 'provider-price-schedule',
19
+ 'pricing-function',
20
+ 'charge-inclusion-policy',
21
+ 'settlement-revision',
15
22
  'eligibility-rule',
16
23
  'recommendation-scenario-set',
17
24
  'recommendation-lifecycle',
@@ -1,2 +1,6 @@
1
1
  export const FINANCIAL_POLICY_READ_PROJECTION_CONTRACT_VERSION_V1 = 'financial-policy-read-projection/v1';
2
2
  export const FINANCIAL_POLICY_ACTION_ATTEMPT_CONTRACT_VERSION_V1 = 'financial-policy-action-attempt/v1';
3
+ export const FINANCIAL_POLICY_DEFINITION_COMMAND_CONTRACT_VERSION_V1 = 'financial-policy-definition-command/v1';
4
+ export const FINANCIAL_POLICY_READ_CURRENT_POINTER_CONTRACT_VERSION_V1 = 'financial-policy-read-current-pointer/v1';
5
+ export const FINANCIAL_POLICY_ACTION_COMPLETION_CONTRACT_VERSION_V1 = 'financial-policy-action-completion/v1';
6
+ export const FINANCIAL_POLICY_READ_MANIFEST_CONTRACT_VERSION_V1 = 'financial-policy-read-manifest/v1';