@spottoai/types-package 1.0.2-dev1138.2 → 1.0.2-dev1138.5

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 (261) hide show
  1. package/README.md +9 -0
  2. package/dist/accounts/accounts.d.ts +77 -4
  3. package/dist/accounts/accounts.d.ts.map +1 -1
  4. package/dist/accounts/accounts.js +2 -1
  5. package/dist/accounts/accounts.js.map +1 -1
  6. package/dist/accounts/azureManualOnboarding.d.ts +114 -0
  7. package/dist/accounts/azureManualOnboarding.d.ts.map +1 -0
  8. package/dist/accounts/azureManualOnboarding.js +12 -0
  9. package/dist/accounts/azureManualOnboarding.js.map +1 -0
  10. package/dist/accounts/azureSpSetup.d.ts +128 -31
  11. package/dist/accounts/azureSpSetup.d.ts.map +1 -1
  12. package/dist/accounts/azureSpSetup.js +15 -0
  13. package/dist/accounts/azureSpSetup.js.map +1 -1
  14. package/dist/accounts/azureSpSetupDurable.d.ts +8 -0
  15. package/dist/accounts/azureSpSetupDurable.d.ts.map +1 -1
  16. package/dist/accounts/azureSpSetupDurable.js +28 -0
  17. package/dist/accounts/azureSpSetupDurable.js.map +1 -1
  18. package/dist/accounts/index.d.ts +1 -0
  19. package/dist/accounts/index.d.ts.map +1 -1
  20. package/dist/accounts/index.js +1 -0
  21. package/dist/accounts/index.js.map +1 -1
  22. package/dist/accounts/readPermissions.d.ts +1 -1
  23. package/dist/accounts/readPermissions.d.ts.map +1 -1
  24. package/dist/accounts/readPermissions.js.map +1 -1
  25. package/dist/accounts/validation.d.ts +24 -0
  26. package/dist/accounts/validation.d.ts.map +1 -1
  27. package/dist/ai/index.d.ts +14 -1
  28. package/dist/ai/index.d.ts.map +1 -1
  29. package/dist/ai/index.js +12 -0
  30. package/dist/ai/index.js.map +1 -1
  31. package/dist/aws/commitments-planning.d.ts +5 -0
  32. package/dist/aws/commitments-planning.d.ts.map +1 -1
  33. package/dist/aws/commitments-planning.js +19 -0
  34. package/dist/aws/commitments-planning.js.map +1 -1
  35. package/dist/aws/estates.d.ts +1 -1
  36. package/dist/aws/estates.d.ts.map +1 -1
  37. package/dist/aws/estates.js +7 -1
  38. package/dist/aws/estates.js.map +1 -1
  39. package/dist/aws/index.d.ts +5 -0
  40. package/dist/aws/index.d.ts.map +1 -1
  41. package/dist/aws/index.js +5 -0
  42. package/dist/aws/index.js.map +1 -1
  43. package/dist/aws/onboarding.d.ts +3 -0
  44. package/dist/aws/onboarding.d.ts.map +1 -1
  45. package/dist/aws/organizationCommitments.d.ts +260 -0
  46. package/dist/aws/organizationCommitments.d.ts.map +1 -0
  47. package/dist/aws/organizationCommitments.js +53 -0
  48. package/dist/aws/organizationCommitments.js.map +1 -0
  49. package/dist/aws/organizationCommitmentsApiValidation.d.ts +21 -0
  50. package/dist/aws/organizationCommitmentsApiValidation.d.ts.map +1 -0
  51. package/dist/aws/organizationCommitmentsApiValidation.js +226 -0
  52. package/dist/aws/organizationCommitmentsApiValidation.js.map +1 -0
  53. package/dist/aws/organizationCommitmentsValidation.d.ts +12 -0
  54. package/dist/aws/organizationCommitmentsValidation.d.ts.map +1 -0
  55. package/dist/aws/organizationCommitmentsValidation.js +228 -0
  56. package/dist/aws/organizationCommitmentsValidation.js.map +1 -0
  57. package/dist/aws/portalOrganizationCommitmentsPlanningPublicArtifactValidation.d.ts +9 -0
  58. package/dist/aws/portalOrganizationCommitmentsPlanningPublicArtifactValidation.d.ts.map +1 -0
  59. package/dist/aws/portalOrganizationCommitmentsPlanningPublicArtifactValidation.js +407 -0
  60. package/dist/aws/portalOrganizationCommitmentsPlanningPublicArtifactValidation.js.map +1 -0
  61. package/dist/aws/portalOrganizationCommitmentsPlanningPublicArtifacts.d.ts +17 -0
  62. package/dist/aws/portalOrganizationCommitmentsPlanningPublicArtifacts.d.ts.map +1 -0
  63. package/dist/aws/portalOrganizationCommitmentsPlanningPublicArtifacts.js +6 -0
  64. package/dist/aws/portalOrganizationCommitmentsPlanningPublicArtifacts.js.map +1 -0
  65. package/dist/aws/requests.d.ts +13 -2
  66. package/dist/aws/requests.d.ts.map +1 -1
  67. package/dist/aws/requests.js +1 -1
  68. package/dist/aws/requests.js.map +1 -1
  69. package/dist/azure/commitmentsPlanning.d.ts +2 -2
  70. package/dist/azure/commitmentsPlanning.d.ts.map +1 -1
  71. package/dist/azure/financialAnalytics.d.ts +68 -2
  72. package/dist/azure/financialAnalytics.d.ts.map +1 -1
  73. package/dist/azure/financialAnalyticsDelivery.d.ts +2 -0
  74. package/dist/azure/financialAnalyticsDelivery.d.ts.map +1 -1
  75. package/dist/azure/financialAnalyticsDelivery.js +4 -1
  76. package/dist/azure/financialAnalyticsDelivery.js.map +1 -1
  77. package/dist/azure/financialAnalyticsDisplayKernel.d.ts +12 -0
  78. package/dist/azure/financialAnalyticsDisplayKernel.d.ts.map +1 -0
  79. package/dist/azure/financialAnalyticsDisplayKernel.js +144 -0
  80. package/dist/azure/financialAnalyticsDisplayKernel.js.map +1 -0
  81. package/dist/azure/financialAnalyticsValidation.d.ts.map +1 -1
  82. package/dist/azure/financialAnalyticsValidation.js +61 -7
  83. package/dist/azure/financialAnalyticsValidation.js.map +1 -1
  84. package/dist/azure/financialAuthorityProjectionKernel.d.ts +7 -0
  85. package/dist/azure/financialAuthorityProjectionKernel.d.ts.map +1 -0
  86. package/dist/azure/financialAuthorityProjectionKernel.js +165 -0
  87. package/dist/azure/financialAuthorityProjectionKernel.js.map +1 -0
  88. package/dist/azure/financialAuthorityView.d.ts +4 -0
  89. package/dist/azure/financialAuthorityView.d.ts.map +1 -1
  90. package/dist/azure/financialAuthorityView.js.map +1 -1
  91. package/dist/azure/financialAuthorityViewValidation.d.ts +3 -1
  92. package/dist/azure/financialAuthorityViewValidation.d.ts.map +1 -1
  93. package/dist/azure/financialAuthorityViewValidation.js +206 -2
  94. package/dist/azure/financialAuthorityViewValidation.js.map +1 -1
  95. package/dist/azure/financialChargeComposition.d.ts +81 -0
  96. package/dist/azure/financialChargeComposition.d.ts.map +1 -0
  97. package/dist/azure/financialChargeComposition.js +41 -0
  98. package/dist/azure/financialChargeComposition.js.map +1 -0
  99. package/dist/azure/financialChargeCompositionKernel.d.ts +3 -0
  100. package/dist/azure/financialChargeCompositionKernel.d.ts.map +1 -0
  101. package/dist/azure/financialChargeCompositionKernel.js +53 -0
  102. package/dist/azure/financialChargeCompositionKernel.js.map +1 -0
  103. package/dist/azure/financialChargeCompositionValidation.d.ts +8 -0
  104. package/dist/azure/financialChargeCompositionValidation.d.ts.map +1 -0
  105. package/dist/azure/financialChargeCompositionValidation.js +164 -0
  106. package/dist/azure/financialChargeCompositionValidation.js.map +1 -0
  107. package/dist/azure/financialDataflow.d.ts +8 -1
  108. package/dist/azure/financialDataflow.d.ts.map +1 -1
  109. package/dist/azure/financialDataflow.js.map +1 -1
  110. package/dist/azure/financialDataflowKernel.d.ts +2 -0
  111. package/dist/azure/financialDataflowKernel.d.ts.map +1 -1
  112. package/dist/azure/financialDataflowKernel.js +60 -7
  113. package/dist/azure/financialDataflowKernel.js.map +1 -1
  114. package/dist/azure/financialDataflowValidation.d.ts +1 -1
  115. package/dist/azure/financialDataflowValidation.d.ts.map +1 -1
  116. package/dist/azure/financialDataflowValidation.js +146 -28
  117. package/dist/azure/financialDataflowValidation.js.map +1 -1
  118. package/dist/azure/financialPolicy.d.ts +3 -0
  119. package/dist/azure/financialPolicy.d.ts.map +1 -1
  120. package/dist/azure/financialPolicy.js.map +1 -1
  121. package/dist/azure/financialPolicyValidation.d.ts.map +1 -1
  122. package/dist/azure/financialPolicyValidation.js +5 -0
  123. package/dist/azure/financialPolicyValidation.js.map +1 -1
  124. package/dist/azure/financialProjection.d.ts +11 -1
  125. package/dist/azure/financialProjection.d.ts.map +1 -1
  126. package/dist/azure/financialProjection.js.map +1 -1
  127. package/dist/azure/financialProjectionValidation.d.ts.map +1 -1
  128. package/dist/azure/financialProjectionValidation.js +43 -3
  129. package/dist/azure/financialProjectionValidation.js.map +1 -1
  130. package/dist/azure/financialSavingsAuthority.d.ts +25 -4
  131. package/dist/azure/financialSavingsAuthority.d.ts.map +1 -1
  132. package/dist/azure/financialSavingsAuthorityValidation.d.ts +6 -2
  133. package/dist/azure/financialSavingsAuthorityValidation.d.ts.map +1 -1
  134. package/dist/azure/financialSavingsAuthorityValidation.js +126 -2
  135. package/dist/azure/financialSavingsAuthorityValidation.js.map +1 -1
  136. package/dist/azure/financialSavingsCoordinateValidation.d.ts.map +1 -1
  137. package/dist/azure/financialSavingsCoordinateValidation.js +62 -19
  138. package/dist/azure/financialSavingsCoordinateValidation.js.map +1 -1
  139. package/dist/azure/financialSavingsSurfaceProjection.d.ts +58 -3
  140. package/dist/azure/financialSavingsSurfaceProjection.d.ts.map +1 -1
  141. package/dist/azure/financialSavingsSurfaceProjection.js +3 -1
  142. package/dist/azure/financialSavingsSurfaceProjection.js.map +1 -1
  143. package/dist/azure/financialSavingsSurfaceProjectionKernel.d.ts +14 -0
  144. package/dist/azure/financialSavingsSurfaceProjectionKernel.d.ts.map +1 -0
  145. package/dist/azure/financialSavingsSurfaceProjectionKernel.js +326 -0
  146. package/dist/azure/financialSavingsSurfaceProjectionKernel.js.map +1 -0
  147. package/dist/azure/financialSavingsSurfaceProjectionValidation.d.ts.map +1 -1
  148. package/dist/azure/financialSavingsSurfaceProjectionValidation.js +126 -12
  149. package/dist/azure/financialSavingsSurfaceProjectionValidation.js.map +1 -1
  150. package/dist/azure/financialScope.d.ts +6 -0
  151. package/dist/azure/financialScope.d.ts.map +1 -1
  152. package/dist/azure/financialScope.js +6 -0
  153. package/dist/azure/financialScope.js.map +1 -1
  154. package/dist/azure/governance.d.ts +145 -0
  155. package/dist/azure/governance.d.ts.map +1 -1
  156. package/dist/azure/governance.js +2 -1
  157. package/dist/azure/governance.js.map +1 -1
  158. package/dist/azure/metrics.d.ts +2 -2
  159. package/dist/azure/metrics.d.ts.map +1 -1
  160. package/dist/azure/payloads.d.ts +19 -0
  161. package/dist/azure/payloads.d.ts.map +1 -1
  162. package/dist/azure/prices.d.ts +16 -3
  163. package/dist/azure/prices.d.ts.map +1 -1
  164. package/dist/azure/recommendationState.d.ts +1 -1
  165. package/dist/azure/recommendationState.d.ts.map +1 -1
  166. package/dist/azure/recommendations.d.ts +15 -5
  167. package/dist/azure/recommendations.d.ts.map +1 -1
  168. package/dist/azure/reports.d.ts +3 -2
  169. package/dist/azure/reports.d.ts.map +1 -1
  170. package/dist/azure/reports.js.map +1 -1
  171. package/dist/azure/resources.d.ts +12 -0
  172. package/dist/azure/resources.d.ts.map +1 -1
  173. package/dist/azure/serviceRetirement.d.ts +33 -2
  174. package/dist/azure/serviceRetirement.d.ts.map +1 -1
  175. package/dist/azure/subscriptions.d.ts +13 -2
  176. package/dist/azure/subscriptions.d.ts.map +1 -1
  177. package/dist/azure/views.d.ts +26 -3
  178. package/dist/azure/views.d.ts.map +1 -1
  179. package/dist/azure/views.js.map +1 -1
  180. package/dist/azure/vmPatchManagement.d.ts +109 -0
  181. package/dist/azure/vmPatchManagement.d.ts.map +1 -0
  182. package/dist/azure/vmPatchManagement.js +7 -0
  183. package/dist/azure/vmPatchManagement.js.map +1 -0
  184. package/dist/common/provider.d.ts +53 -0
  185. package/dist/common/provider.d.ts.map +1 -1
  186. package/dist/common/provider.js.map +1 -1
  187. package/dist/environment/canonicalization.d.ts +12 -0
  188. package/dist/environment/canonicalization.d.ts.map +1 -0
  189. package/dist/environment/canonicalization.js +40 -0
  190. package/dist/environment/canonicalization.js.map +1 -0
  191. package/dist/environment/contracts.d.ts +196 -0
  192. package/dist/environment/contracts.d.ts.map +1 -0
  193. package/dist/environment/contracts.js +21 -0
  194. package/dist/environment/contracts.js.map +1 -0
  195. package/dist/environment/index.d.ts +5 -0
  196. package/dist/environment/index.d.ts.map +1 -0
  197. package/dist/environment/index.js +21 -0
  198. package/dist/environment/index.js.map +1 -0
  199. package/dist/environment/internal.d.ts +21 -0
  200. package/dist/environment/internal.d.ts.map +1 -0
  201. package/dist/environment/internal.js +113 -0
  202. package/dist/environment/internal.js.map +1 -0
  203. package/dist/environment/references.d.ts +18 -0
  204. package/dist/environment/references.d.ts.map +1 -0
  205. package/dist/environment/references.js +206 -0
  206. package/dist/environment/references.js.map +1 -0
  207. package/dist/environment/validation.d.ts +28 -0
  208. package/dist/environment/validation.d.ts.map +1 -0
  209. package/dist/environment/validation.js +320 -0
  210. package/dist/environment/validation.js.map +1 -0
  211. package/dist/esm/accounts/accounts.js +1 -0
  212. package/dist/esm/accounts/azureManualOnboarding.js +8 -0
  213. package/dist/esm/accounts/azureSpSetup.js +14 -1
  214. package/dist/esm/accounts/azureSpSetupDurable.js +27 -1
  215. package/dist/esm/accounts/index.js +1 -0
  216. package/dist/esm/ai/index.js +10 -1
  217. package/dist/esm/aws/commitments-planning.js +5 -0
  218. package/dist/esm/aws/estates.js +7 -1
  219. package/dist/esm/aws/index.js +5 -0
  220. package/dist/esm/aws/organizationCommitments.js +48 -0
  221. package/dist/esm/aws/organizationCommitmentsApiValidation.js +220 -0
  222. package/dist/esm/aws/organizationCommitmentsValidation.js +224 -0
  223. package/dist/esm/aws/portalOrganizationCommitmentsPlanningPublicArtifactValidation.js +402 -0
  224. package/dist/esm/aws/portalOrganizationCommitmentsPlanningPublicArtifacts.js +2 -0
  225. package/dist/esm/aws/requests.js +1 -1
  226. package/dist/esm/azure/financialAnalyticsDelivery.js +2 -0
  227. package/dist/esm/azure/financialAnalyticsDisplayKernel.js +139 -0
  228. package/dist/esm/azure/financialAnalyticsValidation.js +61 -7
  229. package/dist/esm/azure/financialAuthorityProjectionKernel.js +159 -0
  230. package/dist/esm/azure/financialAuthorityViewValidation.js +204 -1
  231. package/dist/esm/azure/financialChargeComposition.js +36 -0
  232. package/dist/esm/azure/financialChargeCompositionKernel.js +48 -0
  233. package/dist/esm/azure/financialChargeCompositionValidation.js +155 -0
  234. package/dist/esm/azure/financialDataflowKernel.js +60 -7
  235. package/dist/esm/azure/financialDataflowValidation.js +146 -28
  236. package/dist/esm/azure/financialPolicyValidation.js +5 -0
  237. package/dist/esm/azure/financialProjectionValidation.js +43 -3
  238. package/dist/esm/azure/financialSavingsAuthorityValidation.js +124 -2
  239. package/dist/esm/azure/financialSavingsCoordinateValidation.js +62 -19
  240. package/dist/esm/azure/financialSavingsSurfaceProjection.js +2 -0
  241. package/dist/esm/azure/financialSavingsSurfaceProjectionKernel.js +318 -0
  242. package/dist/esm/azure/financialSavingsSurfaceProjectionValidation.js +126 -12
  243. package/dist/esm/azure/financialScope.js +6 -0
  244. package/dist/esm/azure/governance.js +1 -0
  245. package/dist/esm/azure/vmPatchManagement.js +3 -0
  246. package/dist/esm/entries/commitments-planning.js +2 -2
  247. package/dist/esm/entries/environment.js +3 -0
  248. package/dist/esm/environment/canonicalization.js +34 -0
  249. package/dist/esm/environment/contracts.js +17 -0
  250. package/dist/esm/environment/index.js +4 -0
  251. package/dist/esm/environment/internal.js +97 -0
  252. package/dist/esm/environment/references.js +194 -0
  253. package/dist/esm/environment/validation.js +303 -0
  254. package/dist/esm/index.js +2 -0
  255. package/dist/index.d.ts +2 -0
  256. package/dist/index.d.ts.map +1 -1
  257. package/dist/index.js +2 -0
  258. package/dist/index.js.map +1 -1
  259. package/dist/portfolio/portfolioOperations.d.ts +1 -1
  260. package/dist/portfolio/portfolioOperations.d.ts.map +1 -1
  261. package/package.json +15 -3
