dabke 0.83.0 → 0.84.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (330) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/README.md +22 -27
  3. package/dist/client.d.ts +39 -3
  4. package/dist/client.d.ts.map +1 -1
  5. package/dist/client.js.map +1 -1
  6. package/dist/client.schemas.d.ts +118 -18
  7. package/dist/client.schemas.d.ts.map +1 -1
  8. package/dist/client.schemas.js +110 -6
  9. package/dist/client.schemas.js.map +1 -1
  10. package/dist/client.types.d.ts +63 -7
  11. package/dist/client.types.d.ts.map +1 -1
  12. package/dist/client.types.js.map +1 -1
  13. package/dist/cpsat/cost.d.ts +5 -2
  14. package/dist/cpsat/cost.d.ts.map +1 -1
  15. package/dist/cpsat/cost.js +13 -6
  16. package/dist/cpsat/cost.js.map +1 -1
  17. package/dist/cpsat/model-builder.d.ts +42 -61
  18. package/dist/cpsat/model-builder.d.ts.map +1 -1
  19. package/dist/cpsat/model-builder.js +451 -56
  20. package/dist/cpsat/model-builder.js.map +1 -1
  21. package/dist/cpsat/response.d.ts +19 -7
  22. package/dist/cpsat/response.d.ts.map +1 -1
  23. package/dist/cpsat/response.js +48 -9
  24. package/dist/cpsat/response.js.map +1 -1
  25. package/dist/cpsat/rule-descriptor.d.ts +250 -0
  26. package/dist/cpsat/rule-descriptor.d.ts.map +1 -0
  27. package/dist/cpsat/rule-descriptor.js +51 -0
  28. package/dist/cpsat/rule-descriptor.js.map +1 -0
  29. package/dist/cpsat/rules/artifacts.d.ts +9 -0
  30. package/dist/cpsat/rules/artifacts.d.ts.map +1 -0
  31. package/dist/cpsat/rules/artifacts.js +31 -0
  32. package/dist/cpsat/rules/artifacts.js.map +1 -0
  33. package/dist/cpsat/rules/assign-together.d.ts +18 -20
  34. package/dist/cpsat/rules/assign-together.d.ts.map +1 -1
  35. package/dist/cpsat/rules/assign-together.js +90 -54
  36. package/dist/cpsat/rules/assign-together.js.map +1 -1
  37. package/dist/cpsat/rules/assigned-day.d.ts +12 -0
  38. package/dist/cpsat/rules/assigned-day.d.ts.map +1 -0
  39. package/dist/cpsat/rules/assigned-day.js +43 -0
  40. package/dist/cpsat/rules/assigned-day.js.map +1 -0
  41. package/dist/cpsat/rules/assignment-priority.d.ts +15 -29
  42. package/dist/cpsat/rules/assignment-priority.d.ts.map +1 -1
  43. package/dist/cpsat/rules/assignment-priority.js +47 -50
  44. package/dist/cpsat/rules/assignment-priority.js.map +1 -1
  45. package/dist/cpsat/rules/assignment-terms.d.ts +6 -0
  46. package/dist/cpsat/rules/assignment-terms.d.ts.map +1 -0
  47. package/dist/cpsat/rules/assignment-terms.js +19 -0
  48. package/dist/cpsat/rules/assignment-terms.js.map +1 -0
  49. package/dist/cpsat/rules/concurrent-intervals.d.ts +19 -0
  50. package/dist/cpsat/rules/concurrent-intervals.d.ts.map +1 -0
  51. package/dist/cpsat/rules/concurrent-intervals.js +57 -0
  52. package/dist/cpsat/rules/concurrent-intervals.js.map +1 -0
  53. package/dist/cpsat/rules/cost-utils.d.ts +1 -3
  54. package/dist/cpsat/rules/cost-utils.d.ts.map +1 -1
  55. package/dist/cpsat/rules/cost-utils.js +0 -7
  56. package/dist/cpsat/rules/cost-utils.js.map +1 -1
  57. package/dist/cpsat/rules/day-cost-multiplier.d.ts +10 -10
  58. package/dist/cpsat/rules/day-cost-multiplier.d.ts.map +1 -1
  59. package/dist/cpsat/rules/day-cost-multiplier.js +88 -77
  60. package/dist/cpsat/rules/day-cost-multiplier.js.map +1 -1
  61. package/dist/cpsat/rules/day-cost-surcharge.d.ts +10 -10
  62. package/dist/cpsat/rules/day-cost-surcharge.d.ts.map +1 -1
  63. package/dist/cpsat/rules/day-cost-surcharge.js +76 -65
  64. package/dist/cpsat/rules/day-cost-surcharge.js.map +1 -1
  65. package/dist/cpsat/rules/index.d.ts +30 -24
  66. package/dist/cpsat/rules/index.d.ts.map +1 -1
  67. package/dist/cpsat/rules/index.js +30 -24
  68. package/dist/cpsat/rules/index.js.map +1 -1
  69. package/dist/cpsat/rules/location-preference.d.ts +14 -21
  70. package/dist/cpsat/rules/location-preference.d.ts.map +1 -1
  71. package/dist/cpsat/rules/location-preference.js +45 -45
  72. package/dist/cpsat/rules/location-preference.js.map +1 -1
  73. package/dist/cpsat/rules/max-concurrent-assignments.d.ts +46 -0
  74. package/dist/cpsat/rules/max-concurrent-assignments.d.ts.map +1 -0
  75. package/dist/cpsat/rules/max-concurrent-assignments.js +121 -0
  76. package/dist/cpsat/rules/max-concurrent-assignments.js.map +1 -0
  77. package/dist/cpsat/rules/max-consecutive-days.d.ts +18 -17
  78. package/dist/cpsat/rules/max-consecutive-days.d.ts.map +1 -1
  79. package/dist/cpsat/rules/max-consecutive-days.js +67 -66
  80. package/dist/cpsat/rules/max-consecutive-days.js.map +1 -1
  81. package/dist/cpsat/rules/max-days-of-week-per-period.d.ts +45 -0
  82. package/dist/cpsat/rules/max-days-of-week-per-period.d.ts.map +1 -0
  83. package/dist/cpsat/rules/max-days-of-week-per-period.js +95 -0
  84. package/dist/cpsat/rules/max-days-of-week-per-period.js.map +1 -0
  85. package/dist/cpsat/rules/max-days-week.d.ts +17 -31
  86. package/dist/cpsat/rules/max-days-week.d.ts.map +1 -1
  87. package/dist/cpsat/rules/max-days-week.js +69 -81
  88. package/dist/cpsat/rules/max-days-week.js.map +1 -1
  89. package/dist/cpsat/rules/max-hours-day.d.ts +14 -31
  90. package/dist/cpsat/rules/max-hours-day.d.ts.map +1 -1
  91. package/dist/cpsat/rules/max-hours-day.js +56 -72
  92. package/dist/cpsat/rules/max-hours-day.js.map +1 -1
  93. package/dist/cpsat/rules/max-hours-week.d.ts +15 -31
  94. package/dist/cpsat/rules/max-hours-week.d.ts.map +1 -1
  95. package/dist/cpsat/rules/max-hours-week.js +60 -75
  96. package/dist/cpsat/rules/max-hours-week.js.map +1 -1
  97. package/dist/cpsat/rules/max-shifts-day.d.ts +17 -33
  98. package/dist/cpsat/rules/max-shifts-day.d.ts.map +1 -1
  99. package/dist/cpsat/rules/max-shifts-day.js +57 -73
  100. package/dist/cpsat/rules/max-shifts-day.js.map +1 -1
  101. package/dist/cpsat/rules/min-consecutive-days.d.ts +18 -18
  102. package/dist/cpsat/rules/min-consecutive-days.d.ts.map +1 -1
  103. package/dist/cpsat/rules/min-consecutive-days.js +123 -94
  104. package/dist/cpsat/rules/min-consecutive-days.js.map +1 -1
  105. package/dist/cpsat/rules/min-days-of-week-per-period.d.ts +35 -0
  106. package/dist/cpsat/rules/min-days-of-week-per-period.d.ts.map +1 -0
  107. package/dist/cpsat/rules/min-days-of-week-per-period.js +108 -0
  108. package/dist/cpsat/rules/min-days-of-week-per-period.js.map +1 -0
  109. package/dist/cpsat/rules/min-days-week.d.ts +13 -26
  110. package/dist/cpsat/rules/min-days-week.d.ts.map +1 -1
  111. package/dist/cpsat/rules/min-days-week.js +85 -74
  112. package/dist/cpsat/rules/min-days-week.js.map +1 -1
  113. package/dist/cpsat/rules/min-hours-day.d.ts +14 -17
  114. package/dist/cpsat/rules/min-hours-day.d.ts.map +1 -1
  115. package/dist/cpsat/rules/min-hours-day.js +72 -54
  116. package/dist/cpsat/rules/min-hours-day.js.map +1 -1
  117. package/dist/cpsat/rules/min-hours-week.d.ts +15 -18
  118. package/dist/cpsat/rules/min-hours-week.d.ts.map +1 -1
  119. package/dist/cpsat/rules/min-hours-week.js +75 -57
  120. package/dist/cpsat/rules/min-hours-week.js.map +1 -1
  121. package/dist/cpsat/rules/min-rest-between-shifts.d.ts +14 -17
  122. package/dist/cpsat/rules/min-rest-between-shifts.d.ts.map +1 -1
  123. package/dist/cpsat/rules/min-rest-between-shifts.js +148 -138
  124. package/dist/cpsat/rules/min-rest-between-shifts.js.map +1 -1
  125. package/dist/cpsat/rules/minimize-cost.d.ts +2 -18
  126. package/dist/cpsat/rules/minimize-cost.d.ts.map +1 -1
  127. package/dist/cpsat/rules/minimize-cost.js +151 -163
  128. package/dist/cpsat/rules/minimize-cost.js.map +1 -1
  129. package/dist/cpsat/rules/must-assign.d.ts +5 -42
  130. package/dist/cpsat/rules/must-assign.d.ts.map +1 -1
  131. package/dist/cpsat/rules/must-assign.js +43 -75
  132. package/dist/cpsat/rules/must-assign.js.map +1 -1
  133. package/dist/cpsat/rules/overtime-daily-multiplier.d.ts +6 -10
  134. package/dist/cpsat/rules/overtime-daily-multiplier.d.ts.map +1 -1
  135. package/dist/cpsat/rules/overtime-daily-multiplier.js +118 -112
  136. package/dist/cpsat/rules/overtime-daily-multiplier.js.map +1 -1
  137. package/dist/cpsat/rules/overtime-daily-surcharge.d.ts +6 -11
  138. package/dist/cpsat/rules/overtime-daily-surcharge.d.ts.map +1 -1
  139. package/dist/cpsat/rules/overtime-daily-surcharge.js +104 -99
  140. package/dist/cpsat/rules/overtime-daily-surcharge.js.map +1 -1
  141. package/dist/cpsat/rules/overtime-tiered-multiplier.d.ts +9 -21
  142. package/dist/cpsat/rules/overtime-tiered-multiplier.d.ts.map +1 -1
  143. package/dist/cpsat/rules/overtime-tiered-multiplier.js +181 -199
  144. package/dist/cpsat/rules/overtime-tiered-multiplier.js.map +1 -1
  145. package/dist/cpsat/rules/overtime-weekly-multiplier.d.ts +13 -12
  146. package/dist/cpsat/rules/overtime-weekly-multiplier.d.ts.map +1 -1
  147. package/dist/cpsat/rules/overtime-weekly-multiplier.js +143 -143
  148. package/dist/cpsat/rules/overtime-weekly-multiplier.js.map +1 -1
  149. package/dist/cpsat/rules/overtime-weekly-surcharge.d.ts +7 -11
  150. package/dist/cpsat/rules/overtime-weekly-surcharge.d.ts.map +1 -1
  151. package/dist/cpsat/rules/overtime-weekly-surcharge.js +124 -119
  152. package/dist/cpsat/rules/overtime-weekly-surcharge.js.map +1 -1
  153. package/dist/cpsat/rules/pattern-eligibility.d.ts +6 -0
  154. package/dist/cpsat/rules/pattern-eligibility.d.ts.map +1 -0
  155. package/dist/cpsat/rules/pattern-eligibility.js +16 -0
  156. package/dist/cpsat/rules/pattern-eligibility.js.map +1 -0
  157. package/dist/cpsat/rules/pattern-time.d.ts +5 -0
  158. package/dist/cpsat/rules/pattern-time.d.ts.map +1 -0
  159. package/dist/cpsat/rules/pattern-time.js +20 -0
  160. package/dist/cpsat/rules/pattern-time.js.map +1 -0
  161. package/dist/cpsat/rules/registry.d.ts +217 -30
  162. package/dist/cpsat/rules/registry.d.ts.map +1 -1
  163. package/dist/cpsat/rules/registry.js +98 -34
  164. package/dist/cpsat/rules/registry.js.map +1 -1
  165. package/dist/cpsat/rules/resolver.d.ts +9 -7
  166. package/dist/cpsat/rules/resolver.d.ts.map +1 -1
  167. package/dist/cpsat/rules/resolver.js +19 -18
  168. package/dist/cpsat/rules/resolver.js.map +1 -1
  169. package/dist/cpsat/rules/role-preference.d.ts +24 -0
  170. package/dist/cpsat/rules/role-preference.d.ts.map +1 -0
  171. package/dist/cpsat/rules/role-preference.js +72 -0
  172. package/dist/cpsat/rules/role-preference.js.map +1 -0
  173. package/dist/cpsat/rules/rules.types.d.ts +90 -17
  174. package/dist/cpsat/rules/rules.types.d.ts.map +1 -1
  175. package/dist/cpsat/rules/scope.types.d.ts +24 -11
  176. package/dist/cpsat/rules/scope.types.d.ts.map +1 -1
  177. package/dist/cpsat/rules/scope.types.js +14 -19
  178. package/dist/cpsat/rules/scope.types.js.map +1 -1
  179. package/dist/cpsat/rules/target-days-week.d.ts +31 -0
  180. package/dist/cpsat/rules/target-days-week.d.ts.map +1 -0
  181. package/dist/cpsat/rules/target-days-week.js +80 -0
  182. package/dist/cpsat/rules/target-days-week.js.map +1 -0
  183. package/dist/cpsat/rules/target-peak-concurrent-assignments.d.ts +33 -0
  184. package/dist/cpsat/rules/target-peak-concurrent-assignments.d.ts.map +1 -0
  185. package/dist/cpsat/rules/target-peak-concurrent-assignments.js +146 -0
  186. package/dist/cpsat/rules/target-peak-concurrent-assignments.js.map +1 -0
  187. package/dist/cpsat/rules/time-cost-surcharge.d.ts +15 -14
  188. package/dist/cpsat/rules/time-cost-surcharge.d.ts.map +1 -1
  189. package/dist/cpsat/rules/time-cost-surcharge.js +82 -96
  190. package/dist/cpsat/rules/time-cost-surcharge.js.map +1 -1
  191. package/dist/cpsat/rules/time-off.d.ts +21 -57
  192. package/dist/cpsat/rules/time-off.d.ts.map +1 -1
  193. package/dist/cpsat/rules/time-off.js +114 -127
  194. package/dist/cpsat/rules/time-off.js.map +1 -1
  195. package/dist/cpsat/rules/variables.d.ts +4 -0
  196. package/dist/cpsat/rules/variables.d.ts.map +1 -0
  197. package/dist/cpsat/rules/variables.js +10 -0
  198. package/dist/cpsat/rules/variables.js.map +1 -0
  199. package/dist/cpsat/rules.d.ts +20 -3
  200. package/dist/cpsat/rules.d.ts.map +1 -1
  201. package/dist/cpsat/rules.js +19 -2
  202. package/dist/cpsat/rules.js.map +1 -1
  203. package/dist/cpsat/semantic-time.d.ts +7 -6
  204. package/dist/cpsat/semantic-time.d.ts.map +1 -1
  205. package/dist/cpsat/semantic-time.js +15 -28
  206. package/dist/cpsat/semantic-time.js.map +1 -1
  207. package/dist/cpsat/types.d.ts +47 -4
  208. package/dist/cpsat/types.d.ts.map +1 -1
  209. package/dist/cpsat/types.js +24 -1
  210. package/dist/cpsat/types.js.map +1 -1
  211. package/dist/cpsat/utils.d.ts +23 -6
  212. package/dist/cpsat/utils.d.ts.map +1 -1
  213. package/dist/cpsat/utils.js +76 -15
  214. package/dist/cpsat/utils.js.map +1 -1
  215. package/dist/cpsat/validation-reporter.d.ts +6 -2
  216. package/dist/cpsat/validation-reporter.d.ts.map +1 -1
  217. package/dist/cpsat/validation-reporter.js +122 -10
  218. package/dist/cpsat/validation-reporter.js.map +1 -1
  219. package/dist/cpsat/validation.types.d.ts +21 -10
  220. package/dist/cpsat/validation.types.d.ts.map +1 -1
  221. package/dist/datetime.utils.d.ts +7 -13
  222. package/dist/datetime.utils.d.ts.map +1 -1
  223. package/dist/datetime.utils.js +29 -36
  224. package/dist/datetime.utils.js.map +1 -1
  225. package/dist/index.d.ts +12 -8
  226. package/dist/index.d.ts.map +1 -1
  227. package/dist/index.js +8 -3
  228. package/dist/index.js.map +1 -1
  229. package/dist/schedule/cost.d.ts +48 -60
  230. package/dist/schedule/cost.d.ts.map +1 -1
  231. package/dist/schedule/cost.js +15 -51
  232. package/dist/schedule/cost.js.map +1 -1
  233. package/dist/schedule/coverage.d.ts +57 -28
  234. package/dist/schedule/coverage.d.ts.map +1 -1
  235. package/dist/schedule/coverage.js +24 -1
  236. package/dist/schedule/coverage.js.map +1 -1
  237. package/dist/schedule/definition.d.ts +138 -19
  238. package/dist/schedule/definition.d.ts.map +1 -1
  239. package/dist/schedule/definition.js +99 -90
  240. package/dist/schedule/definition.js.map +1 -1
  241. package/dist/schedule/index.d.ts +4 -4
  242. package/dist/schedule/index.d.ts.map +1 -1
  243. package/dist/schedule/index.js +2 -2
  244. package/dist/schedule/index.js.map +1 -1
  245. package/dist/schedule/rules.d.ts +438 -113
  246. package/dist/schedule/rules.d.ts.map +1 -1
  247. package/dist/schedule/rules.js +310 -108
  248. package/dist/schedule/rules.js.map +1 -1
  249. package/dist/schedule/shift-patterns.d.ts +0 -17
  250. package/dist/schedule/shift-patterns.d.ts.map +1 -1
  251. package/dist/schedule/shift-patterns.js +0 -17
  252. package/dist/schedule/shift-patterns.js.map +1 -1
  253. package/dist/schedule/time-periods.d.ts +37 -27
  254. package/dist/schedule/time-periods.d.ts.map +1 -1
  255. package/dist/schedule/time-periods.js +37 -27
  256. package/dist/schedule/time-periods.js.map +1 -1
  257. package/dist/types.d.ts +67 -3
  258. package/dist/types.d.ts.map +1 -1
  259. package/dist/types.js +64 -0
  260. package/dist/types.js.map +1 -1
  261. package/package.json +8 -9
  262. package/solver/src/solver/models.py +41 -4
  263. package/solver/src/solver/solver.py +546 -157
  264. package/solver/tests/test_solver.py +363 -7
  265. package/src/client.schemas.ts +127 -10
  266. package/src/client.ts +3 -0
  267. package/src/client.types.ts +73 -7
  268. package/src/cpsat/cost.ts +17 -7
  269. package/src/cpsat/model-builder.ts +614 -129
  270. package/src/cpsat/response.ts +57 -13
  271. package/src/cpsat/rule-descriptor.ts +311 -0
  272. package/src/cpsat/rules/artifacts.ts +56 -0
  273. package/src/cpsat/rules/assign-together.ts +104 -69
  274. package/src/cpsat/rules/assigned-day.ts +70 -0
  275. package/src/cpsat/rules/assignment-priority.ts +54 -58
  276. package/src/cpsat/rules/assignment-terms.ts +43 -0
  277. package/src/cpsat/rules/concurrent-intervals.ts +93 -0
  278. package/src/cpsat/rules/cost-utils.ts +1 -9
  279. package/src/cpsat/rules/day-cost-multiplier.ts +101 -81
  280. package/src/cpsat/rules/day-cost-surcharge.ts +91 -70
  281. package/src/cpsat/rules/index.ts +30 -24
  282. package/src/cpsat/rules/location-preference.ts +47 -52
  283. package/src/cpsat/rules/max-concurrent-assignments.ts +170 -0
  284. package/src/cpsat/rules/max-consecutive-days.ts +74 -91
  285. package/src/cpsat/rules/max-days-of-week-per-period.ts +127 -0
  286. package/src/cpsat/rules/max-days-week.ts +89 -115
  287. package/src/cpsat/rules/max-hours-day.ts +64 -84
  288. package/src/cpsat/rules/max-hours-week.ts +74 -90
  289. package/src/cpsat/rules/max-shifts-day.ts +65 -85
  290. package/src/cpsat/rules/min-consecutive-days.ts +161 -127
  291. package/src/cpsat/rules/min-days-of-week-per-period.ts +144 -0
  292. package/src/cpsat/rules/min-days-week.ts +93 -91
  293. package/src/cpsat/rules/min-hours-day.ts +79 -58
  294. package/src/cpsat/rules/min-hours-week.ts +87 -62
  295. package/src/cpsat/rules/min-rest-between-shifts.ts +191 -178
  296. package/src/cpsat/rules/minimize-cost.ts +175 -188
  297. package/src/cpsat/rules/must-assign.ts +44 -81
  298. package/src/cpsat/rules/overtime-daily-multiplier.ts +158 -140
  299. package/src/cpsat/rules/overtime-daily-surcharge.ts +141 -126
  300. package/src/cpsat/rules/overtime-tiered-multiplier.ts +234 -253
  301. package/src/cpsat/rules/overtime-weekly-multiplier.ts +183 -175
  302. package/src/cpsat/rules/overtime-weekly-surcharge.ts +161 -150
  303. package/src/cpsat/rules/pattern-eligibility.ts +26 -0
  304. package/src/cpsat/rules/pattern-time.ts +30 -0
  305. package/src/cpsat/rules/registry.ts +140 -62
  306. package/src/cpsat/rules/resolver.ts +58 -30
  307. package/src/cpsat/rules/role-preference.ts +92 -0
  308. package/src/cpsat/rules/rules.types.ts +89 -17
  309. package/src/cpsat/rules/scope.types.ts +31 -26
  310. package/src/cpsat/rules/target-days-week.ts +105 -0
  311. package/src/cpsat/rules/target-peak-concurrent-assignments.ts +212 -0
  312. package/src/cpsat/rules/time-cost-surcharge.ts +116 -122
  313. package/src/cpsat/rules/time-off.ts +154 -163
  314. package/src/cpsat/rules/variables.ts +11 -0
  315. package/src/cpsat/rules.ts +43 -17
  316. package/src/cpsat/semantic-time.ts +29 -43
  317. package/src/cpsat/types.ts +53 -4
  318. package/src/cpsat/utils.ts +92 -20
  319. package/src/cpsat/validation-reporter.ts +170 -19
  320. package/src/cpsat/validation.types.ts +22 -11
  321. package/src/datetime.utils.ts +45 -44
  322. package/src/index.ts +64 -12
  323. package/src/schedule/cost.ts +40 -61
  324. package/src/schedule/coverage.ts +57 -28
  325. package/src/schedule/definition.ts +565 -76
  326. package/src/schedule/index.ts +23 -3
  327. package/src/schedule/rules.ts +631 -132
  328. package/src/schedule/shift-patterns.ts +0 -17
  329. package/src/schedule/time-periods.ts +37 -27
  330. package/src/types.ts +114 -2
