dabke 0.82.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 (341) hide show
  1. package/CHANGELOG.md +44 -0
  2. package/README.md +22 -24
  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 -21
  66. package/dist/cpsat/rules/index.d.ts.map +1 -1
  67. package/dist/cpsat/rules/index.js +30 -21
  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 +30 -0
  86. package/dist/cpsat/rules/max-days-week.d.ts.map +1 -0
  87. package/dist/cpsat/rules/max-days-week.js +83 -0
  88. package/dist/cpsat/rules/max-days-week.js.map +1 -0
  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 +21 -0
  110. package/dist/cpsat/rules/min-days-week.d.ts.map +1 -0
  111. package/dist/cpsat/rules/min-days-week.js +95 -0
  112. package/dist/cpsat/rules/min-days-week.js.map +1 -0
  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 +12 -0
  130. package/dist/cpsat/rules/must-assign.d.ts.map +1 -0
  131. package/dist/cpsat/rules/must-assign.js +54 -0
  132. package/dist/cpsat/rules/must-assign.js.map +1 -0
  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 -27
  162. package/dist/cpsat/rules/registry.d.ts.map +1 -1
  163. package/dist/cpsat/rules/registry.js +98 -31
  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 +93 -17
  174. package/dist/cpsat/rules/rules.types.d.ts.map +1 -1
  175. package/dist/cpsat/rules/scope.types.d.ts +25 -12
  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 +15 -9
  226. package/dist/index.d.ts.map +1 -1
  227. package/dist/index.js +11 -4
  228. package/dist/index.js.map +1 -1
  229. package/dist/schedule/cost.d.ts +192 -0
  230. package/dist/schedule/cost.d.ts.map +1 -0
  231. package/dist/schedule/cost.js +151 -0
  232. package/dist/schedule/cost.js.map +1 -0
  233. package/dist/schedule/coverage.d.ts +114 -0
  234. package/dist/schedule/coverage.d.ts.map +1 -0
  235. package/dist/schedule/coverage.js +56 -0
  236. package/dist/schedule/coverage.js.map +1 -0
  237. package/dist/schedule/definition.d.ts +346 -0
  238. package/dist/schedule/definition.d.ts.map +1 -0
  239. package/dist/schedule/definition.js +668 -0
  240. package/dist/schedule/definition.js.map +1 -0
  241. package/dist/schedule/index.d.ts +67 -0
  242. package/dist/schedule/index.d.ts.map +1 -0
  243. package/dist/schedule/index.js +69 -0
  244. package/dist/schedule/index.js.map +1 -0
  245. package/dist/schedule/rules.d.ts +678 -0
  246. package/dist/schedule/rules.d.ts.map +1 -0
  247. package/dist/schedule/rules.js +554 -0
  248. package/dist/schedule/rules.js.map +1 -0
  249. package/dist/schedule/shift-patterns.d.ts +17 -0
  250. package/dist/schedule/shift-patterns.d.ts.map +1 -0
  251. package/dist/schedule/shift-patterns.js +24 -0
  252. package/dist/schedule/shift-patterns.js.map +1 -0
  253. package/dist/schedule/time-periods.d.ts +79 -0
  254. package/dist/schedule/time-periods.d.ts.map +1 -0
  255. package/dist/schedule/time-periods.js +101 -0
  256. package/dist/schedule/time-periods.js.map +1 -0
  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 -14
  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 -21
  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 +117 -0
  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 +122 -0
  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 +71 -0
  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 -56
  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 +92 -17
  309. package/src/cpsat/rules/scope.types.ts +32 -27
  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 +72 -15
  323. package/src/schedule/cost.ts +221 -0
  324. package/src/schedule/coverage.ts +164 -0
  325. package/src/schedule/definition.ts +1447 -0
  326. package/src/schedule/index.ts +132 -0
  327. package/src/schedule/rules.ts +1028 -0
  328. package/src/schedule/shift-patterns.ts +29 -0
  329. package/src/schedule/time-periods.ts +120 -0
  330. package/src/types.ts +114 -2
  331. package/dist/llms.d.ts +0 -2
  332. package/dist/llms.d.ts.map +0 -1
  333. package/dist/llms.js +0 -3
  334. package/dist/llms.js.map +0 -1
  335. package/dist/schedule.d.ts +0 -917
  336. package/dist/schedule.d.ts.map +0 -1
  337. package/dist/schedule.js +0 -1323
  338. package/dist/schedule.js.map +0 -1
  339. package/llms.txt +0 -758
  340. package/src/llms.ts +0 -3
  341. package/src/schedule.ts +0 -1960