@@ -4,7 +4,15 @@ import { isCanonicalExactMoney } from './financialValidationPrimitives.js';
4
4
  import { FINANCIAL_PROJECTION_CONTRACT_VERSION_V1, FINANCIAL_PROJECTION_SCHEMA_VERSION_V1, FINANCIAL_PROJECTION_UNAVAILABLE_REASONS_V1, } from './financialProjection.js';
5
5
  const SHA256_ID = /^sha256:[0-9a-f]{64}$/;
6
6
  const CURRENCY = /^[A-Z]{3}$/;
7
- const OPERATIONS = new Set(['replace-rate', 'replace-quantity', 'remove-component', 'schedule-quantity', 'commitment-coverage']);
7
+ const OPERATIONS = new Set([
8
+ 'unclassified',
9
+ 'replace-rate',
10
+ 'replace-quantity',
11
+ 'replace-quantity-and-rate',
12
+ 'remove-component',
13
+ 'schedule-quantity',
14
+ 'commitment-coverage',
15
+ ]);
8
16
  const COST_BASES = new Set(['billed', 'amortized']);
9
17
  const ESTIMATE_LENSES = new Set(['actual-only', 'actual-plus-estimated', 'estimates-only']);
10
18
  const TARGET_PROVENANCE = new Set(['retail-derived', 'provider-quote-derived', 'billing-backed', 'estimated', 'configuration-derived']);