@@ -1,29 +1,26 @@
1
1
  import * as z from "zod";
2
- import type { CompilationRule } from "../model-builder.js";
3
- declare const MinHoursWeekSchema: z.ZodIntersection<z.ZodObject<{
2
+ export declare const MinHoursWeekSchema: z.ZodIntersection<z.ZodObject<{
4
3
  hours: z.ZodNumber;
5
- priority: z.ZodDefault<z.ZodUnion<readonly [z.ZodLiteral<"LOW">, z.ZodLiteral<"MEDIUM">, z.ZodLiteral<"HIGH">, z.ZodLiteral<"MANDATORY">]>>;
4
+ priority: z.ZodDefault<z.ZodEnum<{
5
+ LOW: "LOW";
6
+ MEDIUM: "MEDIUM";
7
+ HIGH: "HIGH";
8
+ MANDATORY: "MANDATORY";
9
+ }>>;
6
10
  weekStartsOn: z.ZodOptional<z.ZodUnion<readonly [z.ZodLiteral<"monday">, z.ZodLiteral<"tuesday">, z.ZodLiteral<"wednesday">, z.ZodLiteral<"thursday">, z.ZodLiteral<"friday">, z.ZodLiteral<"saturday">, z.ZodLiteral<"sunday">]>>;
7
11
  }, z.core.$strip>, z.ZodType<import("./scope.types.js").EntityScopeType<"members" | "roles" | "skills">, unknown, z.core.$ZodTypeInternals<import("./scope.types.js").EntityScopeType<"members" | "roles" | "skills">, unknown>>>;
8
12
  /**
9
- * Configuration for {@link createMinHoursWeekRule}.
10
- *
11
- * - `hours` (required): minimum hours required per scheduling week
12
- * - `priority` (required): how strictly the solver enforces this rule
13
- * - `weekStartsOn` (optional): which day starts the week; defaults to {@link ModelBuilder.weekStartsOn}
14
- *
15
- * Entity scoping (at most one): `memberIds`, `roleIds`, `skillIds`
13
+ * Configuration for {@link minHoursWeekRuleDescriptor}.
16
14
  */
17
15
  export type MinHoursWeekConfig = z.infer<typeof MinHoursWeekSchema>;
18
16
  /**
19
- * Enforces a minimum total number of hours per scheduling week.
17
+ * Low-level descriptor for the `min-hours-week` rule.
20
18
  *
21
- * @param config - See {@link MinHoursWeekConfig}
22
- * @example
23
- * ```ts
24
- * createMinHoursWeekRule({ hours: 30, priority: "HIGH" });
25
- * ```
19
+ * @category Rules
26
20
  */
27
- export declare function createMinHoursWeekRule(config: MinHoursWeekConfig): CompilationRule;
28
- export {};
21
+ export declare const minHoursWeekRuleDescriptor: import("../rule-descriptor.js").RuleDescriptor<"min-hours-week", {
22
+ hours: number;
23
+ priority: "LOW" | "MEDIUM" | "HIGH" | "MANDATORY";
24
+ weekStartsOn?: "monday" | "tuesday" | "wednesday" | "thursday" | "friday" | "saturday" | "sunday" | undefined;
25
+ } & import("./scope.types.js").EntityScopeType<"members" | "roles" | "skills">>;
29
26
  //# sourceMappingURL=min-hours-week.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"min-hours-week.d.ts","sourceRoot":"","sources":["../../../src/cpsat/rules/min-hours-week.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,KAAK,CAAC;AAEzB,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAiB3D,QAAA,MAAM,kBAAkB;;;;iOAAoE,CAAC;AAE7F;;;;;;;;GAQG;AACH,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAEpE;;;;;;;;GAQG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,kBAAkB,GAAG,eAAe,CAqDlF"}
1
+ {"version":3,"file":"min-hours-week.d.ts","sourceRoot":"","sources":["../../../src/cpsat/rules/min-hours-week.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,KAAK,CAAC;AAsBzB,eAAO,MAAM,kBAAkB;;;;;;;;;iOAAoE,CAAC;AAEpG;;GAEG;AACH,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAEpE;;;;GAIG;AACH,eAAO,MAAM,0BAA0B;;;;+EAqFrC,CAAC"}
@@ -1,73 +1,91 @@
1
1
  import * as z from "zod";
2
2
  import { DayOfWeekSchema } from "../../types.js";
3
+ import { defineRuleDescriptor } from "../rule-descriptor.js";
3
4
  import { priorityToPenalty, splitIntoWeeks } from "../utils.js";
4
5
  import { PrioritySchema, entityScope, parseEntityScope, resolveMembersFromScope, ruleGroup, } from "./scope.types.js";
6
+ import { assignmentTermsForDays } from "./assignment-terms.js";
7
+ import { maxAssignableMinutesForDay, patternDurationMinutes } from "./pattern-time.js";
8
+ import { hardConstraint, reportValidation, softConstraint } from "./artifacts.js";
5
9
  const MinHoursWeekBase = z.object({
6
10
  hours: z.number().min(0),
7
11
  priority: PrioritySchema,
8
12
  weekStartsOn: DayOfWeekSchema.optional(),
9
13
  });
10
- const MinHoursWeekSchema = MinHoursWeekBase.and(entityScope(["members", "roles", "skills"]));
14
+ export const MinHoursWeekSchema = MinHoursWeekBase.and(entityScope(["members", "roles", "skills"]));
11
15
  /**
12
- * Enforces a minimum total number of hours per scheduling week.
16
+ * Low-level descriptor for the `min-hours-week` rule.
13
17
  *
14
- * @param config - See {@link MinHoursWeekConfig}
15
- * @example
16
- * ```ts
17
- * createMinHoursWeekRule({ hours: 30, priority: "HIGH" });
18
- * ```
18
+ * @category Rules
19
19
  */
20
- export function createMinHoursWeekRule(config) {
21
- const parsed = MinHoursWeekSchema.parse(config);
22
- const scope = parseEntityScope(parsed);
23
- const { hours, priority, weekStartsOn } = parsed;
24
- const minMinutes = hours * 60;
25
- const group = ruleGroup(`min-hours-week:${hours}`, `Min ${hours}h per week`, scope);
26
- return {
27
- compile(b) {
28
- if (hours <= 0)
29
- return;
30
- const members = resolveMembersFromScope(scope, b.members);
31
- const weeks = splitIntoWeeks(b.days, weekStartsOn ?? b.weekStartsOn);
32
- for (const emp of members) {
33
- for (const weekDays of weeks) {
34
- const terms = [];
35
- for (const day of weekDays) {
36
- for (const pattern of b.shiftPatterns) {
37
- if (!b.canAssign(emp, pattern))
38
- continue;
39
- if (!b.patternAvailableOnDay(pattern, day))
40
- continue;
41
- terms.push({
42
- var: b.assignment(emp.id, pattern.id, day),
43
- coeff: b.patternDuration(pattern.id),
20
+ export const minHoursWeekRuleDescriptor = defineRuleDescriptor({
21
+ name: "min-hours-week",
22
+ schema: MinHoursWeekSchema,
23
+ compile(config, ctx) {
24
+ const scope = parseEntityScope(config);
25
+ const { hours, priority, weekStartsOn } = config;
26
+ const minMinutes = hours * 60;
27
+ const group = ruleGroup(`min-hours-week:${hours}`, `Min ${hours}h per week`, scope);
28
+ const members = resolveMembersFromScope(scope, [...ctx.members]);
29
+ const weeks = splitIntoWeeks([...ctx.days], weekStartsOn ?? ctx.weekStartsOn);
30
+ const artifacts = [];
31
+ for (const member of members) {
32
+ for (const weekDays of weeks) {
33
+ const weekStart = weekDays[0];
34
+ if (!weekStart)
35
+ continue;
36
+ const terms = assignmentTermsForDays(member, weekDays, ctx.shiftPatterns, patternDurationMinutes);
37
+ if (terms.length === 0)
38
+ continue;
39
+ const description = `${member.id} min ${hours}h in week starting ${weekStart.iso}`;
40
+ const context = { memberIds: [member.id], days: weekDays.map((day) => day.iso) };
41
+ const constraintId = `min-hours-week:${member.id}:${weekStart.iso}`;
42
+ if (priority === "MANDATORY") {
43
+ artifacts.push(hardConstraint({
44
+ group,
45
+ description,
46
+ context,
47
+ validation: reportValidation(constraintId),
48
+ terms,
49
+ comparator: ">=",
50
+ targetValue: minMinutes,
51
+ }), {
52
+ kind: "pre-solve-feedback",
53
+ run(preSolveContext, reporter) {
54
+ const maxMinutes = weekDays.reduce((total, day) => total + maxAssignableMinutesForDay(member, day, preSolveContext.shiftPatterns), 0);
55
+ if (maxMinutes >= minMinutes)
56
+ return;
57
+ reporter.reportRuleError({
58
+ rule: "min-hours-week",
59
+ message: `${member.id} cannot reach ${hours}h in week starting ${weekStart.iso}; maximum possible is ${Math.round((maxMinutes / 60) * 10) / 10}h.`,
60
+ context,
61
+ suggestions: [
62
+ `Reduce the weekly minimum for ${member.id}`,
63
+ `Add longer or additional shifts in the week starting ${weekStart.iso}`,
64
+ ],
65
+ group,
44
66
  });
45
- }
46
- }
47
- if (terms.length === 0)
48
- continue;
49
- const weekLabel = weekDays[0];
50
- const constraintId = `min-hours-week:${emp.id}:${weekLabel}`;
51
- if (priority === "MANDATORY") {
52
- b.addLinear(terms, ">=", minMinutes);
53
- }
54
- else {
55
- b.addSoftLinear(terms, ">=", minMinutes, priorityToPenalty(priority), constraintId);
56
- b.reporter.trackConstraint({
57
- id: constraintId,
58
- type: "rule",
59
- rule: "min-hours-week",
60
- description: `${emp.id} min ${hours}h in week starting ${weekLabel}`,
61
- targetValue: minMinutes,
62
- comparator: ">=",
63
- day: weekLabel,
64
- context: { memberIds: [emp.id], days: weekDays },
65
- group,
66
- });
67
- }
67
+ },
68
+ });
69
+ }
70
+ else {
71
+ artifacts.push(softConstraint({
72
+ group,
73
+ description,
74
+ context,
75
+ validation: reportValidation(),
76
+ terms,
77
+ comparator: ">=",
78
+ targetValue: minMinutes,
79
+ penalty: priorityToPenalty(priority),
80
+ constraintId,
81
+ }));
68
82
  }
69
83
  }
70
- },
71
- };
72
- }
84
+ }
85
+ return {
86
+ rule: "min-hours-week",
87
+ artifacts,
88
+ };
89
+ },
90
+ });
73
91
  //# sourceMappingURL=min-hours-week.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"min-hours-week.js","sourceRoot":"","sources":["../../../src/cpsat/rules/min-hours-week.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"min-hours-week.js","sourceRoot":"","sources":["../../../src/cpsat/rules/min-hours-week.ts"],"names":[],"mappings":"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"}
@@ -1,27 +1,24 @@
1
1
  import * as z from "zod";
2
- import type { CompilationRule } from "../model-builder.js";
3
- declare const MinRestBetweenShiftsSchema: z.ZodIntersection<z.ZodObject<{
2
+ export declare const MinRestBetweenShiftsSchema: z.ZodIntersection<z.ZodObject<{
4
3
  hours: z.ZodNumber;
5
- priority: z.ZodDefault<z.ZodUnion<readonly [z.ZodLiteral<"LOW">, z.ZodLiteral<"MEDIUM">, z.ZodLiteral<"HIGH">, z.ZodLiteral<"MANDATORY">]>>;
4
+ priority: z.ZodDefault<z.ZodEnum<{
5
+ LOW: "LOW";
6
+ MEDIUM: "MEDIUM";
7
+ HIGH: "HIGH";
8
+ MANDATORY: "MANDATORY";
9
+ }>>;
6
10
  }, z.core.$strip>, z.ZodType<import("./scope.types.js").EntityScopeType<"members" | "roles" | "skills">, unknown, z.core.$ZodTypeInternals<import("./scope.types.js").EntityScopeType<"members" | "roles" | "skills">, unknown>>>;
7
11
  /**
8
- * Configuration for {@link createMinRestBetweenShiftsRule}.
9
- *
10
- * - `hours` (required): minimum rest hours required between consecutive shifts
11
- * - `priority` (required): how strictly the solver enforces this rule
12
- *
13
- * Entity scoping (at most one): `memberIds`, `roleIds`, `skillIds`
12
+ * Configuration for {@link minRestBetweenShiftsRuleDescriptor}.
14
13
  */
15
14
  export type MinRestBetweenShiftsConfig = z.infer<typeof MinRestBetweenShiftsSchema>;
16
15
  /**
17
- * Enforces a minimum rest period between any two shifts a person works.
16
+ * Low-level descriptor for the `min-rest-between-shifts` rule.
18
17
  *
19
- * @param config - See {@link MinRestBetweenShiftsConfig}
20
- * @example
21
- * ```ts
22
- * createMinRestBetweenShiftsRule({ hours: 10, priority: "MANDATORY" });
23
- * ```
18
+ * @category Rules
24
19
  */
25
- export declare function createMinRestBetweenShiftsRule(config: MinRestBetweenShiftsConfig): CompilationRule;
26
- export {};
20
+ export declare const minRestBetweenShiftsRuleDescriptor: import("../rule-descriptor.js").RuleDescriptor<"min-rest-between-shifts", {
21
+ hours: number;
22
+ priority: "LOW" | "MEDIUM" | "HIGH" | "MANDATORY";
23
+ } & import("./scope.types.js").EntityScopeType<"members" | "roles" | "skills">>;
27
24
  //# sourceMappingURL=min-rest-between-shifts.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"min-rest-between-shifts.d.ts","sourceRoot":"","sources":["../../../src/cpsat/rules/min-rest-between-shifts.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,KAAK,CAAC;AACzB,OAAO,KAAK,EAAE,eAAe,EAAyB,MAAM,qBAAqB,CAAC;AAYlF,QAAA,MAAM,0BAA0B;;;iOAKmB,CAAC;AAEpD;;;;;;;GAOG;AACH,MAAM,MAAM,0BAA0B,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,0BAA0B,CAAC,CAAC;AAEpF;;;;;;;;GAQG;AACH,wBAAgB,8BAA8B,CAC5C,MAAM,EAAE,0BAA0B,GACjC,eAAe,CAsKjB"}
1
+ {"version":3,"file":"min-rest-between-shifts.d.ts","sourceRoot":"","sources":["../../../src/cpsat/rules/min-rest-between-shifts.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,KAAK,CAAC;AAkBzB,eAAO,MAAM,0BAA0B;;;;;;;;iOAKY,CAAC;AAEpD;;GAEG;AACH,MAAM,MAAM,0BAA0B,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,0BAA0B,CAAC,CAAC;AAEpF;;;;GAIG;AACH,eAAO,MAAM,kCAAkC;;;+EAuK7C,CAAC"}
@@ -1,159 +1,169 @@
1
1
  import * as z from "zod";
2
+ import { schedulingDay } from "../../types.js";
3
+ import { defineRuleDescriptor } from "../rule-descriptor.js";
2
4
  import { normalizeEndMinutes, priorityToPenalty, timeOfDayToMinutes } from "../utils.js";
3
5
  import { PrioritySchema, entityScope, parseEntityScope, resolveMembersFromScope, ruleGroup, } from "./scope.types.js";
4
- const MinRestBetweenShiftsSchema = z
6
+ import { assignmentVar } from "./variables.js";
7
+ import { hardConstraint, reportValidation, softConstraint } from "./artifacts.js";
8
+ import { canAssignMemberToPattern, isPatternAvailableOnDay } from "./pattern-eligibility.js";
9
+ export const MinRestBetweenShiftsSchema = z
5
10
  .object({
6
11
  hours: z.number().min(0),
7
12
  priority: PrioritySchema,
8
13
  })
9
14
  .and(entityScope(["members", "roles", "skills"]));
10
15
  /**
11
- * Enforces a minimum rest period between any two shifts a person works.
16
+ * Low-level descriptor for the `min-rest-between-shifts` rule.
12
17
  *
13
- * @param config - See {@link MinRestBetweenShiftsConfig}
14
- * @example
15
- * ```ts
16
- * createMinRestBetweenShiftsRule({ hours: 10, priority: "MANDATORY" });
17
- * ```
18
+ * @category Rules
18
19
  */
19
- export function createMinRestBetweenShiftsRule(config) {
20
- const parsed = MinRestBetweenShiftsSchema.parse(config);
21
- const scope = parseEntityScope(parsed);
22
- const { hours, priority } = parsed;
23
- const minMinutes = hours * 60;
24
- const group = ruleGroup(`min-rest-between-shifts:${hours}`, `Min ${hours}h rest between shifts`, scope);
25
- return {
26
- compile(b) {
27
- const members = resolveMembersFromScope(scope, b.members);
28
- for (const emp of members) {
29
- for (let i = 0; i < b.days.length; i++) {
30
- const day1 = b.days[i];
31
- if (!day1)
20
+ export const minRestBetweenShiftsRuleDescriptor = defineRuleDescriptor({
21
+ name: "min-rest-between-shifts",
22
+ schema: MinRestBetweenShiftsSchema,
23
+ compile(config, ctx) {
24
+ const scope = parseEntityScope(config);
25
+ const { hours, priority } = config;
26
+ const minMinutes = hours * 60;
27
+ const group = ruleGroup(`min-rest-between-shifts:${hours}`, `Min ${hours}h rest between shifts`, scope);
28
+ const members = resolveMembersFromScope(scope, [...ctx.members]);
29
+ const artifacts = members.flatMap((member) => {
30
+ const memberArtifacts = [];
31
+ for (let dayIndex = 0; dayIndex < ctx.days.length; dayIndex++) {
32
+ const day1 = ctx.days[dayIndex];
33
+ if (!day1)
34
+ continue;
35
+ const checkDays = [day1];
36
+ const nextDay = ctx.days[dayIndex + 1];
37
+ if (nextDay)
38
+ checkDays.push(nextDay);
39
+ for (const pattern1 of ctx.shiftPatterns) {
40
+ if (!canAssignMemberToPattern(member, pattern1) ||
41
+ !isPatternAvailableOnDay(pattern1, day1)) {
32
42
  continue;
33
- const checkDays = [day1];
34
- const nextDay = b.days[i + 1];
35
- if (nextDay)
36
- checkDays.push(nextDay);
37
- for (const pattern1 of b.shiftPatterns) {
38
- if (!b.canAssign(emp, pattern1))
39
- continue;
40
- if (!b.patternAvailableOnDay(pattern1, day1))
41
- continue;
42
- const end1 = b.endMinutes(pattern1, day1);
43
- for (const day2 of checkDays) {
44
- if (!day2)
43
+ }
44
+ const end1 = patternEndMinutes(pattern1);
45
+ for (const day2 of checkDays) {
46
+ for (const pattern2 of ctx.shiftPatterns) {
47
+ if (!canAssignMemberToPattern(member, pattern2) ||
48
+ !isPatternAvailableOnDay(pattern2, day2) ||
49
+ (day1.iso === day2.iso && pattern1.id === pattern2.id)) {
45
50
  continue;
46
- for (const pattern2 of b.shiftPatterns) {
47
- if (!b.canAssign(emp, pattern2))
48
- continue;
49
- if (!b.patternAvailableOnDay(pattern2, day2))
50
- continue;
51
- if (day1 === day2 && pattern1.id === pattern2.id)
52
- continue;
53
- const start2 = b.startMinutes(pattern2, day2);
54
- const gap = start2 - end1;
55
- if (gap >= 0 && gap < minMinutes) {
56
- const var1 = b.assignment(emp.id, pattern1.id, day1);
57
- const var2 = b.assignment(emp.id, pattern2.id, day2);
58
- if (priority === "MANDATORY") {
59
- b.addLinear([
60
- { var: var1, coeff: 1 },
61
- { var: var2, coeff: 1 },
62
- ], "<=", 1);
63
- }
64
- else {
65
- const conflictVar = b.boolVar(`rest_conflict_${emp.id}_${pattern1.id}_${day1}_${pattern2.id}_${day2}`);
66
- b.addLinear([
67
- { var: var1, coeff: 1 },
68
- { var: var2, coeff: 1 },
69
- { var: conflictVar, coeff: -1 },
70
- ], "<=", 1);
71
- b.addLinear([
72
- { var: conflictVar, coeff: 1 },
73
- { var: var1, coeff: -1 },
74
- ], "<=", 0);
75
- b.addLinear([
76
- { var: conflictVar, coeff: 1 },
77
- { var: var2, coeff: -1 },
78
- ], "<=", 0);
79
- b.addPenalty(conflictVar, priorityToPenalty(priority));
80
- }
81
- }
51
+ }
52
+ const start2 = dayGapMinutes(day1, day2) + timeOfDayToMinutes(pattern2.startTime);
53
+ const gap = start2 - end1;
54
+ if (gap < 0 || gap >= minMinutes)
55
+ continue;
56
+ const description = `${member.id} needs ${hours}h rest between ${pattern1.id} on ${day1.iso} and ${pattern2.id} on ${day2.iso}`;
57
+ const context = { memberIds: [member.id], days: [day1.iso, day2.iso] };
58
+ const constraintId = `min-rest-between-shifts:${member.id}:${pattern1.id}:${day1.iso}:${pattern2.id}:${day2.iso}`;
59
+ const terms = [
60
+ { var: assignmentVar(member.id, pattern1.id, day1.iso), coeff: 1 },
61
+ { var: assignmentVar(member.id, pattern2.id, day2.iso), coeff: 1 },
62
+ ];
63
+ if (priority === "MANDATORY") {
64
+ memberArtifacts.push(hardConstraint({
65
+ group,
66
+ description,
67
+ context,
68
+ validation: reportValidation(constraintId),
69
+ terms,
70
+ comparator: "<=",
71
+ targetValue: 1,
72
+ }));
73
+ }
74
+ else {
75
+ memberArtifacts.push(softConstraint({
76
+ group,
77
+ description,
78
+ context,
79
+ validation: reportValidation(),
80
+ terms,
81
+ comparator: "<=",
82
+ targetValue: 1,
83
+ penalty: priorityToPenalty(priority),
84
+ constraintId,
85
+ }));
82
86
  }
83
87
  }
84
88
  }
85
89
  }
86
90
  }
87
- },
88
- validate(assignments, reporter, context) {
89
- if (priority === "MANDATORY")
90
- return;
91
- const members = resolveMembersFromScope(scope, context.members);
92
- if (members.length === 0)
93
- return;
94
- const memberIds = new Set(members.map((m) => m.id));
95
- // Group assignments by member, sort by day then start time
96
- const byMember = new Map();
97
- for (const a of assignments) {
98
- if (!memberIds.has(a.memberId))
99
- continue;
100
- const list = byMember.get(a.memberId) ?? [];
101
- list.push(a);
102
- byMember.set(a.memberId, list);
103
- }
104
- for (const [memberId, memberAssignments] of byMember) {
105
- const sorted = memberAssignments.toSorted((a, b) => {
106
- if (a.day !== b.day)
107
- return a.day < b.day ? -1 : 1;
108
- return timeOfDayToMinutes(a.startTime) - timeOfDayToMinutes(b.startTime);
109
- });
110
- let violated = false;
111
- for (let i = 0; i < sorted.length - 1; i++) {
112
- const current = sorted[i];
113
- const next = sorted[i + 1];
114
- const currentEndMin = timeOfDayToMinutes(current.endTime);
115
- const normalizedEnd = normalizeEndMinutes(timeOfDayToMinutes(current.startTime), currentEndMin);
116
- const nextStartMin = timeOfDayToMinutes(next.startTime);
117
- // Calculate gap considering day boundaries
118
- let gap;
119
- if (current.day === next.day) {
120
- gap = nextStartMin - normalizedEnd;
121
- }
122
- else {
123
- // Different days: account for the day boundary
124
- const dayDiff = daysBetween(current.day, next.day);
125
- gap = dayDiff * 24 * 60 - normalizedEnd + nextStartMin;
126
- }
127
- if (gap >= 0 && gap < minMinutes) {
128
- reporter.reportRuleViolation({
129
- rule: "min-rest-between-shifts",
130
- message: `${memberId} has ${Math.round((gap / 60) * 10) / 10}h rest between shifts on ${current.day} and ${next.day}, need ${hours}h`,
131
- context: { memberIds: [memberId], days: [current.day, next.day] },
132
- shortfall: minMinutes - gap,
133
- group,
134
- });
135
- violated = true;
136
- }
137
- }
138
- if (!violated && sorted.length > 1) {
139
- reporter.reportRulePassed({
140
- rule: "min-rest-between-shifts",
141
- message: `${memberId} has ${hours}h+ rest between all shifts`,
142
- context: {
143
- memberIds: [memberId],
144
- days: [...new Set(sorted.map((a) => a.day))],
145
- },
146
- group,
147
- });
148
- }
149
- }
150
- },
151
- };
91
+ return memberArtifacts;
92
+ });
93
+ const validatorArtifacts = priority === "MANDATORY"
94
+ ? []
95
+ : [
96
+ {
97
+ kind: "post-solve-feedback",
98
+ run(assignments, reporter, validationContext) {
99
+ const validatorMembers = resolveMembersFromScope(scope, [
100
+ ...validationContext.members,
101
+ ]);
102
+ if (validatorMembers.length === 0)
103
+ return;
104
+ const dayLookup = new Map(validationContext.days.map((day) => [day.iso, day]));
105
+ const memberIds = new Set(validatorMembers.map((member) => member.id));
106
+ const byMember = new Map();
107
+ for (const assignment of assignments) {
108
+ if (!memberIds.has(assignment.memberId))
109
+ continue;
110
+ const list = byMember.get(assignment.memberId) ?? [];
111
+ list.push(assignment);
112
+ byMember.set(assignment.memberId, list);
113
+ }
114
+ for (const [memberId, memberAssignments] of byMember) {
115
+ const sorted = [...memberAssignments].toSorted((left, right) => {
116
+ if (left.day !== right.day)
117
+ return left.day < right.day ? -1 : 1;
118
+ return timeOfDayToMinutes(left.startTime) - timeOfDayToMinutes(right.startTime);
119
+ });
120
+ let violated = false;
121
+ for (let index = 0; index < sorted.length - 1; index++) {
122
+ const current = sorted[index];
123
+ const next = sorted[index + 1];
124
+ const currentEnd = normalizeEndMinutes(timeOfDayToMinutes(current.startTime), timeOfDayToMinutes(current.endTime));
125
+ const nextStart = timeOfDayToMinutes(next.startTime);
126
+ const gap = current.day === next.day
127
+ ? nextStart - currentEnd
128
+ : daysBetween(current.day, next.day, dayLookup) * 24 * 60 -
129
+ currentEnd +
130
+ nextStart;
131
+ if (gap < 0 || gap >= minMinutes)
132
+ continue;
133
+ violated = true;
134
+ }
135
+ if (!violated && sorted.length > 1) {
136
+ reporter.reportRulePassed({
137
+ rule: "min-rest-between-shifts",
138
+ message: `${memberId} has ${hours}h+ rest between all shifts`,
139
+ context: {
140
+ memberIds: [memberId],
141
+ days: [...new Set(sorted.map((assignment) => assignment.day))],
142
+ },
143
+ group,
144
+ });
145
+ }
146
+ }
147
+ },
148
+ },
149
+ ];
150
+ return {
151
+ rule: "min-rest-between-shifts",
152
+ artifacts: [...artifacts, ...validatorArtifacts],
153
+ };
154
+ },
155
+ });
156
+ function patternEndMinutes(pattern) {
157
+ return normalizeEndMinutes(timeOfDayToMinutes(pattern.startTime), timeOfDayToMinutes(pattern.endTime));
158
+ }
159
+ function dayGapMinutes(day1, day2) {
160
+ return (day2.epochDay - day1.epochDay) * 24 * 60;
152
161
  }
153
- /** Compute day difference from YYYY-MM-DD strings. */
154
- function daysBetween(day1, day2) {
155
- const d1 = new Date(`${day1}T00:00:00Z`);
156
- const d2 = new Date(`${day2}T00:00:00Z`);
157
- return Math.round((d2.getTime() - d1.getTime()) / (24 * 60 * 60 * 1000));
162
+ function daysBetween(day1, day2, lookup) {
163
+ const left = lookup.get(day1);
164
+ const right = lookup.get(day2);
165
+ if (left && right)
166
+ return right.epochDay - left.epochDay;
167
+ return schedulingDay(day2).epochDay - schedulingDay(day1).epochDay;
158
168
  }
159
169
  //# sourceMappingURL=min-rest-between-shifts.js.map