@@ -1,5 +1,6 @@
1
1
  import * as z from "zod";
2
- import type { CompilationRule } from "../model-builder.js";
2
+ import { defineRuleDescriptor } from "../rule-descriptor.js";
3
+ import type { RuleArtifact } from "../rule-descriptor.js";
3
4
  import { priorityToPenalty } from "../utils.js";
4
5
  import {
5
6
  PrioritySchema,
@@ -8,8 +9,18 @@ import {
8
9
  resolveMembersFromScope,
9
10
  ruleGroup,
10
11
  } from "./scope.types.js";
11
-
12
- const MinConsecutiveDaysSchema = z
12
+ import { assignmentVarsForDay } from "./assignment-terms.js";
13
+ import { assignedDayStartVariableName } from "./variables.js";
14
+ import {
15
+ boolVariable,
16
+ hardConstraint,
17
+ reportValidation,
18
+ skipValidation,
19
+ softConstraint,
20
+ } from "./artifacts.js";
21
+ import { buildAssignedDayIndicator } from "./assigned-day.js";
22
+
23
+ export const MinConsecutiveDaysSchema = z
13
24
  .object({
14
25
  days: z.number().min(0),
15
26
  priority: PrioritySchema,
@@ -17,143 +28,166 @@ const MinConsecutiveDaysSchema = z
17
28
  .and(entityScope(["members", "roles", "skills"]));
18
29
 
19
30
  /**
20
- * Configuration for {@link createMinConsecutiveDaysRule}.
21
- *
22
- * - `days` (required): minimum consecutive days required once a person starts working
23
- * - `priority` (required): how strictly the solver enforces this rule
24
- *
25
- * Entity scoping (at most one): `memberIds`, `roleIds`, `skillIds`
31
+ * Configuration for {@link minConsecutiveDaysRuleDescriptor}.
26
32
  */
27
33
  export type MinConsecutiveDaysConfig = z.infer<typeof MinConsecutiveDaysSchema>;
28
34
 
29
35
  /**
30
- * Requires that once a person starts working, they continue for a minimum
31
- * number of consecutive days.
36
+ * Low-level descriptor for the `min-consecutive-days` rule.
32
37
  *
33
- * @param config - See {@link MinConsecutiveDaysConfig}
34
- * @example
35
- * ```ts
36
- * createMinConsecutiveDaysRule({ days: 3, priority: "MANDATORY" });
37
- * ```
38
+ * @remarks
39
+ * Once an assignment streak starts, this rule requires it to continue for at
40
+ * least the configured number of assigned days.
41
+ *
42
+ * @category Rules
38
43
  */
39
- export function createMinConsecutiveDaysRule(config: MinConsecutiveDaysConfig): CompilationRule {
40
- const parsed = MinConsecutiveDaysSchema.parse(config);
41
- const scope = parseEntityScope(parsed);
42
- const { days, priority } = parsed;
43
- const group = ruleGroup(`min-consecutive-days:${days}`, `Min ${days} consecutive days`, scope);
44
-
45
- return {
46
- compile(b) {
47
- if (days <= 1) return;
48
-
49
- const members = resolveMembersFromScope(scope, b.members);
50
-
51
- for (const emp of members) {
52
- const worksByDay: string[] = [];
53
-
54
- for (const day of b.days) {
55
- const worksVar = b.boolVar(`works_${emp.id}_${day}`);
56
- worksByDay.push(worksVar);
57
-
58
- const dayAssignments = b.shiftPatterns
59
- .filter((p) => b.canAssign(emp, p) && b.patternAvailableOnDay(p, day))
60
- .map((p) => b.assignment(emp.id, p.id, day));
61
-
62
- if (dayAssignments.length === 0) {
63
- b.addLinear([{ var: worksVar, coeff: 1 }], "==", 0);
64
- } else {
65
- for (const assignVar of dayAssignments) {
66
- b.addLinear(
67
- [
68
- { var: worksVar, coeff: 1 },
69
- { var: assignVar, coeff: -1 },
70
- ],
71
- ">=",
72
- 0,
73
- );
74
- }
75
- b.addLinear(
76
- [{ var: worksVar, coeff: 1 }, ...dayAssignments.map((v) => ({ var: v, coeff: -1 }))],
77
- "<=",
78
- 0,
79
- );
80
- }
81
- }
82
-
83
- for (let i = 0; i < b.days.length; i++) {
84
- const dayLabel = b.days[i];
85
- if (!dayLabel) continue;
86
-
87
- const worksToday = worksByDay[i];
88
- if (!worksToday) continue;
89
- const worksYesterday = i > 0 ? worksByDay[i - 1] : undefined;
90
- const startVar = b.boolVar(`work_start_${emp.id}_${dayLabel}`);
91
-
92
- b.addLinear(
93
- [
44
+ export const minConsecutiveDaysRuleDescriptor = defineRuleDescriptor({
45
+ name: "min-consecutive-days",
46
+ schema: MinConsecutiveDaysSchema,
47
+ compile(config, ctx) {
48
+ const scope = parseEntityScope(config);
49
+ const { days, priority } = config;
50
+ const group = ruleGroup(`min-consecutive-days:${days}`, `Min ${days} consecutive days`, scope);
51
+ if (days <= 1) {
52
+ return { rule: "min-consecutive-days", artifacts: [] };
53
+ }
54
+
55
+ const members = resolveMembersFromScope(scope, [...ctx.members]);
56
+ const artifacts = members.flatMap((member) => {
57
+ const supportArtifacts = ctx.days.flatMap(
58
+ (day) =>
59
+ buildAssignedDayIndicator({
60
+ memberId: member.id,
61
+ day,
62
+ assignmentVars: assignmentVarsForDay(member, day, ctx.shiftPatterns),
63
+ variableName: `assigned_${member.id}_${day.iso}`,
64
+ }).artifacts,
65
+ );
66
+
67
+ const startArtifacts = ctx.days.flatMap((day, index) => {
68
+ const assignedToday = `assigned_${member.id}_${day.iso}`;
69
+ const assignedYesterday =
70
+ index > 0 ? `assigned_${member.id}_${ctx.days[index - 1]!.iso}` : undefined;
71
+ const startVar = assignedDayStartVariableName(member.id, day.iso);
72
+ const artifactsForDay: RuleArtifact[] = [boolVariable(startVar)];
73
+
74
+ artifactsForDay.push(
75
+ hardConstraint({
76
+ description: `${startVar} implies an assignment on ${day.iso}`,
77
+ validation: skipValidation(
78
+ "scaffolding",
79
+ "This helper variable only marks the start of an assignment streak when the member has an assignment that day.",
80
+ ),
81
+ context: { memberIds: [member.id], days: [day.iso] },
82
+ terms: [
94
83
  { var: startVar, coeff: 1 },
95
- { var: worksToday, coeff: -1 },
84
+ { var: assignedToday, coeff: -1 },
96
85
  ],
97
- "<=",
98
- 0,
99
- );
100
- if (worksYesterday) {
101
- b.addLinear(
102
- [
86
+ comparator: "<=",
87
+ targetValue: 0,
88
+ }),
89
+ );
90
+
91
+ if (assignedYesterday) {
92
+ artifactsForDay.push(
93
+ hardConstraint({
94
+ description: `${startVar} only when previous day is unassigned`,
95
+ validation: skipValidation(
96
+ "scaffolding",
97
+ "This helper variable must stay off when the previous day already belongs to the same assignment streak.",
98
+ ),
99
+ context: { memberIds: [member.id], days: [ctx.days[index - 1]!.iso, day.iso] },
100
+ terms: [
103
101
  { var: startVar, coeff: 1 },
104
- { var: worksYesterday, coeff: 1 },
102
+ { var: assignedYesterday, coeff: 1 },
105
103
  ],
106
- "<=",
107
- 1,
108
- );
109
- b.addLinear(
110
- [
104
+ comparator: "<=",
105
+ targetValue: 1,
106
+ }),
107
+ );
108
+ artifactsForDay.push(
109
+ hardConstraint({
110
+ description: `${startVar} activates on a new assignment streak`,
111
+ validation: skipValidation(
112
+ "scaffolding",
113
+ "This helper variable identifies new assignment streak boundaries for the consecutive-days window calculation.",
114
+ ),
115
+ context: { memberIds: [member.id], days: [ctx.days[index - 1]!.iso, day.iso] },
116
+ terms: [
111
117
  { var: startVar, coeff: 1 },
112
- { var: worksYesterday, coeff: 1 },
113
- { var: worksToday, coeff: -1 },
118
+ { var: assignedYesterday, coeff: 1 },
119
+ { var: assignedToday, coeff: -1 },
114
120
  ],
115
- ">=",
116
- 0,
117
- );
118
- } else {
119
- b.addLinear(
120
- [
121
+ comparator: ">=",
122
+ targetValue: 0,
123
+ }),
124
+ );
125
+ } else {
126
+ artifactsForDay.push(
127
+ hardConstraint({
128
+ description: `${startVar} matches first-day assignment state`,
129
+ validation: skipValidation(
130
+ "scaffolding",
131
+ "On the first day of the horizon, the helper variable matches whether a new streak starts that day.",
132
+ ),
133
+ context: { memberIds: [member.id], days: [day.iso] },
134
+ terms: [
121
135
  { var: startVar, coeff: 1 },
122
- { var: worksToday, coeff: -1 },
136
+ { var: assignedToday, coeff: -1 },
123
137
  ],
124
- ">=",
125
- 0,
126
- );
127
- }
128
-
129
- const window = worksByDay.slice(i, i + days).filter(Boolean) as string[];
130
- if (window.length === 0) continue;
131
-
132
- const terms = [
133
- ...window.map((v) => ({ var: v, coeff: 1 })),
134
- { var: startVar, coeff: -days },
135
- ];
136
-
137
- const constraintId = `min-consecutive-days:${emp.id}:${dayLabel}`;
138
-
139
- if (priority === "MANDATORY") {
140
- b.addLinear(terms, ">=", 0);
141
- } else {
142
- b.addSoftLinear(terms, ">=", 0, priorityToPenalty(priority), constraintId);
143
- b.reporter.trackConstraint({
144
- id: constraintId,
145
- type: "rule",
146
- rule: "min-consecutive-days",
147
- description: `${emp.id} min ${days} consecutive days from ${dayLabel}`,
148
- targetValue: 0,
149
138
  comparator: ">=",
150
- day: dayLabel,
151
- context: { memberIds: [emp.id], days: b.days.slice(i, i + days) },
152
- group,
153
- });
154
- }
139
+ targetValue: 0,
140
+ }),
141
+ );
155
142
  }
156
- }
157
- },
158
- };
159
- }
143
+
144
+ const windowDays = ctx.days.slice(index, index + days);
145
+ if (windowDays.length === 0) return artifactsForDay;
146
+
147
+ const description = `${member.id} min ${days} consecutive days from ${day.iso}`;
148
+ const context = { memberIds: [member.id], days: windowDays.map((entry) => entry.iso) };
149
+ const constraintId = `min-consecutive-days:${member.id}:${day.iso}`;
150
+ const terms = [
151
+ ...windowDays.map((windowDay) => ({
152
+ var: `assigned_${member.id}_${windowDay.iso}`,
153
+ coeff: 1,
154
+ })),
155
+ { var: startVar, coeff: -days },
156
+ ];
157
+
158
+ artifactsForDay.push(
159
+ priority === "MANDATORY"
160
+ ? hardConstraint({
161
+ group,
162
+ description,
163
+ context,
164
+ validation: reportValidation(constraintId),
165
+ terms,
166
+ comparator: ">=",
167
+ targetValue: 0,
168
+ })
169
+ : softConstraint({
170
+ group,
171
+ description,
172
+ context,
173
+ validation: reportValidation(),
174
+ terms,
175
+ comparator: ">=",
176
+ targetValue: 0,
177
+ penalty: priorityToPenalty(priority),
178
+ constraintId,
179
+ }),
180
+ );
181
+
182
+ return artifactsForDay;
183
+ });
184
+
185
+ return supportArtifacts.concat(startArtifacts);
186
+ });
187
+
188
+ return {
189
+ rule: "min-consecutive-days",
190
+ artifacts,
191
+ };
192
+ },
193
+ });
@@ -0,0 +1,144 @@
1
+ import * as z from "zod";
2
+ import { DayOfWeekSchema } from "../../types.js";
3
+ import { defineRuleDescriptor } from "../rule-descriptor.js";
4
+ import type { RuleCompileContext } from "../rule-descriptor.js";
5
+ import type { ValidationReporter } from "../validation-reporter.js";
6
+ import { groupWeekChunks, priorityToPenalty, splitIntoMonths } from "../utils.js";
7
+ import {
8
+ PrioritySchema,
9
+ entityScope,
10
+ parseEntityScope,
11
+ resolveMembersFromScope,
12
+ ruleGroup,
13
+ } from "./scope.types.js";
14
+ import { assignmentVarsForDay } from "./assignment-terms.js";
15
+ import { hasAnyAssignablePattern } from "./pattern-eligibility.js";
16
+ import { assignedDayVariableName } from "./variables.js";
17
+ import { hardConstraint, reportValidation, softConstraint } from "./artifacts.js";
18
+ import { buildAssignedDayIndicator } from "./assigned-day.js";
19
+
20
+ const PeriodSchema = z.discriminatedUnion("type", [
21
+ z.object({ type: z.literal("weeks"), value: z.number().int().min(1) }),
22
+ z.object({ type: z.literal("months"), value: z.number().int().min(1) }),
23
+ ]);
24
+
25
+ const MinDaysOfWeekPerPeriodBase = z.object({
26
+ days: z.number().int().min(0),
27
+ dayOfWeek: z.array(DayOfWeekSchema).nonempty(),
28
+ period: PeriodSchema,
29
+ priority: PrioritySchema,
30
+ });
31
+
32
+ export const MinDaysOfWeekPerPeriodSchema = MinDaysOfWeekPerPeriodBase.and(
33
+ entityScope(["members", "roles", "skills"]),
34
+ );
35
+
36
+ /**
37
+ * Configuration for {@link minDaysOfWeekPerPeriodRuleDescriptor}.
38
+ */
39
+ export type MinDaysOfWeekPerPeriodConfig = z.infer<typeof MinDaysOfWeekPerPeriodSchema>;
40
+
41
+ export const minDaysOfWeekPerPeriodRuleDescriptor = defineRuleDescriptor({
42
+ name: "min-days-of-week-per-period",
43
+ schema: MinDaysOfWeekPerPeriodSchema,
44
+ compile(config, ctx) {
45
+ const entityScopeValue = parseEntityScope(config);
46
+ const { days, dayOfWeek, period, priority } = config;
47
+ const dowLabel = dayOfWeek.toSorted().join(",");
48
+ const periodLabel = `${period.value}${period.type === "weeks" ? "w" : "m"}`;
49
+ const group = ruleGroup(
50
+ `min-days-of-week-per-period:${days}:${dowLabel}:${periodLabel}`,
51
+ `Min ${days} ${dowLabel} per ${period.value} ${period.type}`,
52
+ entityScopeValue,
53
+ );
54
+
55
+ const targetMembers = resolveMembersFromScope(entityScopeValue, [...ctx.members]);
56
+ const targetDows = new Set(dayOfWeek);
57
+ const chunks =
58
+ period.type === "weeks"
59
+ ? groupWeekChunks([...ctx.days], period.value, ctx.weekStartsOn)
60
+ : splitIntoMonths([...ctx.days], period.value);
61
+
62
+ const artifacts = targetMembers.flatMap((member) =>
63
+ chunks.flatMap((chunkDays) => {
64
+ const chunkStart = chunkDays[0];
65
+ if (!chunkStart) return [];
66
+
67
+ const matchingDays = chunkDays.filter((day) => targetDows.has(day.dayOfWeek));
68
+ if (matchingDays.length === 0) return [];
69
+
70
+ const supportArtifacts = matchingDays.flatMap(
71
+ (day) =>
72
+ buildAssignedDayIndicator({
73
+ memberId: member.id,
74
+ day,
75
+ assignmentVars: assignmentVarsForDay(member, day, ctx.shiftPatterns),
76
+ }).artifacts,
77
+ );
78
+
79
+ const assignedDayVars = matchingDays
80
+ .filter((day) => assignmentVarsForDay(member, day, ctx.shiftPatterns).length > 0)
81
+ .map((day) => assignedDayVariableName(member.id, day.iso));
82
+ if (assignedDayVars.length === 0) return supportArtifacts;
83
+
84
+ const description = `${member.id} min ${days} ${dowLabel} in period starting ${chunkStart.iso}`;
85
+ const context = { memberIds: [member.id], days: matchingDays.map((day) => day.iso) };
86
+ const constraintId = `min-days-of-week-per-period:${member.id}:${chunkStart.iso}`;
87
+ const terms = assignedDayVars.map((varName) => ({ var: varName, coeff: 1 }));
88
+
89
+ const finalArtifacts =
90
+ priority === "MANDATORY"
91
+ ? [
92
+ hardConstraint({
93
+ group,
94
+ description,
95
+ context,
96
+ validation: reportValidation(constraintId),
97
+ terms,
98
+ comparator: ">=",
99
+ targetValue: days,
100
+ }),
101
+ {
102
+ kind: "pre-solve-feedback" as const,
103
+ run(_preSolveContext: RuleCompileContext, reporter: ValidationReporter) {
104
+ const possibleDays = matchingDays.filter((day) =>
105
+ hasAnyAssignablePattern(member, day, ctx.shiftPatterns),
106
+ ).length;
107
+ if (possibleDays >= days) return;
108
+ reporter.reportRuleError({
109
+ rule: "min-days-of-week-per-period",
110
+ message: `${member.id} cannot reach ${days} ${dowLabel} assignments in the period starting ${chunkStart.iso}; only ${possibleDays} matching day${possibleDays === 1 ? " is" : "s are"} assignable.`,
111
+ context,
112
+ suggestions: [
113
+ `Reduce the ${dowLabel} minimum in this period`,
114
+ `Add more assignable ${dowLabel} shifts in the period starting ${chunkStart.iso}`,
115
+ ],
116
+ group,
117
+ });
118
+ },
119
+ },
120
+ ]
121
+ : [
122
+ softConstraint({
123
+ group,
124
+ description,
125
+ context,
126
+ validation: reportValidation(),
127
+ terms,
128
+ comparator: ">=",
129
+ targetValue: days,
130
+ penalty: priorityToPenalty(priority),
131
+ constraintId,
132
+ }),
133
+ ];
134
+
135
+ return supportArtifacts.concat(finalArtifacts);
136
+ }),
137
+ );
138
+
139
+ return {
140
+ rule: "min-days-of-week-per-period",
141
+ artifacts,
142
+ };
143
+ },
144
+ });
@@ -0,0 +1,122 @@
1
+ import * as z from "zod";
2
+ import { DayOfWeekSchema } from "../../types.js";
3
+ import { defineRuleDescriptor } from "../rule-descriptor.js";
4
+ import type { RuleCompileContext } from "../rule-descriptor.js";
5
+ import type { ValidationReporter } from "../validation-reporter.js";
6
+ import { priorityToPenalty, splitIntoWeeks } from "../utils.js";
7
+ import {
8
+ PrioritySchema,
9
+ entityScope,
10
+ parseEntityScope,
11
+ resolveMembersFromScope,
12
+ ruleGroup,
13
+ } from "./scope.types.js";
14
+ import { assignmentVarsForDay } from "./assignment-terms.js";
15
+ import { hasAnyAssignablePattern } from "./pattern-eligibility.js";
16
+ import { assignedDayVariableName } from "./variables.js";
17
+ import { hardConstraint, reportValidation, softConstraint } from "./artifacts.js";
18
+ import { buildAssignedDayIndicator } from "./assigned-day.js";
19
+
20
+ const MinDaysWeekBase = z.object({
21
+ days: z.number().int().min(0),
22
+ priority: PrioritySchema,
23
+ weekStartsOn: DayOfWeekSchema.optional(),
24
+ });
25
+
26
+ export const MinDaysWeekSchema = MinDaysWeekBase.and(entityScope(["members", "roles", "skills"]));
27
+
28
+ /**
29
+ * Configuration for {@link minDaysWeekRuleDescriptor}.
30
+ */
31
+ export type MinDaysWeekConfig = z.infer<typeof MinDaysWeekSchema>;
32
+
33
+ export const minDaysWeekRuleDescriptor = defineRuleDescriptor({
34
+ name: "min-days-week",
35
+ schema: MinDaysWeekSchema,
36
+ compile(config, ctx) {
37
+ const scope = parseEntityScope(config);
38
+ const { days, priority, weekStartsOn } = config;
39
+ const group = ruleGroup(`min-days-week:${days}`, `Min ${days}d per week`, scope);
40
+ const members = resolveMembersFromScope(scope, [...ctx.members]);
41
+ const weeks = splitIntoWeeks([...ctx.days], weekStartsOn ?? ctx.weekStartsOn);
42
+
43
+ const artifacts = members.flatMap((member) =>
44
+ weeks.flatMap((weekDays) => {
45
+ const weekStart = weekDays[0];
46
+ if (!weekStart) return [];
47
+
48
+ const supportArtifacts = weekDays.flatMap(
49
+ (day) =>
50
+ buildAssignedDayIndicator({
51
+ memberId: member.id,
52
+ day,
53
+ assignmentVars: assignmentVarsForDay(member, day, ctx.shiftPatterns),
54
+ }).artifacts,
55
+ );
56
+
57
+ const assignedDayVars = weekDays
58
+ .filter((day) => assignmentVarsForDay(member, day, ctx.shiftPatterns).length > 0)
59
+ .map((day) => assignedDayVariableName(member.id, day.iso));
60
+ if (assignedDayVars.length === 0) return supportArtifacts;
61
+
62
+ const description = `${member.id} min ${days}d in week starting ${weekStart.iso}`;
63
+ const context = { memberIds: [member.id], days: weekDays.map((day) => day.iso) };
64
+ const constraintId = `min-days-week:${member.id}:${weekStart.iso}`;
65
+ const terms = assignedDayVars.map((varName) => ({ var: varName, coeff: 1 }));
66
+
67
+ const finalArtifacts =
68
+ priority === "MANDATORY"
69
+ ? [
70
+ hardConstraint({
71
+ group,
72
+ description,
73
+ context,
74
+ validation: reportValidation(constraintId),
75
+ terms,
76
+ comparator: ">=",
77
+ targetValue: days,
78
+ }),
79
+ {
80
+ kind: "pre-solve-feedback" as const,
81
+ run(_preSolveContext: RuleCompileContext, reporter: ValidationReporter) {
82
+ const possibleDays = weekDays.filter((day) =>
83
+ hasAnyAssignablePattern(member, day, ctx.shiftPatterns),
84
+ ).length;
85
+ if (possibleDays >= days) return;
86
+ reporter.reportRuleError({
87
+ rule: "min-days-week",
88
+ message: `${member.id} cannot reach ${days} assigned days in week starting ${weekStart.iso}; only ${possibleDays} day${possibleDays === 1 ? " is" : "s are"} assignable.`,
89
+ context,
90
+ suggestions: [
91
+ `Reduce the weekly day minimum for ${member.id}`,
92
+ `Add more assignable days in the week starting ${weekStart.iso}`,
93
+ ],
94
+ group,
95
+ });
96
+ },
97
+ },
98
+ ]
99
+ : [
100
+ softConstraint({
101
+ group,
102
+ description,
103
+ context,
104
+ validation: reportValidation(),
105
+ terms,
106
+ comparator: ">=",
107
+ targetValue: days,
108
+ penalty: priorityToPenalty(priority),
109
+ constraintId,
110
+ }),
111
+ ];
112
+
113
+ return supportArtifacts.concat(finalArtifacts);
114
+ }),
115
+ );
116
+
117
+ return {
118
+ rule: "min-days-week",
119
+ artifacts,
120
+ };
121
+ },
122
+ });