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,50 +1,46 @@
1
- import type { DayOfWeek, SchedulingPeriod } from "./types.js";
2
-
3
- export const DAY_OF_WEEK_MAP: Record<DayOfWeek, number> = {
4
- sunday: 0, // JavaScript Date week starts on Sunday
5
- monday: 1,
6
- tuesday: 2,
7
- wednesday: 3,
8
- thursday: 4,
9
- friday: 5,
10
- saturday: 6,
11
- };
12
-
13
- const DAY_NAMES = [
14
- "sunday",
15
- "monday",
16
- "tuesday",
17
- "wednesday",
18
- "thursday",
19
- "friday",
20
- "saturday",
21
- ] as const;
1
+ import {
2
+ DAY_NAMES,
3
+ type DateString,
4
+ type DayOfWeek,
5
+ type SchedulingDay,
6
+ type SchedulingPeriod,
7
+ } from "./types.js";
22
8
 
23
9
  /**
24
- * Helper to get the day of week name from a Date (UTC).
25
- * Use this when working with date strings like "2026-01-10" that are timezone-agnostic.
10
+ * Builds a {@link SchedulingDay} from an existing UTC `Date`, avoiding a
11
+ * redundant `new Date()` call. Used internally by {@link resolveDaysFromPeriod}
12
+ * where the loop already maintains a `Date` cursor.
26
13
  */