@@ -32,6 +40,16 @@ const isNonNegativeDecimal = (value, currency = 'AUD') => {
32
40
  }
33
41
  };
34
42
  const isUnit = (value) => isIdentity(value) && value.length <= 512;
43
+ const isReplayedProduct = (quantity, rate, targetAmount, currency) => {
44
+ if (!isNonNegativeDecimal(quantity) || !isNonNegativeDecimal(rate, currency) || !isDecimal(targetAmount, currency))
45
+ return false;
46
+ try {
47
+ return equalsDecimal(multiplyExactDecimalValues(parseCanonicalDecimal(quantity), parseCanonicalDecimal(rate)), parseCanonicalDecimal(targetAmount));
48
+ }
49
+ catch {
50
+ return false;
51
+ }
52
+ };
35
53
  const isCanonicalDate = (value) => typeof value === 'string' && /^\d{4}-\d{2}-\d{2}$/.test(value) && Number.isFinite(Date.parse(`${value}T00:00:00.000Z`));
36
54
  const isNormalizedAverageMonthProfile = (value) => isRecord(value) &&
37
55
  hasExactFields(value, ['kind', 'annualDayCount', 'monthDivisor', 'hoursPerDay', 'normalizedHours']) &&
@@ -203,7 +221,8 @@ const isAppliedComponentTargets = (value, operationKind, targetProvenance, targe
203
221
  !isNonNegativeDecimal(target.targetRate.amount) ||
204
222
  target.targetRate.currencyCode !== accountingCurrencyCode ||
205
223
  !isUnit(target.targetRate.quantityUnit) ||
206
- target.targetRate.quantityUnit !== target.sourceQuantity.unit)
224
+ target.targetRate.quantityUnit !== target.sourceQuantity.unit ||
225
+ !isReplayedProduct(target.sourceQuantity.amount, target.targetRate.amount, target.targetAmount, accountingCurrencyCode))
207
226
  return false;