27
- export function toDayOfWeekUTC(date: Date): DayOfWeek {
28
- // getUTCDay() always returns 0-6
29
- return DAY_NAMES[date.getUTCDay()] as DayOfWeek;
14
+ function schedulingDayFromDate(date: Date, iso: DateString): SchedulingDay {
15
+ const dayOfWeek = DAY_NAMES[date.getUTCDay()]!;
16
+ const month = date.getUTCMonth() + 1;
17
+ const dayOfMonth = date.getUTCDate();
18
+ return {
19
+ iso,
20
+ dayOfWeek,
21
+ month,
22
+ dayOfMonth,
23
+ yearMonth: iso.slice(0, 7),
24
+ epochDay: Math.floor(date.getTime() / 86_400_000),
25
+ };
30
26
  }
31
27
 
32
28
  /**
33
- * Computes the list of day strings (YYYY-MM-DD) from a SchedulingPeriod.
29
+ * Computes the list of {@link SchedulingDay} values from a {@link SchedulingPeriod}.
34
30
  *
35
31
  * Generates all days between start and end (inclusive), applying optional
36
32
  * dayOfWeek and dates filters. Filters compose: a day must pass all
37
33
  * specified filters to be included.
38
34
  *
39
35
  * @param period - The scheduling period specification
40
- * @returns Array of day strings in YYYY-MM-DD format, sorted chronologically
36
+ * @returns Array of scheduling days, sorted chronologically
41
37
  *
42
38
  * @example All days in range
43
39
  * ```typescript
44
40
  * const days = resolveDaysFromPeriod({
45
41
  * dateRange: { start: '2025-02-03', end: '2025-02-05' },
46
42
  * });
47
- * // Returns: ['2025-02-03', '2025-02-04', '2025-02-05']
43
+ * // Returns days for 2025-02-03, 2025-02-04, 2025-02-05
48
44
  * ```
49
45
  *
50
46
  * @example Day-of-week filter
@@ -53,7 +49,7 @@ export function toDayOfWeekUTC(date: Date): DayOfWeek {
53
49
  * dateRange: { start: '2025-02-03', end: '2025-02-09' },
54
50
  * dayOfWeek: ['wednesday', 'friday'],
55
51
  * });
56
- * // Returns: ['2025-02-05', '2025-02-07']
52
+ * // Returns days for 2025-02-05, 2025-02-07
57
53
  * ```
58
54
  *
59
55
  * @example Specific dates filter
@@ -62,31 +58,36 @@ export function toDayOfWeekUTC(date: Date): DayOfWeek {
62
58
  * dateRange: { start: '2025-02-03', end: '2025-02-10' },
63
59
  * dates: ['2025-02-05', '2025-02-07'],
64
60
  * });
65
- * // Returns: ['2025-02-05', '2025-02-07']
61
+ * // Returns days for 2025-02-05, 2025-02-07
66
62
  * ```
67
63
  */
68
- export function resolveDaysFromPeriod(period: SchedulingPeriod): string[] {
64
+ export function resolveDaysFromPeriod(period: SchedulingPeriod): SchedulingDay[] {
69
65
  const { dateRange, dayOfWeek, dates } = period;
70
- const allowedDays = dayOfWeek ? new Set(dayOfWeek) : null;
71
- const allowedDates = dates ? new Set(dates) : null;
66
+ const allowedDays: Set<DayOfWeek> | null = dayOfWeek ? new Set(dayOfWeek) : null;
67
+ const allowedDates: Set<string> | null = dates ? new Set(dates) : null;
72
68
 
73
69
  const startDate = new Date(`${dateRange.start}T00:00:00Z`);
74
70
  const endDate = new Date(`${dateRange.end}T00:00:00Z`);
75
- const result: string[] = [];
71
+ const result: SchedulingDay[] = [];
76
72
 
77
- const current = new Date(startDate);
78
- while (current <= endDate) {
73
+ for (
74
+ let currentTime = startDate.getTime(), endTime = endDate.getTime();
75
+ currentTime <= endTime;
76
+ currentTime += 24 * 60 * 60 * 1000
77
+ ) {
78
+ const current = new Date(currentTime);
79
79
  const year = current.getUTCFullYear();
80
80
  const month = (current.getUTCMonth() + 1).toString().padStart(2, "0");
81
- const day = current.getUTCDate().toString().padStart(2, "0");
82
- const iso = `${year}-${month}-${day}`;
83
- const dow = toDayOfWeekUTC(current);
81
+ const d = current.getUTCDate().toString().padStart(2, "0");
82
+ const iso = `${year}-${month}-${d}` as DateString;
83
+ const day = schedulingDayFromDate(current, iso);
84
84
 
85
- if ((!allowedDays || allowedDays.has(dow)) && (!allowedDates || allowedDates.has(iso))) {
86
- result.push(iso);
85
+ if (
86
+ (!allowedDays || allowedDays.has(day.dayOfWeek)) &&
87
+ (!allowedDates || allowedDates.has(iso))
88
+ ) {
89
+ result.push(day);
87
90
  }
88
-
89
- current.setUTCDate(current.getUTCDate() + 1);
90
91
  }
91
92
 
92
93
  return result;
package/src/index.ts CHANGED
@@ -1,5 +1,7 @@
1
1
  /**
2
- * @privateRemarks
2
+ * Scheduling library powered by constraint programming (CP-SAT).
3
+ *
4
+ * @remarks
3
5
  * ## Core Concepts
4
6
  *
5
7
  * **Schedule**: The primary API. Small, composable functions
@@ -34,9 +36,9 @@
34
36
  // Time primitives
35
37
  // ============================================================================
36
38
 
37
- export type { TimeOfDay, DayOfWeek, SchedulingPeriod } from "./types.js";
39
+ export type { DateString, TimeOfDay, DayOfWeek, SchedulingDay, SchedulingPeriod } from "./types.js";
38
40
 
39
- export { DayOfWeekSchema } from "./types.js";
41
+ export { schedulingDay, DAY_OF_WEEK_INDEX, DayOfWeekSchema } from "./types.js";
40
42
 
41
43
  // ============================================================================
42
44
  // Solver client
@@ -49,13 +51,27 @@ export type {
49
51
  SolverRequest,
50
52
  SolverResponse,
51
53
  SolverStatus,
52
- SoftConstraintViolation,
54
+ SolverMode,
55
+ SolverDiagnosticMode,
56
+ SolverObjectiveStage,
57
+ SolverStageResult,
58
+ SolverSoftConstraintViolation,
59
+ SolverHardConstraintConflict,
53
60
  FetcherLike,
54
61
  } from "./client.types.js";
55
62
 
56
63
  export { SOLVER_STATUS } from "./client.types.js";
57
64
 
58
- export { SolverRequestSchema, SolverResponseSchema, SolverStatusSchema } from "./client.schemas.js";
65
+ export {
66
+ SolverModeSchema,
67
+ SolverDiagnosticModeSchema,
68
+ SolverObjectiveStageSchema,
69
+ SolverRequestSchema,
70
+ SolverResponseSchema,
71
+ SolverStageResultSchema,
72
+ SolverStatusSchema,
73
+ SolverHardConstraintConflictSchema,
74
+ } from "./client.schemas.js";
59
75
 
60
76
  // ============================================================================
61
77
  // Model builder
@@ -63,14 +79,27 @@ export { SolverRequestSchema, SolverResponseSchema, SolverStatusSchema } from ".
63
79
 
64
80
  export { ModelBuilder } from "./cpsat/model-builder.js";
65
81
 
82
+ export type { ModelBuilderConfig, CompilationResult } from "./cpsat/model-builder.js";
83
+ export type { ModelSolveStrategy } from "./cpsat/types.js";
84
+
85
+ export { compileRuleDescriptor, defineRuleDescriptor } from "./cpsat/rule-descriptor.js";
86
+
66
87
  export type {
67
- ModelBuilderConfig,
68
- CompilationResult,
69
- CompilationRule,
70
- RuleValidationContext,
88
+ CostValidationStrategy,
89
+ HardConstraintValidationStrategy,
90
+ ObjectiveValidationStrategy,
91
+ ReportHardConstraintValidationStrategy,
92
+ ReportSoftConstraintValidationStrategy,
93
+ RuleDescriptor,
94
+ RuleCompileContext,
95
+ RuleArtifact,
96
+ SkipValidationStrategy,
97
+ SoftConstraintValidationStrategy,
98
+ CompiledRule,
99
+ ValidationSkipCategory,
71
100
  CostEntry,
72
101
  CostContribution,
73
- } from "./cpsat/model-builder.js";
102
+ } from "./cpsat/rule-descriptor.js";
74
103
 
75
104
  // ============================================================================
76
105
  // Solver response parsing
@@ -92,10 +121,19 @@ export type { CostBreakdown, MemberCostDetail, CostCalculationConfig } from "./c
92
121
  // Rules (registry types)
93
122
  // ============================================================================
94
123
 
124
+ export {
125
+ assertValidCpsatRuleRegistry,
126
+ builtInCpsatRuleRegistry,
127
+ createCpsatRuleRegistry,
128
+ } from "./cpsat/rules/registry.js";
129
+
95
130
  export type {
131
+ BuiltInCpsatRuleConfigRegistry,
132
+ BuiltInCpsatRuleRegistry,
133
+ CpsatRuleConfigByName,
96
134
  CpsatRuleConfigEntry,
97
- CpsatRuleFactories,
98
- CreateCpsatRuleFunction,
135
+ CpsatRuleConfigEntryFor,
136
+ CpsatRuleRegistry,
99
137
  } from "./cpsat/rules/rules.types.js";
100
138
 
101
139
  export type { RecurringPeriod } from "./cpsat/rules/scope.types.js";
@@ -148,6 +186,7 @@ export { summarizeValidation } from "./cpsat/validation-reporter.js";
148
186
 
149
187
  export {
150
188
  schedule,
189
+ scheduleWithRuleRegistry,
151
190
  partialSchedule,
152
191
  Schedule,
153
192
  t,
@@ -158,15 +197,26 @@ export {
158
197
  maxHoursPerWeek,
159
198
  minHoursPerDay,
160
199
  minHoursPerWeek,
200
+ maxDaysPerWeek,
201
+ minDaysPerWeek,
202
+ targetDaysPerWeek,
161
203
  maxShiftsPerDay,
204
+ maxConcurrentAssignments,
205
+ targetPeakConcurrentAssignments,
162
206
  maxConsecutiveDays,
163
207
  minConsecutiveDays,
164
208
  minRestBetweenShifts,
165
- preference,
209
+ mustAssign,
210
+ preferAssignment,
211
+ avoidAssignment,
212
+ preferRole,
166
213
  preferLocation,
167
214
  timeOff,
168
215
  assignTogether,
216
+ maxDaysOfWeekPerPeriod,
217
+ minDaysOfWeekPerPeriod,
169
218
  defineRule,
219
+ defineRuleFor,
170
220
  minimizeCost,
171
221
  dayMultiplier,
172
222
  daySurcharge,
@@ -178,7 +228,7 @@ export {
178
228
  tieredOvertimeMultiplier,
179
229
  weekdays,
180
230
  weekend,
181
- } from "./schedule.js";
231
+ } from "./schedule/index.js";
182
232
 
183
233
  export type {
184
234
  CoverageEntry,
@@ -187,12 +237,19 @@ export type {
187
237
  RuleEntry,
188
238
  RuleResolveContext,
189
239
  RuleOptions,
240
+ ScheduleRuleEntry,
190
241
  EntityOnlyRuleOptions,
242
+ TargetDaysPerWeekOptions,
191
243
  TimeOffOptions,
192
244
  AssignTogetherOptions,
245
+ MaxConcurrentAssignmentsOptions,
246
+ TargetPeakConcurrentAssignmentsOptions,
247
+ DaysOfWeekPerPeriodOptions,
193
248
  CostRuleOptions,
194
249
  ScheduleConfig,
250
+ ScheduleWithRuleRegistryConfig,
195
251
  SolveResult,
196
252
  SolveStatus,
253
+ SolveStrategy,
197
254
  SolveOptions,
198
- } from "./schedule.js";
255
+ } from "./schedule/index.js";
@@ -0,0 +1,221 @@
1
+ /**
2
+ * Cost optimization rules: minimize labor cost with modifiers.
3
+ *
4
+ *
5
+ * @example
6
+ * ```typescript
7
+ * rules: [
8
+ * minimizeCost(),
9
+ * dayMultiplier(1.5, { dayOfWeek: weekend }),
10
+ * overtimeMultiplier({ after: 40, factor: 1.5 }),
11
+ * dailyOvertimeSurcharge({ after: 8, amount: 500 }),
12
+ * tieredOvertimeMultiplier([
13
+ * { after: 40, factor: 1.5 },
14
+ * { after: 48, factor: 2.0 },
15
+ * ]),
16
+ * ]
17
+ * ```
18
+ *
19
+ * @module
20
+ */
21
+
22
+ import type { DayOfWeek, TimeOfDay } from "../types.js";
23
+ import type { OvertimeTier } from "../cpsat/rules/overtime-tiered-multiplier.js";
24
+ import type { RecurringPeriod } from "../cpsat/rules/scope.types.js";
25
+ import type { RuleEntry } from "./rules.js";
26
+ import { defineRule } from "./rules.js";
27
+
28
+ // ============================================================================
29
+ // Cost Rule Options
30
+ // ============================================================================
31
+
32
+ /**
33
+ * Options for cost rules.
34
+ *
35
+ * Cost rules are objective terms, not constraints. The `priority` field from
36
+ * {@link RuleOptions} does not apply.
37
+ *
38
+ * @category Cost Optimization
39
+ */
40
+ export interface CostRuleOptions {
41
+ /** Who this rule applies to (role name, skill name, or member ID). */
42
+ appliesTo?: string | string[];
43
+ /** Restrict to specific days of the week. */
44
+ dayOfWeek?: readonly [DayOfWeek, ...DayOfWeek[]];
45
+ /** Restrict to a date range. */
46
+ dateRange?: { start: string; end: string };
47
+ /** Restrict to specific dates (YYYY-MM-DD). */
48
+ dates?: string[];
49
+ /** Restrict to recurring calendar periods. */
50
+ recurringPeriods?: [RecurringPeriod, ...RecurringPeriod[]];
51
+ }
52
+
53
+ // ============================================================================
54
+ // Cost Rules
55
+ // ============================================================================
56
+
57
+ function makeCostRule<const Name extends string, const Fields extends object>(
58
+ rule: Name,
59
+ fields: Fields,
60
+ ): RuleEntry<Name, Omit<Fields, "_type" | "_rule">> {
61
+ return defineRule(rule, fields);
62
+ }
63
+
64
+ /**
65
+ * Tells the solver to minimize total labor cost.
66
+ *
67
+ * @remarks
68
+ * Without this rule, cost modifiers only affect post-solve calculation.
69
+ * When present, the solver actively prefers cheaper assignments.
70
+ *
71
+ * For hourly members, penalizes each assignment proportionally to cost.
72
+ * For salaried members, adds a fixed weekly salary cost when they have
73
+ * any assignment that week (zero marginal cost up to contracted hours).
74
+ *
75
+ * Cost modifiers adjust the calculation:
76
+ * - `dayMultiplier(factor, opts?)` - multiply base rate on specific days
77
+ * - `daySurcharge(amount, opts?)` - flat extra per hour on specific days
78
+ * - `timeSurcharge(amount, window, opts?)` - flat extra per hour during a time window
79
+ * - `overtimeMultiplier({ after, factor }, opts?)` - weekly overtime multiplier
80
+ * - `overtimeSurcharge({ after, amount }, opts?)` - weekly overtime surcharge
81
+ * - `dailyOvertimeMultiplier({ after, factor }, opts?)` - daily overtime multiplier
82
+ * - `dailyOvertimeSurcharge({ after, amount }, opts?)` - daily overtime surcharge
83
+ * - `tieredOvertimeMultiplier(tiers, opts?)` - multiple overtime thresholds
84
+ *
85
+ * @category Cost Optimization
86
+ */
87
+ export function minimizeCost(opts?: CostRuleOptions): RuleEntry<"minimize-cost", CostRuleOptions> {
88
+ return makeCostRule("minimize-cost", { ...opts });
89
+ }
90
+
91
+ /**
92
+ * Multiplies the base rate for assignments on specified days.
93
+ *
94
+ * @remarks
95
+ * The base cost (1x) is already counted by {@link minimizeCost};
96
+ * this rule adds only the extra portion above 1x.
97
+ *
98
+ * @category Cost Optimization
99
+ */
100
+ export function dayMultiplier(
101
+ factor: number,
102
+ opts?: CostRuleOptions,
103
+ ): RuleEntry<"day-cost-multiplier", { factor: number } & CostRuleOptions> {
104
+ return makeCostRule("day-cost-multiplier", { factor, ...opts });
105
+ }
106
+
107
+ /**
108
+ * Adds a flat extra amount per hour for assignments on specified days.
109
+ *
110
+ * @remarks
111
+ * The surcharge is independent of the member's base rate.
112
+ *
113
+ * @category Cost Optimization
114
+ */
115
+ export function daySurcharge(
116
+ amountPerHour: number,
117
+ opts?: CostRuleOptions,
118
+ ): RuleEntry<"day-cost-surcharge", { amountPerHour: number } & CostRuleOptions> {
119
+ return makeCostRule("day-cost-surcharge", { amountPerHour, ...opts });
120
+ }
121
+
122
+ /**
123
+ * Adds a flat surcharge per hour for the portion of a shift that overlaps a time-of-day window.
124
+ *
125
+ * @remarks
126
+ * The window supports overnight spans (e.g., 22:00-06:00). The surcharge
127
+ * is independent of the member's base rate.
128
+ *
129
+ * @param amountPerHour - Flat surcharge per hour in smallest currency unit
130
+ * @param window - Time-of-day window
131
+ * @param opts - Entity and time scoping
132
+ *
133
+ * @category Cost Optimization
134
+ */
135
+ export function timeSurcharge(
136
+ amountPerHour: number,
137
+ window: { from: TimeOfDay; until: TimeOfDay },
138
+ opts?: CostRuleOptions,
139
+ ): RuleEntry<
140
+ "time-cost-surcharge",
141
+ { amountPerHour: number; window: { from: TimeOfDay; until: TimeOfDay } } & CostRuleOptions
142
+ > {
143
+ return makeCostRule("time-cost-surcharge", { amountPerHour, window, ...opts });
144
+ }
145
+
146
+ /**
147
+ * Applies a multiplier to hours beyond a weekly threshold.
148
+ *
149
+ * @remarks
150
+ * Only the extra portion above 1x is added (the base cost is already
151
+ * counted by {@link minimizeCost}).
152
+ *
153
+ * @category Cost Optimization
154
+ */
155
+ export function overtimeMultiplier(
156
+ opts: { after: number; factor: number } & CostRuleOptions,
157
+ ): RuleEntry<"overtime-weekly-multiplier", { after: number; factor: number } & CostRuleOptions> {
158
+ return makeCostRule("overtime-weekly-multiplier", { ...opts });
159
+ }
160
+
161
+ /**
162
+ * Adds a flat surcharge per hour beyond a weekly threshold.
163
+ *
164
+ * @remarks
165
+ * The surcharge is independent of the member's base rate.
166
+ *
167
+ * @category Cost Optimization
168
+ */
169
+ export function overtimeSurcharge(
170
+ opts: { after: number; amount: number } & CostRuleOptions,
171
+ ): RuleEntry<"overtime-weekly-surcharge", { after: number; amount: number } & CostRuleOptions> {
172
+ return makeCostRule("overtime-weekly-surcharge", { ...opts });
173
+ }
174
+
175
+ /**
176
+ * Applies a multiplier to hours beyond a daily threshold.
177
+ *
178
+ * @remarks
179
+ * Only the extra portion above 1x is added (the base cost is already
180
+ * counted by {@link minimizeCost}).
181
+ *
182
+ * @category Cost Optimization
183
+ */
184
+ export function dailyOvertimeMultiplier(
185
+ opts: { after: number; factor: number } & CostRuleOptions,
186
+ ): RuleEntry<"overtime-daily-multiplier", { after: number; factor: number } & CostRuleOptions> {
187
+ return makeCostRule("overtime-daily-multiplier", { ...opts });
188
+ }
189
+
190
+ /**
191
+ * Adds a flat surcharge per hour beyond a daily threshold.
192
+ *
193
+ * @remarks
194
+ * The surcharge is independent of the member's base rate.
195
+ *
196
+ * @category Cost Optimization
197
+ */
198
+ export function dailyOvertimeSurcharge(
199
+ opts: { after: number; amount: number } & CostRuleOptions,
200
+ ): RuleEntry<"overtime-daily-surcharge", { after: number; amount: number } & CostRuleOptions> {
201
+ return makeCostRule("overtime-daily-surcharge", { ...opts });
202
+ }
203
+
204
+ /**
205
+ * Applies multiple overtime thresholds with increasing multipliers.
206
+ *
207
+ * @remarks
208
+ * Each tier applies only to the hours between its threshold and the next.
209
+ * Tiers must be sorted by threshold ascending.
210
+ *
211
+ * @category Cost Optimization
212
+ */
213
+ export function tieredOvertimeMultiplier(
214
+ tiers: [OvertimeTier, ...OvertimeTier[]],
215
+ opts?: CostRuleOptions,
216
+ ): RuleEntry<
217
+ "overtime-tiered-multiplier",
218
+ { tiers: [OvertimeTier, ...OvertimeTier[]] } & CostRuleOptions
219
+ > {
220
+ return makeCostRule("overtime-tiered-multiplier", { tiers, ...opts });
221
+ }
@@ -0,0 +1,164 @@
1
+ /**
2
+ * Coverage definitions: lower-bound staffing requirements per semantic time period.
3
+ *
4
+ * Coverage answers "what floor should apply throughout this scoped time, with
5
+ * the chosen priority?". It attaches sustained lower bounds to semantic times,
6
+ * whether those periods are
7
+ * explicit in the requirements or inferred to separate distinct business
8
+ * requirements. Coverage does not express caps, targets, fairness, or other
9
+ * assignment-shaping logic. Use rules for those concerns.
10
+ *
11
+ * @example
12
+ * ```typescript
13
+ * coverage: [
14
+ * cover("lunch", "waiter", 2, { dayOfWeek: weekdays }),
15
+ * cover("lunch", "waiter", 3, { dayOfWeek: weekend }),
16
+ * cover("dinner", ["manager", "supervisor"], 1),
17
+ * cover("opening", "keyholder", 1),
18
+ *
19
+ * // Variant form: different counts by day
20
+ * cover("peak_hours", "agent",
21
+ * { count: 4 },
22
+ * { count: 2, dates: ["2025-12-24"] },
23
+ * ),
24
+ * ]
25
+ * ```
26
+ *
27
+ * @module
28
+ */
29
+
30
+ import type { DateString, DayOfWeek } from "../types.js";
31
+ import type { CoverageVariant } from "../cpsat/semantic-time.js";
32
+ import type { Priority } from "../cpsat/types.js";
33
+
34
+ export type { CoverageVariant } from "../cpsat/semantic-time.js";
35
+
36
+ /**
37
+ * Options for a {@link cover} call.
38
+ *
39
+ * @remarks
40
+ * Day/date scoping controls which days this coverage entry applies to.
41
+ * An entry without `dayOfWeek` or `dates` applies every day in the
42
+ * scheduling period. Scope answers where the floor applies; it does not change
43
+ * the meaning of coverage itself. `priority` controls how hard the coverage floor is.
44
+ * Use it to distinguish language like "must keep 5 staffed on Saturdays"
45
+ * from "ideally keep 5 staffed on Mondays too" without changing the
46
+ * underlying coverage shape. `skillIds` is a hard filter, not a preference.
47
+ * Use it only when the required minimum truly needs those skills throughout
48
+ * the window. If a role or skill mix is preferred rather than required, model
49
+ * that with rules such as {@link preferAssignment} instead of skill-filtered
50
+ * coverage.
51
+ *
52
+ * @category Coverage
53
+ */
54
+ export interface CoverageOptions {
55
+ /** Additional skill ID filter (AND logic with the target role). */
56
+ skillIds?: [string, ...string[]];
57
+ /** Restrict to specific days of the week. */
58
+ dayOfWeek?: readonly [DayOfWeek, ...DayOfWeek[]];
59
+ /** Restrict to specific dates (YYYY-MM-DD). */
60
+ dates?: DateString[];
61
+ /** Defaults to `"MANDATORY"`. */
62
+ priority?: Priority;
63
+ }
64
+
65
+ /**
66
+ * A coverage entry returned by {@link cover}.
67
+ *
68
+ * @remarks
69
+ * Carries the semantic time name and target type information for
70
+ * compile-time validation by {@link schedule}. This is an opaque
71
+ * token; pass it directly into the `coverage` array.
72
+ */
73
+ export interface CoverageEntry<T extends string = string, R extends string = string> {
74
+ /** @internal */ readonly _type: "coverage";
75
+ /** @internal */ readonly timeName: T;
76
+ /** @internal */ readonly target: R | R[];
77
+ /** @internal */ readonly count: number;
78
+ /** @internal */ readonly options: CoverageOptions;
79
+ /** @internal When present, this entry uses variant-based resolution. */
80
+ readonly variants?: readonly CoverageVariant[];
81
+ }
82
+
83
+ /**
84
+ * Defines a staffing requirement for a semantic time period.
85
+ *
86
+ * @remarks
87
+ * Coverage always defines a lower bound that applies throughout the scoped
88
+ * semantic time, with strength controlled by `priority`. If the requirements
89
+ * also state an upper bound or productive
90
+ * cap, model that separately in `rules`, for example with
91
+ * {@link maxConcurrentAssignments}.
92
+ *
93
+ * Scope answers where the floor applies. Priority answers how strictly the
94
+ * solver should preserve that floor when trade-offs are necessary.
95
+ *
96
+ * Attach coverage to the narrowest semantic time that actually carries that
97
+ * minimum. Avoid layering a broad parent coverage window on top of narrower
98
+ * windows unless the same lower bound truly applies throughout the full span.
99
+ * If the requirements talk about hitting full occupancy at the busy point,
100
+ * prefer {@link targetPeakConcurrentAssignments} over turning that into a
101
+ * whole-window minimum. Do not infer a synthetic "peak" semantic time just to attach
102
+ * `cover(..., 5)` unless the requirements really define a sustained window
103
+ * that needs that minimum throughout.
104
+ *
105
+ * Overlapping entries for the same time and role produce independent
106
+ * constraints; the solver enforces the **max** count, not the sum.
107
+ * An unscoped entry acts as a floor that scoped entries cannot reduce.
108
+ * Use mutually exclusive scopes when different days need different coverage.
109
+ *
110
+ * @param timeName - Name of a declared semantic time
111
+ * @param target - Role name (string), array of role names (OR logic), or skill name
112
+ * @param count - Number of people needed
113
+ * @param opts - Options: `skillIds` (AND filter), `dayOfWeek`, `dates`, `priority`
114
+ *
115
+ * @category Coverage
116
+ */
117
+ export function cover<T extends string, const R extends string>(
118
+ timeName: T,
119
+ target: R | [R, ...R[]],
120
+ count: number,
121
+ opts?: CoverageOptions,
122
+ ): CoverageEntry<T, R>;
123
+ export function cover<T extends string, const R extends string>(
124
+ timeName: T,
125
+ target: R | [R, ...R[]],
126
+ ...variants: [CoverageVariant, ...CoverageVariant[]]
127
+ ): CoverageEntry<T, R>;
128
+ export function cover<T extends string, R extends string>(
129
+ timeName: T,
130
+ target: R | [R, ...R[]],
131
+ countOrFirstVariant: number | CoverageVariant,
132
+ ...rest: unknown[]
133
+ ): CoverageEntry<T, R> {
134
+ if (typeof countOrFirstVariant === "number") {
135
+ // Simple form: cover(time, target, count, opts?)
136
+ return {
137
+ _type: "coverage",
138
+ timeName,
139
+ target,
140
+ count: countOrFirstVariant,
141
+ options: (rest[0] as CoverageOptions | undefined) ?? {},
142
+ };
143
+ }
144
+
145
+ // Variant form: cover(time, target, ...variants)
146
+ const variants = [countOrFirstVariant, ...(rest as CoverageVariant[])];
147
+
148
+ const defaults = variants.filter((v) => !v.dayOfWeek && !v.dates);
149
+ if (defaults.length > 1) {
150
+ throw new Error(
151
+ "cover() accepts at most one default variant (without dayOfWeek or dates). " +
152
+ `Found ${defaults.length} default variants.`,
153
+ );
154
+ }
155
+
156
+ return {
157
+ _type: "coverage",
158
+ timeName,
159
+ target,
160
+ count: 0,
161
+ options: {},
162
+ variants,
163
+ };
164
+ }