208
227
  continue;
209
228
  }
@@ -218,7 +237,24 @@ const isAppliedComponentTargets = (value, operationKind, targetProvenance, targe
218
237
  !hasExactFields(target.targetQuantity, ['amount', 'unit']) ||
219
238
  !isNonNegativeDecimal(target.targetQuantity.amount) ||
220
239
  !isUnit(target.targetQuantity.unit) ||
221
- target.targetQuantity.unit !== target.sourceRate.unit)
240
+ target.targetQuantity.unit !== target.sourceRate.unit ||
241
+ !isReplayedProduct(target.targetQuantity.amount, target.sourceRate.amount, target.targetAmount, accountingCurrencyCode))
242
+ return false;
243
+ continue;
244
+ }
245
+ if (operationKind === 'replace-quantity-and-rate') {
246
+ if (!hasExactFields(target, ['componentId', 'targetAmount', 'targetConfigurationId', 'targetEvidenceRefIds', 'targetQuantity', 'targetRate']) ||
247
+ !isRecord(target.targetQuantity) ||
248
+ !hasExactFields(target.targetQuantity, ['amount', 'unit']) ||
249
+ !isNonNegativeDecimal(target.targetQuantity.amount) ||
250
+ !isUnit(target.targetQuantity.unit) ||
251
+ !isRecord(target.targetRate) ||
252
+ !hasExactFields(target.targetRate, ['amount', 'currencyCode', 'quantityUnit']) ||
253
+ !isNonNegativeDecimal(target.targetRate.amount, accountingCurrencyCode) ||
254
+ target.targetRate.currencyCode !== accountingCurrencyCode ||
255
+ !isUnit(target.targetRate.quantityUnit) ||
256
+ target.targetRate.quantityUnit !== target.targetQuantity.unit ||
257
+ !isReplayedProduct(target.targetQuantity.amount, target.targetRate.amount, target.targetAmount, accountingCurrencyCode))
222
258
  return false;
223
259
  continue;
224
260
  }
@@ -428,6 +464,10 @@ const isUnavailable = (value) => {
428
464
  !TARGET_PERIOD_CONVENTIONS.has(value.targetPeriodConvention) ||
429
465
  !isTargetPeriodProfileCompatible(value.targetPeriodConvention, value.targetPeriodProfile, false) ||
430
466
  (isObservedPeriodProfile(value.targetPeriodProfile) && value.operationKind !== 'commitment-coverage') ||
467
+ (value.operationKind === 'unclassified' &&
468
+ (value.unavailableReason !== 'target-evidence-unavailable' ||
469
+ !Array.isArray(value.affectedComponentIds) ||
470
+ value.affectedComponentIds.length !== 0)) ||
431
471
  (value.targetProvenance === 'configuration-derived' && value.operationKind !== 'remove-component') ||
432
472
  (value.operationKind === 'commitment-coverage' && value.targetProvenance !== 'provider-quote-derived') ||
433
473
  !isPossiblyEmptyHashArray(value.affectedComponentIds) ||
@@ -2,7 +2,7 @@ import { sha256Utf8 } from '../common/sha256.js';
2
2
  import { FINANCIAL_SAVINGS_AUTHORITY_CONTRACT_VERSION_V1, FINANCIAL_SAVINGS_AUTHORITY_SCHEMA_VERSION_V1, } from './financialSavingsAuthority.js';
3
3
  import { validateFinancialEligibilityAssessmentV1, validateFinancialEligibilityBaselineV1, } from './financialEligibilityAssessmentValidation.js';
4
4
  import { validateFinancialSavingsCoordinateEnvelopeV1 } from './financialSavingsCoordinateValidation.js';
5
- import { canonicalizeFinancialSavingsJsonValue, hasExactFinancialSavingsFields, isFinancialSavingsHash, isFinancialSavingsRecord, } from './financialSavingsAuthorityValidationPrimitives.js';
5
+ import { canonicalizeFinancialSavingsJsonValue, hasExactFinancialSavingsFields, haveSameFinancialSavingsSet, isFinancialSavingsHash, isFinancialSavingsIdentity, isFinancialSavingsIsoInstant, isFinancialSavingsMinorUnits, isFinancialSavingsRecord, sumFinancialSavingsMinorUnits, } from './financialSavingsAuthorityValidationPrimitives.js';
6
6
  export { canonicalizeFinancialEligibilityAssessmentIdentityV1, createFinancialEligibilityAssessmentIdV1, } from './financialEligibilityAssessmentValidation.js';
7
7
  export { canonicalizeFinancialSavingsActivationIdentityV1, canonicalizeFinancialSavingsAllocationIdentityV1, canonicalizeFinancialSavingsDenominatorIdentityV1, createFinancialSavingsActivationIdV1, createFinancialSavingsAllocationIdV1, createFinancialSavingsDenominatorIdV1, } from './financialSavingsCoordinateValidation.js';
8
8
  export const canonicalizeFinancialSavingsAuthorityIdentityV1 = (value) => JSON.stringify(canonicalizeFinancialSavingsJsonValue({
@@ -28,7 +28,7 @@ export const canonicalizeFinancialSavingsAuthorityIdentityV1 = (value) => JSON.s
28
28
  .map(allocation => ({
29
29
  ...allocation,
30
30
  billableComponentIds: [...allocation.billableComponentIds].sort(),
31
- eligibility: allocation.eligibility.kind === 'not-applicable'
31
+ eligibility: allocation.eligibility.kind !== 'mapped'
32
32
  ? allocation.eligibility
33
33
  : {
34
34
  ...allocation.eligibility,
@@ -115,3 +115,125 @@ export const isFinancialSavingsAuthorityBoundToFinancialAuthorityV1 = (value, au
115
115
  const { savingsAuthorityId: _savingsAuthorityId, ...identity } = savingsAuthority;
116
116
  return savingsAuthority.savingsAuthorityId === createFinancialSavingsAuthorityIdV1(identity);
117
117
  };
118
+ const RESOURCE_PROJECTION_UNAVAILABLE_REASONS = new Set([
119
+ 'scenario-coverage-unproven',
120
+ 'unmigrated-scenario-producer',
121
+ 'projection-unavailable',
122
+ 'activation-unavailable',
123
+ 'allocation-unavailable',
124
+ ]);
125
+ const RESOURCE_PROJECTION_CURRENCY = /^[A-Z]{3}$/;
126
+ const normalizeResourceScope = (value) => value.trim().toLowerCase().replace(/\/+$/, '');
127
+ const isResourceContribution = (value, scopeId) => isFinancialSavingsRecord(value) &&
128
+ hasExactFinancialSavingsFields(value, ['ownerScopeId', 'allocationIds', 'savingsMinorUnits']) &&
129
+ isFinancialSavingsIdentity(value.ownerScopeId) &&
130
+ normalizeResourceScope(value.ownerScopeId) === scopeId &&
131
+ Array.isArray(value.allocationIds) &&
132
+ value.allocationIds.length > 0 &&
133
+ value.allocationIds.length <= 20000 &&
134
+ value.allocationIds.every(isFinancialSavingsHash) &&
135
+ new Set(value.allocationIds).size === value.allocationIds.length &&
136
+ isFinancialSavingsMinorUnits(value.savingsMinorUnits);
137
+ const isRecommendationContribution = (value, scopeId) => isFinancialSavingsRecord(value) &&
138
+ hasExactFinancialSavingsFields(value, ['ownerScopeId', 'recommendationId', 'allocationIds', 'savingsMinorUnits']) &&
139
+ isFinancialSavingsIdentity(value.ownerScopeId) &&
140
+ normalizeResourceScope(value.ownerScopeId) === scopeId &&
141
+ isFinancialSavingsIdentity(value.recommendationId) &&
142
+ Array.isArray(value.allocationIds) &&
143
+ value.allocationIds.length > 0 &&
144
+ value.allocationIds.length <= 20000 &&
145
+ value.allocationIds.every(isFinancialSavingsHash) &&
146
+ new Set(value.allocationIds).size === value.allocationIds.length &&
147
+ isFinancialSavingsMinorUnits(value.savingsMinorUnits);
148
+ const isSavingsResourceCoordinate = (value, scopeId) => {
149
+ if (!isFinancialSavingsRecord(value) || !isFinancialSavingsHash(value.coordinateId))
150
+ return false;
151
+ if (value.status === 'unavailable') {
152
+ return (hasExactFinancialSavingsFields(value, ['status', 'coordinateId', 'unavailableReason'], ['currentAggregateBaselineId']) &&
153
+ (value.currentAggregateBaselineId === undefined || isFinancialSavingsHash(value.currentAggregateBaselineId)) &&
154
+ typeof value.unavailableReason === 'string' &&
155
+ RESOURCE_PROJECTION_UNAVAILABLE_REASONS.has(value.unavailableReason));
156
+ }
157
+ const partial = value.status === 'partial';
158
+ if (value.status !== 'available' &&
159
+ !partial)
160
+ return false;
161
+ if (!hasExactFinancialSavingsFields(value, [
162
+ 'status',
163
+ 'coordinateId',
164
+ 'currentAggregateBaselineId',
165
+ 'accountingCurrencyCode',
166
+ 'minorUnitScale',
167
+ 'roundingMode',
168
+ 'recommendationContributions',
169
+ ...(partial ? ['unavailableScenarioIds'] : []),
170
+ ], ['resourceContribution']) ||
171
+ !isFinancialSavingsHash(value.currentAggregateBaselineId) ||
172
+ typeof value.accountingCurrencyCode !== 'string' ||
173
+ !RESOURCE_PROJECTION_CURRENCY.test(value.accountingCurrencyCode) ||
174
+ !Number.isSafeInteger(value.minorUnitScale) ||
175
+ Number(value.minorUnitScale) < 0 ||
176
+ Number(value.minorUnitScale) > 6 ||
177
+ value.roundingMode !== 'half-away-from-zero' ||
178
+ (value.resourceContribution !== undefined && !isResourceContribution(value.resourceContribution, scopeId)) ||
179
+ !Array.isArray(value.recommendationContributions) ||
180
+ value.recommendationContributions.length > 20000 ||
181
+ !value.recommendationContributions.every(contribution => isRecommendationContribution(contribution, scopeId)) ||
182
+ (partial &&
183
+ (!Array.isArray(value.unavailableScenarioIds) ||
184
+ value.unavailableScenarioIds.length === 0 ||
185
+ value.unavailableScenarioIds.length > 20000 ||
186
+ !value.unavailableScenarioIds.every(isFinancialSavingsIdentity) ||
187
+ new Set(value.unavailableScenarioIds).size !== value.unavailableScenarioIds.length)))
188
+ return false;
189
+ const recommendationIds = value.recommendationContributions.map(contribution => contribution.recommendationId);
190
+ const allocationIds = value.recommendationContributions.flatMap(contribution => contribution.allocationIds);
191
+ const contributionSum = sumFinancialSavingsMinorUnits(value.recommendationContributions.map(contribution => contribution.savingsMinorUnits));
192
+ const resourceContribution = value.resourceContribution;
193
+ return (new Set(recommendationIds).size === recommendationIds.length &&
194
+ new Set(allocationIds).size === allocationIds.length &&
195
+ contributionSum !== undefined &&
196
+ (resourceContribution === undefined
197
+ ? allocationIds.length === 0 && contributionSum === 0
198
+ : haveSameFinancialSavingsSet(allocationIds, resourceContribution.allocationIds) &&
199
+ contributionSum === resourceContribution.savingsMinorUnits));
200
+ };
201
+ /** Strict structural and arithmetic validation for one bounded resource savings projection. */
202
+ export const isFinancialSavingsResourceProjectionV1 = (value) => {
203
+ if (!isFinancialSavingsRecord(value) ||
204
+ !hasExactFinancialSavingsFields(value, [
205
+ 'contractVersion',
206
+ 'savingsAuthorityId',
207
+ 'financialAuthorityId',
208
+ 'artifactGeneration',
209
+ 'scopeId',
210
+ 'coordinates',
211
+ ]) ||
212
+ value.contractVersion !== 'financial-savings-resource-projection/v1' ||
213
+ !isFinancialSavingsHash(value.savingsAuthorityId) ||
214
+ !isFinancialSavingsHash(value.financialAuthorityId) ||
215
+ !isFinancialSavingsRecord(value.artifactGeneration) ||
216
+ !hasExactFinancialSavingsFields(value.artifactGeneration, ['runId', 'generatedAt']) ||
217
+ !isFinancialSavingsIdentity(value.artifactGeneration.runId) ||
218
+ !isFinancialSavingsIsoInstant(value.artifactGeneration.generatedAt) ||
219
+ !isFinancialSavingsIdentity(value.scopeId) ||
220
+ value.scopeId !== normalizeResourceScope(value.scopeId) ||
221
+ !Array.isArray(value.coordinates) ||
222
+ value.coordinates.length === 0 ||
223
+ value.coordinates.length > 128)
224
+ return false;
225
+ const projection = value;
226
+ return (projection.coordinates.every(coordinate => isSavingsResourceCoordinate(coordinate, projection.scopeId)) &&
227
+ new Set(projection.coordinates.map(coordinate => coordinate.coordinateId)).size === projection.coordinates.length);
228
+ };
229
+ /** Verifies that the bounded savings projection is the exact companion of one bounded Financial Authority projection. */
230
+ export const isFinancialSavingsResourceProjectionBoundToFinancialProjectionV1 = (value, financialProjection) => {
231
+ if (!isFinancialSavingsResourceProjectionV1(value))
232
+ return false;
233
+ const financialCoordinateIds = financialProjection.coordinates.map(coordinate => coordinate.coordinateId);
234
+ return (value.financialAuthorityId === financialProjection.authorityId &&
235
+ normalizeResourceScope(value.scopeId) === normalizeResourceScope(financialProjection.scopeId) &&
236
+ value.artifactGeneration.runId === financialProjection.artifactGeneration.runId &&
237
+ value.artifactGeneration.generatedAt === financialProjection.artifactGeneration.generatedAt &&
238
+ haveSameFinancialSavingsSet(value.coordinates.map(coordinate => coordinate.coordinateId), financialCoordinateIds));
239
+ };
@@ -23,8 +23,17 @@ const ACTIVATION_REASONS = new Set([
23
23
  'lifecycle-conflict',
24
24
  'unrecognized-lifecycle',
25
25
  'generation-mismatch',
26
+ 'projection-unavailable',
27
+ 'eligibility-unavailable',
28
+ ]);
29
+ const UNAVAILABLE_ACTIVATION_REASONS = new Set([
30
+ 'lifecycle-stale',
31
+ 'lifecycle-unavailable',
32
+ 'lifecycle-conflict',
33
+ 'generation-mismatch',
34
+ 'projection-unavailable',
35
+ 'eligibility-unavailable',
26
36
  ]);
27
- const UNAVAILABLE_ACTIVATION_REASONS = new Set(['lifecycle-stale', 'lifecycle-unavailable', 'lifecycle-conflict', 'generation-mismatch']);
28
37
  export const canonicalizeFinancialSavingsDenominatorIdentityV1 = (value) => JSON.stringify(canonicalizeFinancialSavingsJsonValue({
29
38
  kind: value.kind,
30
39
  baselineId: value.baselineId,
@@ -35,7 +44,8 @@ export const canonicalizeFinancialSavingsDenominatorIdentityV1 = (value) => JSON
35
44
  export const createFinancialSavingsDenominatorIdV1 = (value) => `sha256:${sha256Utf8(canonicalizeFinancialSavingsDenominatorIdentityV1(value))}`;
36
45
  export const canonicalizeFinancialSavingsActivationIdentityV1 = (value) => JSON.stringify(canonicalizeFinancialSavingsJsonValue({
37
46
  recommendationId: value.recommendationId,
38
- projectionId: value.projectionId,
47
+ scenarioId: value.scenarioId,
48
+ ...(value.projectionId === undefined ? {} : { projectionId: value.projectionId }),
39
49
  lifecycleState: value.lifecycleState,
40
50
  lifecycleVersion: value.lifecycleVersion,
41
51
  lifecycleEvidenceRefId: value.lifecycleEvidenceRefId,
@@ -49,10 +59,11 @@ export const canonicalizeFinancialSavingsAllocationIdentityV1 = (value) => JSON.
49
59
  ownerScopeId: value.ownerScopeId,
50
60
  billableComponentIds: [...value.billableComponentIds].sort(),
51
61
  recommendationId: value.recommendationId,
62
+ scenarioId: value.scenarioId,
52
63
  baselineId: value.baselineId,
53
64
  projectionId: value.projectionId,
54
65
  denominatorId: value.denominatorId,
55
- eligibility: value.eligibility.kind === 'not-applicable'
66
+ eligibility: value.eligibility.kind !== 'mapped'
56
67
  ? value.eligibility
57
68
  : {
58
69
  ...value.eligibility,
@@ -98,10 +109,23 @@ const isActivationDecision = (state, result, reason) => {
98
109
  return UNAVAILABLE_ACTIVATION_REASONS.has(reason);
99
110
  };
100
111
  const isEligibility = (value) => {
101
- if (!isFinancialSavingsRecord(value) || (value.kind !== 'not-applicable' && value.kind !== 'mapped'))
112
+ if (!isFinancialSavingsRecord(value) || !['not-applicable', 'unavailable', 'mapped'].includes(String(value.kind)))
102
113
  return false;
103
114
  if (value.kind === 'not-applicable')
104
115
  return Object.keys(value).length === 1;
116
+ if (value.kind === 'unavailable') {
117
+ return (Object.keys(value).length === 2 &&
118
+ typeof value.reason === 'string' &&
119
+ [
120
+ 'rule-evidence-unavailable',
121
+ 'eligibility-baseline-unavailable',
122
+ 'eligible-components-unavailable',
123
+ 'denominator-unavailable',
124
+ 'current-baseline-mapping-unavailable',
125
+ 'currency-conflict',
126
+ 'reconciliation-failure',
127
+ ].includes(value.reason));
128
+ }
105
129
  return (Object.keys(value).length === 5 &&
106
130
  isFinancialSavingsHash(value.eligibilityId) &&
107
131
  isFinancialSavingsHash(value.eligibilityBaselineId) &&
@@ -114,7 +138,7 @@ const isEligibility = (value) => {
114
138
  value.eligibilityComponentIds.every(isFinancialSavingsIdentity) &&
115
139
  new Set(value.eligibilityComponentIds).size === value.eligibilityComponentIds.length);
116
140
  };
117
- const validateAvailableCoordinate = (value, authorityCoordinate, eligibilityById, evidenceById, authorityGeneratedAt, authorityRunId) => {
141
+ const validateComposedCoordinate = (value, authorityCoordinate, eligibilityById, evidenceById, authorityGeneratedAt, authorityRunId) => {
118
142
  if (!hasExactFinancialSavingsFields(value, [
119
143
  'status',
120
144
  'coordinateId',
@@ -140,7 +164,7 @@ const validateAvailableCoordinate = (value, authorityCoordinate, eligibilityById
140
164
  value.roundingMode !== 'half-away-from-zero' ||
141
165
  !isFinancialSavingsRecord(value.scenarioCoverage) ||
142
166
  !hasExactFinancialSavingsFields(value.scenarioCoverage, ['status', 'evidenceRefId', 'scenarioIds']) ||
143
- value.scenarioCoverage.status !== 'complete' ||
167
+ value.scenarioCoverage.status !== (value.status === 'available' ? 'complete' : 'partial') ||
144
168
  !isFinancialSavingsHash(value.scenarioCoverage.evidenceRefId) ||
145
169
  !Array.isArray(value.scenarioCoverage.scenarioIds) ||
146
170
  value.scenarioCoverage.scenarioIds.length > 20000 ||
@@ -166,15 +190,17 @@ const validateAvailableCoordinate = (value, authorityCoordinate, eligibilityById
166
190
  Date.parse(scenarioCoverageEvidence.intrinsicTime.at) > Date.parse(authorityGeneratedAt))
167
191
  return false;
168
192
  const projectionById = new Map(authorityCoordinate.projections.flatMap(projection => (projection.status === 'available' ? [[projection.projectionId, projection]] : [])));
193
+ const availableProjectionScenarioIds = new Set(authorityCoordinate.projections.flatMap(projection => (projection.status === 'available' ? [projection.scenarioId] : [])));
194
+ const unavailableEligibilityScenarioIds = new Set([...eligibilityById.values()].flatMap(assessment => (assessment.status === 'unavailable' ? [assessment.scenarioId] : [])));
169
195
  const activationById = new Map();
170
- const activationByRecommendationId = new Map();
196
+ const activationByScenarioId = new Map();
171
197
  for (const activation of value.activations) {
172
198
  const lifecycleEvidence = evidenceById.get(activation.lifecycleEvidenceRefId);
173
199
  if (!isFinancialSavingsRecord(activation) ||
174
200
  !hasExactFinancialSavingsFields(activation, [
175
201
  'activationId',
202
+ 'scenarioId',
176
203
  'recommendationId',
177
- 'projectionId',
178
204
  'lifecycleState',
179
205
  'lifecycleVersion',
180
206
  'lifecycleEvidenceRefId',
@@ -182,19 +208,29 @@ const validateAvailableCoordinate = (value, authorityCoordinate, eligibilityById
182
208
  'reason',
183
209
  'evaluatedAt',
184
210
  'policyVersion',
185
- ]) ||
211
+ ], ['projectionId']) ||
186
212
  !isFinancialSavingsHash(activation.activationId) ||
187
213
  activationById.has(activation.activationId) ||
188
- activationByRecommendationId.has(activation.recommendationId) ||
214
+ activationByScenarioId.has(activation.scenarioId) ||
215
+ !isFinancialSavingsIdentity(activation.scenarioId) ||
189
216
  !isFinancialSavingsIdentity(activation.recommendationId) ||
190
- !isFinancialSavingsHash(activation.projectionId) ||
217
+ (activation.projectionId !== undefined && !isFinancialSavingsHash(activation.projectionId)) ||
191
218
  !isFinancialSavingsIdentity(activation.lifecycleVersion) ||
192
219
  !isFinancialSavingsHash(activation.lifecycleEvidenceRefId) ||
193
220
  !isActivationDecision(activation.lifecycleState, activation.result, activation.reason) ||
194
221
  !isFinancialSavingsIsoInstant(activation.evaluatedAt) ||
195
222
  Date.parse(activation.evaluatedAt) > Date.parse(authorityGeneratedAt) ||
196
223
  !isFinancialSavingsIdentity(activation.policyVersion) ||
197
- projectionById.get(activation.projectionId)?.scenarioId !== activation.recommendationId ||
224
+ (activation.result === 'included' &&
225
+ (activation.projectionId === undefined || projectionById.get(activation.projectionId)?.scenarioId !== activation.scenarioId)) ||
226
+ (activation.result === 'excluded' &&
227
+ activation.projectionId !== undefined &&
228
+ projectionById.get(activation.projectionId)?.scenarioId !== activation.scenarioId) ||
229
+ (activation.result === 'unavailable' &&
230
+ (activation.projectionId !== undefined ||
231
+ (activation.reason === 'projection-unavailable' && availableProjectionScenarioIds.has(activation.scenarioId)) ||
232
+ (activation.reason === 'eligibility-unavailable' &&
233
+ !unavailableEligibilityScenarioIds.has(activation.scenarioId)))) ||
198
234
  lifecycleEvidence?.role !== 'recommendation-lifecycle' ||
199
235
  lifecycleEvidence.revisionId !== activation.lifecycleVersion ||
200
236
  Date.parse(lifecycleEvidence.intrinsicTime.at) > Date.parse(authorityGeneratedAt))
@@ -203,12 +239,15 @@ const validateAvailableCoordinate = (value, authorityCoordinate, eligibilityById
203
239
  if (activation.activationId !== createFinancialSavingsActivationIdV1(activationIdentity))
204
240
  return false;
205
241
  activationById.set(activation.activationId, activation);
206
- activationByRecommendationId.set(activation.recommendationId, activation);
242
+ activationByScenarioId.set(activation.scenarioId, activation);
207
243
  }
208
244
  const coveredScenarioIds = new Set(value.scenarioCoverage.scenarioIds);
209
- const activatedScenarioIds = new Set(value.activations.map(activation => activation.recommendationId));
245
+ const activatedScenarioIds = new Set(value.activations.map(activation => activation.scenarioId));
210
246
  if (value.scenarioCoverage.scenarioIds.some(scenarioId => !activatedScenarioIds.has(scenarioId)) ||
211
- value.activations.some(activation => !coveredScenarioIds.has(activation.recommendationId)))
247
+ value.activations.some(activation => !coveredScenarioIds.has(activation.scenarioId)))
248
+ return false;
249
+ const hasUnavailableActivation = value.activations.some(activation => activation.result === 'unavailable');
250
+ if ((value.status === 'available' && hasUnavailableActivation) || (value.status === 'partial' && !hasUnavailableActivation))
212
251
  return false;
213
252
  const allocationById = new Map();
214
253
  const allocatedBaselineComponents = new Set();
@@ -218,7 +257,7 @@ const validateAvailableCoordinate = (value, authorityCoordinate, eligibilityById
218
257
  const eligibility = allocation.eligibility.kind === 'mapped' ? eligibilityById.get(allocation.eligibility.eligibilityId) : undefined;
219
258
  const expectedDenominatorId = allocation.eligibility.kind === 'mapped' && eligibility?.status === 'available'
220
259
  ? eligibility.denominator.denominatorId
221
- : projection
260
+ : allocation.eligibility.kind === 'not-applicable' && projection
222
261
  ? createFinancialSavingsDenominatorIdV1({
223
262
  kind: 'projection-affected-current',
224
263
  baselineId: projection.baselineId,
@@ -232,6 +271,7 @@ const validateAvailableCoordinate = (value, authorityCoordinate, eligibilityById
232
271
  'allocationId',
233
272
  'ownerScopeId',
234
273
  'billableComponentIds',
274
+ 'scenarioId',
235
275
  'recommendationId',
236
276
  'baselineId',
237
277
  'projectionId',
@@ -248,6 +288,7 @@ const validateAvailableCoordinate = (value, authorityCoordinate, eligibilityById
248
288
  allocation.billableComponentIds.length > 20000 ||
249
289
  !allocation.billableComponentIds.every(isFinancialSavingsIdentity) ||
250
290
  new Set(allocation.billableComponentIds).size !== allocation.billableComponentIds.length ||
291
+ !isFinancialSavingsIdentity(allocation.scenarioId) ||
251
292
  !isFinancialSavingsIdentity(allocation.recommendationId) ||
252
293
  !isFinancialSavingsHash(allocation.baselineId) ||
253
294
  !isFinancialSavingsHash(allocation.projectionId) ||
@@ -261,15 +302,17 @@ const validateAvailableCoordinate = (value, authorityCoordinate, eligibilityById
261
302
  projection.baselineId !== allocation.baselineId ||
262
303
  !haveSameFinancialSavingsSet(projection.affectedComponentIds, allocation.billableComponentIds) ||
263
304
  decimalToMinorUnits(projection.change.savings, value.minorUnitScale) !== allocation.savingsMinorUnits ||
305
+ projection.scenarioId !== allocation.scenarioId ||
264
306
  !activation ||
265
307
  activation.result !== 'included' ||
308
+ activation.scenarioId !== allocation.scenarioId ||
266
309
  activation.recommendationId !== allocation.recommendationId ||
267
310
  activation.projectionId !== allocation.projectionId ||
268
311
  (allocation.eligibility.kind === 'mapped' &&
269
312
  (!eligibility ||
270
313
  eligibility.status !== 'available' ||
271
314
  eligibility.scopeId !== allocation.ownerScopeId ||
272
- eligibility.scenarioId !== allocation.recommendationId ||
315
+ eligibility.scenarioId !== allocation.scenarioId ||
273
316
  eligibility.eligibilityBaselineId !== allocation.eligibility.eligibilityBaselineId ||
274
317
  eligibility.denominator.denominatorId !== allocation.denominatorId ||
275
318
  eligibility.currentBaselineMapping.currentBaselineId !== allocation.baselineId ||
@@ -360,6 +403,6 @@ export const validateFinancialSavingsCoordinateEnvelopeV1 = (value, authorityCoo
360
403
  ? value.currentAggregateBaselineId === authorityCoordinate.aggregateBaseline.baselineId
361
404
  : value.currentAggregateBaselineId === undefined));
362
405
  }
363
- return (value.status === 'available' &&
364
- validateAvailableCoordinate(value, authorityCoordinate, eligibilityById, evidenceById, authorityGeneratedAt, authorityRunId));
406
+ return ((value.status === 'available' || value.status === 'partial') &&
407
+ validateComposedCoordinate(value, authorityCoordinate, eligibilityById, evidenceById, authorityGeneratedAt, authorityRunId));
365
408
  };
@@ -1,2 +1,4 @@
1
1
  export const FINANCIAL_SAVINGS_SURFACE_PROJECTION_SCHEMA_VERSION_V1 = 1;
2
2
  export const FINANCIAL_SAVINGS_SURFACE_PROJECTION_CONTRACT_VERSION_V1 = 'financial-savings-surface-projection/v1';
3
+ export const FINANCIAL_SAVINGS_QUERY_SELECTION_CONTRACT_VERSION_V1 = 'financial-savings-query-selection/v1';
4
+ export const FINANCIAL_SAVINGS_RESOURCE_QUERY_SELECTION_CONTRACT_VERSION_V1 = 'financial-savings-resource-query-selection/v1';