scriptplan 0.10.1__tar.gz → 0.10.3__tar.gz

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 (285) hide show
  1. scriptplan-0.10.3/CHANGELOG.md +502 -0
  2. {scriptplan-0.10.1 → scriptplan-0.10.3}/MANIFEST.in +1 -0
  3. {scriptplan-0.10.1/scriptplan.egg-info → scriptplan-0.10.3}/PKG-INFO +76 -22
  4. {scriptplan-0.10.1 → scriptplan-0.10.3}/README.md +75 -21
  5. scriptplan-0.10.3/examples/README.md +42 -0
  6. scriptplan-0.10.3/examples/edge_cases/alap_before_declared_start.expected.csv +5 -0
  7. scriptplan-0.10.3/examples/edge_cases/alap_before_declared_start.expected.md +6 -0
  8. scriptplan-0.10.3/examples/edge_cases/alap_before_declared_start.tjp +8 -0
  9. scriptplan-0.10.3/examples/edge_cases/alap_bounded_by_declared_starts.expected.csv +5 -0
  10. scriptplan-0.10.3/examples/edge_cases/alap_bounded_by_declared_starts.expected.md +6 -0
  11. scriptplan-0.10.3/examples/edge_cases/alap_bounded_by_declared_starts.tjp +8 -0
  12. scriptplan-0.10.3/examples/edge_cases/alap_gapduration_before_successor.expected.csv +5 -0
  13. scriptplan-0.10.3/examples/edge_cases/alap_gapduration_before_successor.expected.md +6 -0
  14. scriptplan-0.10.3/examples/edge_cases/alap_gapduration_before_successor.tjp +15 -0
  15. scriptplan-0.10.3/examples/edge_cases/alap_keeps_successor_gaps.expected.csv +7 -0
  16. scriptplan-0.10.3/examples/edge_cases/alap_keeps_successor_gaps.expected.md +8 -0
  17. scriptplan-0.10.3/examples/edge_cases/alap_keeps_successor_gaps.tjp +10 -0
  18. scriptplan-0.10.3/examples/edge_cases/alap_milestones_exact.expected.csv +6 -0
  19. scriptplan-0.10.3/examples/edge_cases/alap_milestones_exact.expected.md +5 -0
  20. scriptplan-0.10.3/examples/edge_cases/alap_milestones_exact.tjp +9 -0
  21. scriptplan-0.10.3/examples/edge_cases/alap_onstart_reading.expected.csv +5 -0
  22. scriptplan-0.10.3/examples/edge_cases/alap_onstart_reading.expected.md +5 -0
  23. scriptplan-0.10.3/examples/edge_cases/alap_onstart_reading.tjp +15 -0
  24. scriptplan-0.10.3/examples/edge_cases/alap_own_end_before_successor.expected.csv +5 -0
  25. scriptplan-0.10.3/examples/edge_cases/alap_own_end_before_successor.expected.md +5 -0
  26. scriptplan-0.10.3/examples/edge_cases/alap_own_end_before_successor.tjp +15 -0
  27. scriptplan-0.10.3/examples/edge_cases/alap_project_end_and_declared_end.expected.csv +4 -0
  28. scriptplan-0.10.3/examples/edge_cases/alap_project_end_and_declared_end.expected.md +5 -0
  29. scriptplan-0.10.3/examples/edge_cases/alap_project_end_and_declared_end.tjp +7 -0
  30. scriptplan-0.10.3/examples/edge_cases/alap_spans_before_mid_slot_successor.expected.csv +5 -0
  31. scriptplan-0.10.3/examples/edge_cases/alap_spans_before_mid_slot_successor.expected.md +5 -0
  32. scriptplan-0.10.3/examples/edge_cases/alap_spans_before_mid_slot_successor.tjp +8 -0
  33. scriptplan-0.10.3/examples/edge_cases/alap_without_anchor_parent.expected.csv +5 -0
  34. scriptplan-0.10.3/examples/edge_cases/alap_without_anchor_parent.expected.md +6 -0
  35. scriptplan-0.10.3/examples/edge_cases/alap_without_anchor_parent.tjp +15 -0
  36. scriptplan-0.10.3/examples/edge_cases/alap_without_anchor_plan.expected.csv +5 -0
  37. scriptplan-0.10.3/examples/edge_cases/alap_without_anchor_plan.expected.md +6 -0
  38. scriptplan-0.10.3/examples/edge_cases/alap_without_anchor_plan.tjp +15 -0
  39. scriptplan-0.10.3/examples/edge_cases/asap_and_alap_share_a_slot.expected.csv +4 -0
  40. scriptplan-0.10.3/examples/edge_cases/asap_and_alap_share_a_slot.expected.md +5 -0
  41. scriptplan-0.10.3/examples/edge_cases/asap_and_alap_share_a_slot.tjp +7 -0
  42. scriptplan-0.10.3/examples/edge_cases/daily_cap_counts_worked_time.expected.csv +4 -0
  43. scriptplan-0.10.3/examples/edge_cases/daily_cap_counts_worked_time.expected.md +8 -0
  44. scriptplan-0.10.3/examples/edge_cases/daily_cap_counts_worked_time.tjp +7 -0
  45. scriptplan-0.10.3/examples/edge_cases/dependency_offset_one_slot.expected.csv +4 -0
  46. scriptplan-0.10.3/examples/edge_cases/dependency_offset_one_slot.expected.md +5 -0
  47. scriptplan-0.10.3/examples/edge_cases/dependency_offset_one_slot.tjp +8 -0
  48. scriptplan-0.10.3/examples/edge_cases/duration_length_after_mid_slot_end.expected.csv +4 -0
  49. scriptplan-0.10.3/examples/edge_cases/duration_length_after_mid_slot_end.expected.md +5 -0
  50. scriptplan-0.10.3/examples/edge_cases/duration_length_after_mid_slot_end.tjp +7 -0
  51. scriptplan-0.10.3/examples/edge_cases/eight_efforts_fill_whole_days.expected.csv +9 -0
  52. scriptplan-0.10.3/examples/edge_cases/eight_efforts_fill_whole_days.expected.md +6 -0
  53. scriptplan-0.10.3/examples/edge_cases/eight_efforts_fill_whole_days.tjp +12 -0
  54. scriptplan-0.10.3/examples/edge_cases/gaplength_on_project_calendar.expected.csv +5 -0
  55. scriptplan-0.10.3/examples/edge_cases/gaplength_on_project_calendar.expected.md +6 -0
  56. scriptplan-0.10.3/examples/edge_cases/gaplength_on_project_calendar.tjp +15 -0
  57. scriptplan-0.10.3/examples/edge_cases/inherited_start_waits_for_dependency.expected.csv +4 -0
  58. scriptplan-0.10.3/examples/edge_cases/inherited_start_waits_for_dependency.expected.md +6 -0
  59. scriptplan-0.10.3/examples/edge_cases/inherited_start_waits_for_dependency.tjp +19 -0
  60. scriptplan-0.10.3/examples/edge_cases/mid_slot_start_and_end.expected.csv +3 -0
  61. scriptplan-0.10.3/examples/edge_cases/mid_slot_start_and_end.expected.md +4 -0
  62. scriptplan-0.10.3/examples/edge_cases/mid_slot_start_and_end.tjp +7 -0
  63. scriptplan-0.10.3/examples/edge_cases/shared_slot_backward.expected.csv +4 -0
  64. scriptplan-0.10.3/examples/edge_cases/shared_slot_backward.expected.md +6 -0
  65. scriptplan-0.10.3/examples/edge_cases/shared_slot_backward.tjp +7 -0
  66. scriptplan-0.10.3/examples/edge_cases/shared_slot_forward_5min.expected.csv +4 -0
  67. scriptplan-0.10.3/examples/edge_cases/shared_slot_forward_5min.expected.md +8 -0
  68. scriptplan-0.10.3/examples/edge_cases/shared_slot_forward_5min.tjp +7 -0
  69. scriptplan-0.10.3/examples/edge_cases/shared_slot_forward_60min.expected.csv +4 -0
  70. scriptplan-0.10.3/examples/edge_cases/shared_slot_forward_60min.expected.md +8 -0
  71. scriptplan-0.10.3/examples/edge_cases/shared_slot_forward_60min.tjp +7 -0
  72. scriptplan-0.10.3/examples/edge_cases/skipped_time_stays_free.expected.csv +5 -0
  73. scriptplan-0.10.3/examples/edge_cases/skipped_time_stays_free.expected.md +6 -0
  74. scriptplan-0.10.3/examples/edge_cases/skipped_time_stays_free.tjp +8 -0
  75. scriptplan-0.10.3/examples/edge_cases/two_people_finish_together.expected.csv +2 -0
  76. scriptplan-0.10.3/examples/edge_cases/two_people_finish_together.expected.md +5 -0
  77. scriptplan-0.10.3/examples/edge_cases/two_people_finish_together.tjp +6 -0
  78. scriptplan-0.10.3/examples/showcase/airport_retrofit.expected.csv +5 -0
  79. scriptplan-0.10.3/examples/showcase/airport_retrofit.expected.md +84 -0
  80. scriptplan-0.10.3/examples/showcase/airport_retrofit.tjp +80 -0
  81. scriptplan-0.10.3/examples/showcase/airport_stress_test.expected.csv +9 -0
  82. scriptplan-0.10.3/examples/showcase/airport_stress_test.expected.md +106 -0
  83. scriptplan-0.10.3/examples/showcase/airport_stress_test.tjp +110 -0
  84. scriptplan-0.10.3/examples/showcase/airport_ultra_math.expected.csv +6 -0
  85. scriptplan-0.10.3/examples/showcase/airport_ultra_math.expected.md +111 -0
  86. scriptplan-0.10.3/examples/showcase/airport_ultra_math.tjp +160 -0
  87. scriptplan-0.10.3/examples/showcase/airport_ultra_math_report.expected.csv +6 -0
  88. scriptplan-0.10.3/examples/showcase/airport_ultra_math_report.expected.md +30 -0
  89. scriptplan-0.10.3/examples/showcase/airport_ultra_math_report.tjp +152 -0
  90. scriptplan-0.10.3/examples/showcase/alap_backward.expected.csv +4 -0
  91. scriptplan-0.10.3/examples/showcase/alap_backward.expected.md +61 -0
  92. scriptplan-0.10.3/examples/showcase/alap_backward.tjp +44 -0
  93. scriptplan-0.10.3/examples/showcase/atomic.expected.csv +2 -0
  94. scriptplan-0.10.3/examples/showcase/atomic.expected.md +49 -0
  95. scriptplan-0.10.3/examples/showcase/atomic.tjp +31 -0
  96. scriptplan-0.10.3/examples/showcase/blackbox.expected.csv +4 -0
  97. scriptplan-0.10.3/examples/showcase/blackbox.expected.md +86 -0
  98. scriptplan-0.10.3/examples/showcase/blackbox.tjp +51 -0
  99. scriptplan-0.10.3/examples/showcase/bottleneck.expected.csv +5 -0
  100. scriptplan-0.10.3/examples/showcase/bottleneck.expected.md +67 -0
  101. scriptplan-0.10.3/examples/showcase/bottleneck.tjp +55 -0
  102. scriptplan-0.10.3/examples/showcase/eclipse.expected.csv +3 -0
  103. scriptplan-0.10.3/examples/showcase/eclipse.expected.md +60 -0
  104. scriptplan-0.10.3/examples/showcase/eclipse.tjp +43 -0
  105. scriptplan-0.10.3/examples/showcase/failover.expected.csv +2 -0
  106. scriptplan-0.10.3/examples/showcase/failover.expected.md +48 -0
  107. scriptplan-0.10.3/examples/showcase/failover.tjp +37 -0
  108. scriptplan-0.10.3/examples/showcase/jit_supply.expected.csv +7 -0
  109. scriptplan-0.10.3/examples/showcase/jit_supply.expected.md +126 -0
  110. scriptplan-0.10.3/examples/showcase/jit_supply.tjp +58 -0
  111. scriptplan-0.10.3/examples/showcase/math_torture.expected.csv +502 -0
  112. scriptplan-0.10.3/examples/showcase/math_torture.expected.md +208 -0
  113. scriptplan-0.10.3/examples/showcase/math_torture.tjp +3028 -0
  114. scriptplan-0.10.3/examples/showcase/paradox.expected.csv +4 -0
  115. scriptplan-0.10.3/examples/showcase/paradox.expected.md +89 -0
  116. scriptplan-0.10.3/examples/showcase/paradox.tjp +48 -0
  117. scriptplan-0.10.3/examples/showcase/priority_clash.expected.csv +4 -0
  118. scriptplan-0.10.3/examples/showcase/priority_clash.expected.md +36 -0
  119. scriptplan-0.10.3/examples/showcase/priority_clash.tjp +36 -0
  120. scriptplan-0.10.3/examples/showcase/quota.expected.csv +5 -0
  121. scriptplan-0.10.3/examples/showcase/quota.expected.md +63 -0
  122. scriptplan-0.10.3/examples/showcase/quota.tjp +49 -0
  123. scriptplan-0.10.3/examples/showcase/simple.expected.csv +5 -0
  124. scriptplan-0.10.3/examples/showcase/simple.expected.md +52 -0
  125. scriptplan-0.10.3/examples/showcase/simple.tjp +50 -0
  126. scriptplan-0.10.3/examples/showcase/synchrony.expected.csv +5 -0
  127. scriptplan-0.10.3/examples/showcase/synchrony.expected.md +54 -0
  128. scriptplan-0.10.3/examples/showcase/synchrony.tjp +70 -0
  129. scriptplan-0.10.3/examples/showcase/thermal.expected.csv +4 -0
  130. scriptplan-0.10.3/examples/showcase/thermal.expected.md +82 -0
  131. scriptplan-0.10.3/examples/showcase/thermal.tjp +43 -0
  132. scriptplan-0.10.3/examples/showcase/throughput.expected.csv +2 -0
  133. scriptplan-0.10.3/examples/showcase/throughput.expected.md +42 -0
  134. scriptplan-0.10.3/examples/showcase/throughput.tjp +37 -0
  135. scriptplan-0.10.3/examples/showcase/time_traveler.expected.csv +4 -0
  136. scriptplan-0.10.3/examples/showcase/time_traveler.expected.md +75 -0
  137. scriptplan-0.10.3/examples/showcase/time_traveler.tjp +63 -0
  138. scriptplan-0.10.3/examples/showcase/timezone_stress.expected.csv +4 -0
  139. scriptplan-0.10.3/examples/showcase/timezone_stress.expected.md +56 -0
  140. scriptplan-0.10.3/examples/showcase/timezone_stress.tjp +65 -0
  141. scriptplan-0.10.3/examples/showcase/tutorial.expected.csv +16 -0
  142. scriptplan-0.10.3/examples/showcase/tutorial.expected.md +448 -0
  143. scriptplan-0.10.3/examples/showcase/tutorial.tjp +494 -0
  144. scriptplan-0.10.3/examples/showcase/union_contract.expected.csv +6 -0
  145. scriptplan-0.10.3/examples/showcase/union_contract.expected.md +44 -0
  146. scriptplan-0.10.3/examples/showcase/union_contract.tjp +53 -0
  147. scriptplan-0.10.3/examples/showcase/workflow_engine.expected.csv +4 -0
  148. scriptplan-0.10.3/examples/showcase/workflow_engine.expected.md +43 -0
  149. scriptplan-0.10.3/examples/showcase/workflow_engine.tjp +66 -0
  150. scriptplan-0.10.3/examples/simple.tjp +26 -0
  151. {scriptplan-0.10.1 → scriptplan-0.10.3}/pyproject.toml +1 -1
  152. {scriptplan-0.10.1 → scriptplan-0.10.3}/scriptplan/__init__.py +4 -8
  153. {scriptplan-0.10.1 → scriptplan-0.10.3}/scriptplan/cli/main.py +4 -49
  154. {scriptplan-0.10.1 → scriptplan-0.10.3}/scriptplan/cli/plan.py +17 -8
  155. {scriptplan-0.10.1 → scriptplan-0.10.3}/scriptplan/cli/plan_help.py +5 -5
  156. scriptplan-0.10.3/scriptplan/cli/programmatic.py +61 -0
  157. {scriptplan-0.10.1 → scriptplan-0.10.3}/scriptplan/core/allocation_plan.py +22 -9
  158. scriptplan-0.10.3/scriptplan/core/criticalness.py +124 -0
  159. scriptplan-0.10.3/scriptplan/core/dated_tasks.py +83 -0
  160. scriptplan-0.10.3/scriptplan/core/declared_dates.py +47 -0
  161. {scriptplan-0.10.1 → scriptplan-0.10.3}/scriptplan/core/limits.py +2 -1
  162. {scriptplan-0.10.1 → scriptplan-0.10.3}/scriptplan/core/project.py +29 -87
  163. {scriptplan-0.10.1 → scriptplan-0.10.3}/scriptplan/core/project_calendar.py +73 -24
  164. {scriptplan-0.10.1 → scriptplan-0.10.3}/scriptplan/core/project_tree.py +13 -1
  165. {scriptplan-0.10.1 → scriptplan-0.10.3}/scriptplan/core/property_tree_node.py +15 -9
  166. {scriptplan-0.10.1 → scriptplan-0.10.3}/scriptplan/core/resolution.py +7 -2
  167. {scriptplan-0.10.1 → scriptplan-0.10.3}/scriptplan/core/resource_availability.py +22 -21
  168. {scriptplan-0.10.1 → scriptplan-0.10.3}/scriptplan/core/resource_reporting.py +32 -28
  169. {scriptplan-0.10.1 → scriptplan-0.10.3}/scriptplan/core/resource_scenario.py +12 -15
  170. scriptplan-0.10.3/scriptplan/core/slot_ledger.py +263 -0
  171. {scriptplan-0.10.1 → scriptplan-0.10.3}/scriptplan/core/task_booking.py +24 -11
  172. {scriptplan-0.10.1 → scriptplan-0.10.3}/scriptplan/core/task_dependencies.py +68 -2
  173. {scriptplan-0.10.1 → scriptplan-0.10.3}/scriptplan/core/task_placement.py +107 -73
  174. {scriptplan-0.10.1 → scriptplan-0.10.3}/scriptplan/core/task_resources.py +36 -10
  175. {scriptplan-0.10.1 → scriptplan-0.10.3}/scriptplan/core/task_scenario.py +42 -15
  176. scriptplan-0.10.3/scriptplan/core/task_spans.py +65 -0
  177. {scriptplan-0.10.1 → scriptplan-0.10.3}/scriptplan/core/units.py +4 -4
  178. {scriptplan-0.10.1 → scriptplan-0.10.3}/scriptplan/core/working_hours.py +8 -2
  179. {scriptplan-0.10.1 → scriptplan-0.10.3}/scriptplan/parser/attribute_apply.py +17 -8
  180. {scriptplan-0.10.1 → scriptplan-0.10.3}/scriptplan/parser/model_pieces.py +55 -63
  181. {scriptplan-0.10.1 → scriptplan-0.10.3}/scriptplan/parser/tjp.lark +6 -5
  182. {scriptplan-0.10.1 → scriptplan-0.10.3}/scriptplan/parser/tjp_parser.py +62 -13
  183. {scriptplan-0.10.1 → scriptplan-0.10.3}/scriptplan/parser/transformer_resource.py +4 -0
  184. {scriptplan-0.10.1 → scriptplan-0.10.3}/scriptplan/parser/transformer_task.py +5 -1
  185. {scriptplan-0.10.1 → scriptplan-0.10.3}/scriptplan/report/logical_expression.py +5 -4
  186. scriptplan-0.10.3/scriptplan/scheduler/postcheck.py +245 -0
  187. {scriptplan-0.10.1 → scriptplan-0.10.3}/scriptplan/scheduler/preflight.py +32 -1
  188. scriptplan-0.10.3/scriptplan/scheduler/stalls.py +89 -0
  189. {scriptplan-0.10.1 → scriptplan-0.10.3}/scriptplan/utils/message_handler.py +37 -21
  190. {scriptplan-0.10.1 → scriptplan-0.10.3}/scriptplan/utils/messages.py +2 -2
  191. {scriptplan-0.10.1 → scriptplan-0.10.3}/scriptplan/utils/time.py +1 -1
  192. {scriptplan-0.10.1 → scriptplan-0.10.3/scriptplan.egg-info}/PKG-INFO +76 -22
  193. scriptplan-0.10.3/scriptplan.egg-info/SOURCES.txt +279 -0
  194. scriptplan-0.10.3/tests/test_container_dependencies.py +244 -0
  195. scriptplan-0.10.3/tests/test_contention_and_bookings.py +168 -0
  196. scriptplan-0.10.3/tests/test_dependency_check.py +67 -0
  197. scriptplan-0.10.3/tests/test_examples.py +117 -0
  198. scriptplan-0.10.3/tests/test_failure_messages.py +49 -0
  199. {scriptplan-0.10.1 → scriptplan-0.10.3}/tests/test_fixture_golden.py +2 -2
  200. {scriptplan-0.10.1 → scriptplan-0.10.3}/tests/test_parser.py +2 -2
  201. scriptplan-0.10.3/tests/test_project_calendar.py +150 -0
  202. {scriptplan-0.10.1 → scriptplan-0.10.3}/tests/test_property_set.py +1 -1
  203. scriptplan-0.10.3/tests/test_reference_and_duration.py +69 -0
  204. {scriptplan-0.10.1 → scriptplan-0.10.3}/tests/test_scheduling.py +1 -1
  205. {scriptplan-0.10.1 → scriptplan-0.10.3}/tests/test_scheduling_validation.py +21 -21
  206. scriptplan-0.10.3/tests/test_scope_and_inherited_start.py +86 -0
  207. {scriptplan-0.10.1 → scriptplan-0.10.3}/tests/test_slot_ledger.py +36 -16
  208. scriptplan-0.10.3/tests/test_stated_dates.py +107 -0
  209. scriptplan-0.10.3/tests/test_threads.py +108 -0
  210. scriptplan-0.10.1/CHANGELOG.md +0 -209
  211. scriptplan-0.10.1/scriptplan/core/slot_ledger.py +0 -234
  212. scriptplan-0.10.1/scriptplan/scheduler/postcheck.py +0 -106
  213. scriptplan-0.10.1/scriptplan.egg-info/SOURCES.txt +0 -117
  214. {scriptplan-0.10.1 → scriptplan-0.10.3}/LICENSE +0 -0
  215. {scriptplan-0.10.1 → scriptplan-0.10.3}/scriptplan/cli/__init__.py +0 -0
  216. {scriptplan-0.10.1 → scriptplan-0.10.3}/scriptplan/cli/plan_files.py +0 -0
  217. {scriptplan-0.10.1 → scriptplan-0.10.3}/scriptplan/core/__init__.py +0 -0
  218. {scriptplan-0.10.1 → scriptplan-0.10.3}/scriptplan/core/account.py +0 -0
  219. {scriptplan-0.10.1 → scriptplan-0.10.3}/scriptplan/core/allocation.py +0 -0
  220. {scriptplan-0.10.1 → scriptplan-0.10.3}/scriptplan/core/attributes.py +0 -0
  221. {scriptplan-0.10.1 → scriptplan-0.10.3}/scriptplan/core/booking.py +0 -0
  222. {scriptplan-0.10.1 → scriptplan-0.10.3}/scriptplan/core/exceptions.py +0 -0
  223. {scriptplan-0.10.1 → scriptplan-0.10.3}/scriptplan/core/journal.py +0 -0
  224. {scriptplan-0.10.1 → scriptplan-0.10.3}/scriptplan/core/leave.py +0 -0
  225. {scriptplan-0.10.1 → scriptplan-0.10.3}/scriptplan/core/project_attributes.py +0 -0
  226. {scriptplan-0.10.1 → scriptplan-0.10.3}/scriptplan/core/property.py +0 -0
  227. {scriptplan-0.10.1 → scriptplan-0.10.3}/scriptplan/core/property_list.py +0 -0
  228. {scriptplan-0.10.1 → scriptplan-0.10.3}/scriptplan/core/property_set.py +0 -0
  229. {scriptplan-0.10.1 → scriptplan-0.10.3}/scriptplan/core/resource.py +0 -0
  230. {scriptplan-0.10.1 → scriptplan-0.10.3}/scriptplan/core/scenario.py +0 -0
  231. {scriptplan-0.10.1 → scriptplan-0.10.3}/scriptplan/core/scenario_data.py +0 -0
  232. {scriptplan-0.10.1 → scriptplan-0.10.3}/scriptplan/core/shift.py +0 -0
  233. {scriptplan-0.10.1 → scriptplan-0.10.3}/scriptplan/core/task.py +0 -0
  234. {scriptplan-0.10.1 → scriptplan-0.10.3}/scriptplan/core/timesheet.py +0 -0
  235. {scriptplan-0.10.1 → scriptplan-0.10.3}/scriptplan/core/timezones.py +0 -0
  236. {scriptplan-0.10.1 → scriptplan-0.10.3}/scriptplan/parser/__init__.py +0 -0
  237. {scriptplan-0.10.1 → scriptplan-0.10.3}/scriptplan/parser/macro_processor.py +0 -0
  238. {scriptplan-0.10.1 → scriptplan-0.10.3}/scriptplan/parser/report_builder.py +0 -0
  239. {scriptplan-0.10.1 → scriptplan-0.10.3}/scriptplan/parser/transformer_project.py +0 -0
  240. {scriptplan-0.10.1 → scriptplan-0.10.3}/scriptplan/parser/transformer_report.py +0 -0
  241. {scriptplan-0.10.1 → scriptplan-0.10.3}/scriptplan/py.typed +0 -0
  242. {scriptplan-0.10.1 → scriptplan-0.10.3}/scriptplan/report/__init__.py +0 -0
  243. {scriptplan-0.10.1 → scriptplan-0.10.3}/scriptplan/report/report.py +0 -0
  244. {scriptplan-0.10.1 → scriptplan-0.10.3}/scriptplan/report/report_base.py +0 -0
  245. {scriptplan-0.10.1 → scriptplan-0.10.3}/scriptplan/report/report_context.py +0 -0
  246. {scriptplan-0.10.1 → scriptplan-0.10.3}/scriptplan/report/resource_report.py +0 -0
  247. {scriptplan-0.10.1 → scriptplan-0.10.3}/scriptplan/report/table_cells.py +0 -0
  248. {scriptplan-0.10.1 → scriptplan-0.10.3}/scriptplan/report/table_headers.py +0 -0
  249. {scriptplan-0.10.1 → scriptplan-0.10.3}/scriptplan/report/table_report.py +0 -0
  250. {scriptplan-0.10.1 → scriptplan-0.10.3}/scriptplan/report/task_report.py +0 -0
  251. {scriptplan-0.10.1 → scriptplan-0.10.3}/scriptplan/report/text_report.py +0 -0
  252. {scriptplan-0.10.1 → scriptplan-0.10.3}/scriptplan/scheduler/__init__.py +0 -0
  253. {scriptplan-0.10.1 → scriptplan-0.10.3}/scriptplan/scheduler/scoreboard.py +0 -0
  254. {scriptplan-0.10.1 → scriptplan-0.10.3}/scriptplan/utils/__init__.py +0 -0
  255. {scriptplan-0.10.1 → scriptplan-0.10.3}/scriptplan/utils/data_cache.py +0 -0
  256. {scriptplan-0.10.1 → scriptplan-0.10.3}/scriptplan/utils/logger.py +0 -0
  257. {scriptplan-0.10.1 → scriptplan-0.10.3}/scriptplan.egg-info/dependency_links.txt +0 -0
  258. {scriptplan-0.10.1 → scriptplan-0.10.3}/scriptplan.egg-info/entry_points.txt +0 -0
  259. {scriptplan-0.10.1 → scriptplan-0.10.3}/scriptplan.egg-info/requires.txt +0 -0
  260. {scriptplan-0.10.1 → scriptplan-0.10.3}/scriptplan.egg-info/top_level.txt +0 -0
  261. {scriptplan-0.10.1 → scriptplan-0.10.3}/setup.cfg +0 -0
  262. {scriptplan-0.10.1 → scriptplan-0.10.3}/setup.py +0 -0
  263. {scriptplan-0.10.1 → scriptplan-0.10.3}/tests/test_account.py +0 -0
  264. {scriptplan-0.10.1 → scriptplan-0.10.3}/tests/test_ansi_color.py +0 -0
  265. {scriptplan-0.10.1 → scriptplan-0.10.3}/tests/test_attribute_base.py +0 -0
  266. {scriptplan-0.10.1 → scriptplan-0.10.3}/tests/test_audit_probes.py +0 -0
  267. {scriptplan-0.10.1 → scriptplan-0.10.3}/tests/test_cli.py +0 -0
  268. {scriptplan-0.10.1 → scriptplan-0.10.3}/tests/test_core_allocation.py +0 -0
  269. {scriptplan-0.10.1 → scriptplan-0.10.3}/tests/test_core_booking.py +0 -0
  270. {scriptplan-0.10.1 → scriptplan-0.10.3}/tests/test_core_project.py +0 -0
  271. {scriptplan-0.10.1 → scriptplan-0.10.3}/tests/test_core_resource.py +0 -0
  272. {scriptplan-0.10.1 → scriptplan-0.10.3}/tests/test_core_scenario.py +0 -0
  273. {scriptplan-0.10.1 → scriptplan-0.10.3}/tests/test_core_task.py +0 -0
  274. {scriptplan-0.10.1 → scriptplan-0.10.3}/tests/test_journal.py +0 -0
  275. {scriptplan-0.10.1 → scriptplan-0.10.3}/tests/test_macro_processor.py +0 -0
  276. {scriptplan-0.10.1 → scriptplan-0.10.3}/tests/test_message_handler.py +0 -0
  277. {scriptplan-0.10.1 → scriptplan-0.10.3}/tests/test_plan_cli.py +0 -0
  278. {scriptplan-0.10.1 → scriptplan-0.10.3}/tests/test_project_isolation.py +0 -0
  279. {scriptplan-0.10.1 → scriptplan-0.10.3}/tests/test_property_list.py +0 -0
  280. {scriptplan-0.10.1 → scriptplan-0.10.3}/tests/test_property_tree_node.py +0 -0
  281. {scriptplan-0.10.1 → scriptplan-0.10.3}/tests/test_report.py +0 -0
  282. {scriptplan-0.10.1 → scriptplan-0.10.3}/tests/test_scoreboard.py +0 -0
  283. {scriptplan-0.10.1 → scriptplan-0.10.3}/tests/test_shift.py +0 -0
  284. {scriptplan-0.10.1 → scriptplan-0.10.3}/tests/test_timesheet.py +0 -0
  285. {scriptplan-0.10.1 → scriptplan-0.10.3}/tests/test_utils_time.py +0 -0
@@ -0,0 +1,502 @@
1
+ # Changelog
2
+
3
+ ## 0.10.3
4
+
5
+ Fixes the defects Trace and Siambr reported against 0.10.2, and those found while fixing
6
+ them. Two are regressions, one in 0.10.2 and one in 0.10.0. Three of the fixes can move
7
+ the dates of a project that already scheduled, and they are listed first.
8
+
9
+ ### Fixes that can move an existing schedule
10
+
11
+ - Tasks of equal priority were placed in declaration order. The README has always said
12
+ they are placed by criticalness, which no code computed until this release. A
13
+ resource's criticalness is the effort asked of it divided by the time it has. A task's
14
+ is its effort times the mean criticalness of the resources it may use, and its path
15
+ criticalness adds the heaviest chain of tasks that follow it. In practice the larger
16
+ effort is placed first. Tasks of 4 h, 1 h and 4 h on one desk used to run t0, t1, t2
17
+ and now run t0, t2, t1, which is the reference scheduler's order forwards, backwards
18
+ and under a daily cap. Give a task a `priority` to fix its place.
19
+ - A task with a stated `start` and `end` and no effort booked none of the resources it
20
+ allocates. With `a` at priority 600 from 18:00 to 20:00 on a resource and `w` needing
21
+ an hour of the same resource from 18:00, 0.10.2 placed `w` at 18:00, inside `a`. `a`
22
+ now holds the resource and `w` runs 20:00-21:00. Where two such tasks overlap on one
23
+ resource, the one placed first holds the shared hours. The other keeps its dates and
24
+ books what is left, and neither is an error.
25
+ - A project's `workinghours`, a global `leaves` and a shift's `leaves` now take effect
26
+ (next section). A project that sets any of them gets different dates, and they are
27
+ the dates it asked for.
28
+
29
+ ### Calendar
30
+
31
+ Siambr reported the first three.
32
+
33
+ - A project's `workinghours` was parsed and never applied. `length`, `gaplength` and a
34
+ resource with no hours of its own used Monday to Friday 09:00-17:00 whatever the
35
+ project said. With `workinghours mon - sat 09:00 - 17:00`, three days from Thursday
36
+ 3 December ended on Monday the 7th. They now end on Saturday the 5th.
37
+ - A global `leaves` did not close the calendar that `length` and `gaplength` count in,
38
+ although a global `vacation` did. `length 3d` from 24 December with
39
+ `leaves holiday "Christmas" 2026-12-25` ended on the 28th. It now ends on the 29th,
40
+ for any leave type and for a leave of part of a day.
41
+ - A shift's `leaves` was dropped when the file was read, because the parser kept the
42
+ word `holiday` and lost the date. A resource on the shift now takes the shift's leave
43
+ with its hours.
44
+ - A global `vacation` in the first week of a project in UTC was repeated every week for
45
+ a resource on the default hours. Ten days of effort from Monday 7 December with a
46
+ vacation on the 8th ended on the 23rd. They now end on the 21st.
47
+ - Because each `leaves`, `vacation` or `booking` line on a resource stored the earlier
48
+ ones again, N lines kept 2^N - 1 entries and an availability check walked them all.
49
+ The dates were right, but the time doubled with each line, and Siambr measured 58
50
+ seconds for 20 leave days. Twenty lines now store twenty entries and schedule in
51
+ half a second.
52
+ - A day that no `workinghours` line of a block names is not worked, for a project as
53
+ for a shift or a resource. This is unchanged and is now written down, because other
54
+ schedulers of this format keep the inherited hours on such a day.
55
+
56
+ ### Accepted and ignored
57
+
58
+ `audit/evaluations/probe_directive_effect.py` now checks every directive the grammar
59
+ accepts. It found these, beyond the calendar ones above.
60
+
61
+ - Allocating a resource that has members failed with "could not be scheduled". It now
62
+ allocates every member, and 16 hours on a group of two takes one day.
63
+ - `allocate r { limits { ... } }` was parsed and never applied. It is now refused, and
64
+ the error says to put the limits on the task.
65
+ - `dailymin`, `weeklymin`, `monthlymin` and `minimum` were counted and never reported.
66
+ A period in which a resource or task was booked for less than its minimum now draws
67
+ a warning. The schedule and the exit code are unchanged.
68
+ - `plan report` now prints warnings to stderr when the run succeeds. It used to discard
69
+ them, including the one that says a task asked to be scheduled as late as possible
70
+ and was scheduled as soon as possible because nothing fixed when it must end.
71
+ - An attribute the reader could not turn into a name and a value was skipped. It is an
72
+ error now. The one case left on purpose is the value of a custom attribute declared
73
+ with `extend`, which ScriptPlan does not keep (README, known limits).
74
+
75
+ ### Regressions
76
+
77
+ - A `!` reference whose scope is a task bound a task elsewhere in the project when that
78
+ scope had no such child. `g.b` with `depends !a` and no sibling `a` was scheduled after
79
+ `h.a`, an unrelated task in another branch. 0.10.1 refused the file, and 0.10.3
80
+ refuses it again. A reference with no `!`, or whose `!`s reach the top level of the
81
+ project, still binds the only task with that id, and one that could mean two tasks is
82
+ still refused. This was a regression in 0.10.2.
83
+ - A task that depends on a container nested two or more levels deep never started. With
84
+ `p { m { w } }` and `s depends p`, 0.10.0 to 0.10.2 reported "Task 's' could not be
85
+ scheduled: no ready predecessor or successor". Containers were marked done in one
86
+ pass in declaration order, so p was checked before m and never marked. s now starts
87
+ 09:30, when w ends, as 0.9.2 and the reference scheduler place it.
88
+
89
+ ### Fixed
90
+
91
+ - A container that depends on another with a gap, `gaplength` or `onstart` never
92
+ scheduled its children. `q { depends p { gapduration 30min } }` reported "Task 'q.c'
93
+ could not be scheduled: no ready predecessor or successor" in 0.10.0 to 0.10.2, and
94
+ 0.9.2 left q.c without dates and said nothing. Inheriting the dependency copied the
95
+ task `p` it names, and q.c waited for the copy, which is never scheduled. q.c now
96
+ runs 10:00-11:00, 30 minutes after p ends, which is the reference scheduler's answer.
97
+ An attribute that names a task, resource, account or shift keeps naming that same
98
+ one when a child inherits it.
99
+ - A task scheduled as late as possible inside a container was not bounded by a
100
+ successor that depends on the container. With `q depends p` and q.c ending Monday
101
+ 17:30, 0.9.2 to 0.10.1 placed p.p1 on Friday the 20th, after q.c, and said nothing.
102
+ 0.10.2 refused the plan. p.p1 now ends when q.c starts, or 30 minutes earlier with
103
+ `gapduration 30min`. The same holds for a task nested deeper inside p.
104
+ - `precedes` dropped its options. `a precedes b { gapduration 30min }` let b start the
105
+ moment a ended, and `gaplength` and `maxgapduration` were dropped the same way, with
106
+ nothing said. They now hold b back exactly as `b depends a` with the same option
107
+ does, in both directions; the backward cases match the reference scheduler.
108
+ `precedes b { onend }` is refused, because ScriptPlan cannot tie a task to another's
109
+ end, where 0.10.2 dropped it.
110
+ - When a task broke a dependency on a container, the error was printed twice, and it
111
+ quoted the task's actual start as the start the file declares. It is printed once,
112
+ and names the declared start when that differs.
113
+ - A milestone took a start inherited from its container as fixed. With the container
114
+ starting Monday 09:00 and the milestone depending on a task that ends at 17:00, 0.10.1
115
+ dated the milestone 09:00 and 0.10.2 refused the plan. The inherited start is now an
116
+ earliest start, as it already was for tasks with work, so the milestone sits at 17:00.
117
+ A start stated on the milestone itself is still fixed.
118
+ - An unresolved `depends` or `precedes` was reported as "not a task in this project",
119
+ even when a task with that id existed elsewhere. The error now says the reference
120
+ names no task from where it is written.
121
+
122
+ ### Documentation
123
+
124
+ - README now says that a task ranked higher takes a resource's daily or weekly
125
+ allowance first, so a lower-ranked task that started earlier can finish later. Trace
126
+ asked about a task that waited two days for 15 minutes on a capped resource. 0.10.2
127
+ and the hour-level reference scheduler give that schedule, and 0.10.1 gives it too at
128
+ 15-minute slots. 0.10.1 differed only at 30-minute slots, because of the skipped-time
129
+ regression that 0.10.2 fixed.
130
+
131
+ ### Verification
132
+
133
+ `tests/test_scope_and_inherited_start.py` runs six plans through the `plan` CLI. The
134
+ three for the defects fail on 0.10.2, and the three that check what must not change pass
135
+ on both versions. `tests/test_container_dependencies.py` runs 18 plans with container
136
+ dependencies and `precedes`, checked against the reference scheduler where it accepts
137
+ the plan and worked out by hand where it does not, and all 18 fail on 0.10.2.
138
+
139
+ `tests/test_project_calendar.py` and `tests/test_contention_and_bookings.py` run 33
140
+ plans for the calendar, booking and ordering fixes. Their expected dates are the
141
+ reference scheduler's, apart from the one test of the unnamed-days rule. 28 of them
142
+ fail on 0.10.2 and the 5 that check what must not change pass on both.
143
+ `probe_directive_effect.py` holds a pair of projects for each of 52 directives and
144
+ fails on 0.10.2 for nine of them. 150 random projects with contended resources give the
145
+ reference scheduler's dates exactly. Before the ordering fix, 8 of 80 did not.
146
+
147
+ No golden snapshot changes, but five example answers in `examples/edge_cases` do,
148
+ because they assumed declaration order between tasks of equal priority:
149
+ `shared_slot_forward_5min`, `shared_slot_forward_60min`, `shared_slot_backward`,
150
+ `daily_cap_counts_worked_time` and `eight_efforts_fill_whole_days`. Four probes that
151
+ assumed the same are updated. Trace's 16 project files give the same result as on
152
+ 0.10.2, apart from the two this release was meant to fix.
153
+
154
+ Free-threaded Python builds were not exercised, nor Python 3.10 to 3.12 for the full
155
+ suite.
156
+
157
+ ## 0.10.2
158
+
159
+ 0.10.1 shipped two regressions. This release fixes them and the gaps 0.10.1 listed as
160
+ not fixed. It also fixes the defects found while checking every example project
161
+ against answers worked out without the engine, and the thirteen that Trace reported.
162
+ Several plans that 0.10.1 scheduled silently and wrongly are now refused with an error
163
+ that names the task and the date it cannot keep.
164
+
165
+ ### Regressions in 0.10.1
166
+
167
+ - An alap `duration` or `length` task before a successor that starts inside a slot
168
+ ended after that successor started. Before a task starting at 16:20, a 1-hour
169
+ duration ran 16:00-17:00. It now runs 15:20-16:20. 0.10.0 put it at 15:00-16:00.
170
+ - Time a task skipped to honour a mid-slot start or end was lost to every other task.
171
+ After an alap task that had to end at 14:30, a task free from 14:00 ran 15:00-16:00
172
+ instead of 14:30-15:30. Before a task declared to start at 09:30, a task free from
173
+ 09:00 was pushed to 10:00 instead of using 09:00-09:30.
174
+
175
+ Each booking now holds its own interval of the slot, so time a task skips stays free
176
+ and a task that finishes early frees only what follows it.
177
+
178
+ ### Fixed: wrong schedules
179
+
180
+ - A `duration` or `length` task after a task ending mid-slot started at the top of
181
+ that slot, before its predecessor finished. It now starts when the predecessor ends
182
+ and lasts its duration or length to the second.
183
+ - A `duration` waited for working time. After a task ending Friday 17:00 a 2-hour
184
+ duration ran Monday 09:00-11:00, and it now runs Friday 17:00-19:00. An alap 2-hour
185
+ duration that had to end on a Sunday spanned 48 hours, and it now spans 2.
186
+ - A task's finish depended on `timingresolution` when several people shared its last
187
+ slot, because only the first of them worked it. In `tutorial.tjp` the project ended
188
+ at 12:48, 12:00 or 11:44 depending on the slot size alone. All of them now work the
189
+ last slot, and the answer is the same at every resolution.
190
+ - An alap milestone sat a slot before the moment it had to be at. Before a task
191
+ starting at 16:00 it was placed at 15:00. It now sits at 16:00, and one with no
192
+ successor sits at the project end.
193
+ - An alap task did not keep the gap its successor asked for. With `gapduration 24h`
194
+ it ended where the successor began, and now it ends 24 hours earlier.
195
+ - An alap task with an `end` of its own ignored its successors and could end after
196
+ one had started. It now ends by the earlier of the two.
197
+ - An alap task whose successor states its start was moved to the project start, as
198
+ though nothing bounded it. It now ends as late as that start allows.
199
+ - A `start` inherited from a container overrode the task's dependencies. It is now an
200
+ earliest start, and the task waits for what it depends on.
201
+
202
+ ### Fixed: silent wrong schedules are now errors
203
+
204
+ Each of these exits non-zero with a message naming the task and both dates:
205
+
206
+ - a task that would start before a task it depends on ends, including when its own
207
+ `start` says so, with or without a gap, and for milestones;
208
+ - a stated `end` that a task scheduled as soon as possible, or its container, cannot
209
+ meet, which 0.10.1 overran by hours;
210
+ - a stated `start` that an alap task cannot keep;
211
+ - a stated start or end outside the project window. A start after the window used to
212
+ crash with "Error parsing project file: list index out of range", and an end after
213
+ it was clamped while the milestone was dated outside the project.
214
+
215
+ An alap task that cannot fit before its deadline now names that deadline. A task
216
+ whose successor failed is reported as blocked by it. 0.10.1 blamed the project window
217
+ for the first, and moved the second to the start of the project, booked after the
218
+ deadline.
219
+
220
+ ### Fixed: other
221
+
222
+ - A reference that could mean two tasks with the same id bound whichever came first.
223
+ It is now an error that lists both.
224
+ - `getAllocatedTime()` and timesheet figures credited a shared slot to the last task
225
+ booked in it. 40, 13 and 40 minutes in one hour read as 0, 0 and 2 hours, and now
226
+ read as 0.67, 0.22 and 0.67.
227
+ - Each `ProjectFileParser()` compiled the grammar again (about 0.7 s). The grammar is
228
+ now compiled once per process.
229
+ - The `plan` CLI scheduled every project twice and reported any exception raised
230
+ while scheduling as a parse error. It now schedules each project once and reports
231
+ a scheduling exception as a scheduling error.
232
+ - Projects scheduled in parallel threads shared one message list, one error count
233
+ and one switch that turns error collection on. When one thread finished scheduling,
234
+ another thread's error could raise `TjRuntimeError` out of `schedule()` instead of
235
+ making it return False, and an error in one project could fail another. Each thread
236
+ now has its own messages, error count and switch.
237
+ - An `effort` task with no resource allocated was reported as running outside the
238
+ project window because it "needs more time or more resource availability". It is now
239
+ reported as having effort but no resource to do it.
240
+ - `plan report` printed every engine error as "Error: Error: …". It now prints one
241
+ "Error:".
242
+
243
+ ### Documentation
244
+
245
+ - README described `onstart` as one reading for both directions. For a task scheduled
246
+ as soon as possible it is start-to-start. For one scheduled as late as possible it
247
+ means the task must finish before the predecessor starts.
248
+ - README now says that `length` and `gaplength` count the project's working time, how
249
+ an alap task's end is bounded, and that unkept stated dates are errors.
250
+ - README listed `maxgaplength` among the checked constraints. The syntax has never
251
+ accepted it, and the claim is removed.
252
+
253
+ ### Schedules that move
254
+
255
+ A plan whose dates all fall on its slot grid, with no alap milestones and no
256
+ `duration` across non-working time, schedules as it did in 0.10.1. Of the 24 example
257
+ projects, 22 schedule identically:
258
+
259
+ - `tutorial.tjp`: `spec` ends 14:20 instead of 15:00 on 24 January because three
260
+ developers finish it together, and every task after it moves with it. The project
261
+ ends on 18 April at 11:44 instead of 12:48.
262
+ - `jit_supply.tjp`: the alap milestone `connection_setup.set_deps` sits at 2025-07-18
263
+ 08:00, when `pack` starts, instead of 2025-07-17 16:00.
264
+
265
+ ### Internal API
266
+
267
+ `ResourceScenario.reserve()` returns a list of `SlotBooking`, one per free stretch it
268
+ books. The slot ledger is `slotIntervals`, and `slotFrontUsed` and `slotBackUsed` from
269
+ 0.10.1 are gone. Failure handling moved to `scriptplan.scheduler.stalls`, and stated
270
+ dates are tracked in `scriptplan.core.declared_dates`. `slotSecondsUsed` is now
271
+ exactly the sum of `slotTaskUsage` for every slot.
272
+
273
+ ### Verification
274
+
275
+ The golden snapshots record what the engine produced last time. They catch a change
276
+ but not an error, and 0.10.1 passed all of them. `examples/` now holds an answer for every
277
+ task in the 24 showcase projects and in 24 edge cases, each derived by hand from
278
+ the file and the documented semantics without running ScriptPlan, and compared with an
279
+ hour-level reference scheduler wherever it accepts the file. `tests/test_examples.py`
280
+ runs each project through the `plan` CLI and compares every task to the second. Every
281
+ project passes on 0.10.2, and 13 of the edge cases fail on 0.10.1.
282
+
283
+ `audit/evaluations/probe_placement.py` generates 300 plans that mix effort, duration,
284
+ length and milestones in both directions. It checks that every dependency, stated date
285
+ and span holds, that no slot is overfull, and that no task leaves free time it could
286
+ have used. All 300 pass on 0.10.2, against 28 on 0.10.1 and 14
287
+ on 0.10.0.
288
+
289
+ `tests/test_threads.py` schedules five projects three times each in parallel threads
290
+ and compares every date and message with the same project scheduled alone. It also
291
+ forces one thread to leave error collection while another is still inside it. Its
292
+ three tests fail on the 0.10.1 message handler.
293
+
294
+ The full gate runs on Python 3.9 and 3.13.
295
+
296
+ ## 0.10.1
297
+
298
+ Tasks that shared a timing slot on one resource could be booked into time that
299
+ does not exist. Three tasks of 40, 13 and 40 minutes on one person at
300
+ `timingresolution 60min` all started at 09:00, and the 09:00 slot held 5580
301
+ seconds of work without any warning. Every release from 0.9.0 to 0.10.0 has
302
+ the defect. Trace's scheduling harness found it.
303
+
304
+ When a task finished part-way through a slot, the engine gave the rest of that
305
+ slot back as if the task had booked all of it, even when an earlier task had
306
+ already used the front of the slot. It also placed every later task at the top
307
+ of the slot. Each booking now records where in the slot it sits. Forward work
308
+ fills a slot from its start and backward (`alap`) work from its end, and a task
309
+ that finishes early hands back only the part of its own booking it did not use.
310
+ The same three tasks now run 09:00-09:40, 09:40-09:53 and 09:53-10:33 at any
311
+ resolution.
312
+
313
+ ### Fixed
314
+
315
+ - A task whose first slot was partly used reported its start at the top of that
316
+ slot. At 5-minute resolution the third task above started at 09:50 while the
317
+ second ran until 09:53. It now starts at 09:53.
318
+ - `alap` tasks sharing a slot overbooked it the same way. They now fill it
319
+ backwards from the end without overlapping.
320
+ - When several resources finished a task in the same slot, only one of them
321
+ handed back its unused time. 80 minutes of effort on two people ended at
322
+ 10:00 and cost two hours. It now ends at 09:40 and costs 80 minutes.
323
+ - Time handed back was not returned to `limits`. Under `dailymax 60min` the
324
+ three tasks above took Monday, Tuesday and Wednesday, and the person worked
325
+ 40 minutes on Monday. They now use exactly 60 minutes on Monday and finish on
326
+ Tuesday at 09:33.
327
+ - A task that could start mid-slot because its predecessor ended there was kept
328
+ out of the first part of every slot until it booked something. When the
329
+ resource was busy in that slot, the task lost the same minutes in the next
330
+ one, and a task free to start at 10:00 started at 10:50.
331
+ - A `start` inside a slot was rounded down. `start 2026-10-19-09:30` at 60-minute
332
+ resolution started at 09:00, half an hour before the date in the file. A
333
+ mid-slot `end` on an `alap` task was also rounded down to the start of its
334
+ slot. Both are now honoured to the minute.
335
+ - A milestone after a task that ended mid-slot sat at the top of that slot,
336
+ before its predecessor had finished. It now sits at the moment the
337
+ predecessor ends.
338
+
339
+ ### Schedules that move
340
+
341
+ A plan in which no work starts or ends inside a slot schedules as it did in
342
+ 0.10.0. Results change where efforts are off the slot grid, where an efficiency
343
+ other than 1 makes work end mid-slot, where several resources share a task, and
344
+ where a date falls inside a slot. Of the 24 example projects, 22 schedule
345
+ identically to 0.10.0:
346
+
347
+ - `airport_stress_test.tjp`: `t_install` starts at 11:40 instead of 11:00,
348
+ which is when the electrician finishes `t_crit`. `t_low` starts at 10:20
349
+ instead of 10:00 for the same reason. Both keep the end times they had.
350
+ - `tutorial.tjp`: `test.alpha` ends at 11:36 instead of 12:00 on 3 April because
351
+ both people on it stop together. `test.beta` and the project finish at 12:48
352
+ instead of 13:00, and the `beta` and `done` milestones follow.
353
+
354
+ ### Not fixed in this release
355
+
356
+ A `duration` or `length` task that depends on a task ending mid-slot still
357
+ starts at the top of that slot, before its predecessor has finished. After a
358
+ task ending at 09:40, `duration 2h` is reported as 09:00-11:00. 0.10.0 does the
359
+ same. `TaskScenario.getAllocatedTime()` still credits a shared slot to the last
360
+ task booked in it, although cost is correct.
361
+
362
+ ### Internal API
363
+
364
+ `ResourceScenario.book()` takes a `forward` argument. `reserve()` and
365
+ `release()` are new and return or take a `SlotBooking` from
366
+ `scriptplan.core.slot_ledger`. `markSlotPartiallyUsed()` and
367
+ `releasePartialSlot()` had no callers and are removed. `slotSecondsUsed` also
368
+ counts the time a task skips to honour a mid-slot start or end. To measure the work
369
+ booked in a slot, sum `slotTaskUsage`.
370
+
371
+ ### Verification
372
+
373
+ The probe named "Two tasks sharing one resource never double-book a slot" used
374
+ efforts of whole hours, which never share a slot, and it checked the total
375
+ booked, which stays correct when work overlaps. Every capacity check in the
376
+ harness read `slotSecondsUsed`, and the defect lowered that counter in the same
377
+ step that overbooked the slot. None of them could fail on this defect.
378
+
379
+ `audit/evaluations/probe_slot_sharing.py` checks each slot against what was
380
+ booked into it, compares the CLI's report with dates worked out by hand, and
381
+ runs 360 seeded random plans, 240 of them with efforts anywhere from 1 to 600
382
+ minutes. Against 0.10.0 all nine of its probes fail, including the 490-minute
383
+ day Trace reported, and 115 of those 240 plans break at least one of its
384
+ checks. Against 0.10.1 all nine pass. The harness now sums `slotTaskUsage`
385
+ wherever it measures booked time.
386
+
387
+ ## 0.10.0
388
+
389
+ A readiness audit of 0.9.2 turned every documented claim into a probe that
390
+ drives ScriptPlan through its own API or CLI. 32 of those probes failed. This
391
+ release is what it took to make them pass, and it changes scheduling results.
392
+
393
+ ### Breaking: `effort` is person-time
394
+
395
+ `effort 16h allocate a, b` used to occupy both resources for sixteen hours and
396
+ credit sixteen hours of work. Two resources booked thirty-two hours, four booked
397
+ sixty-four, and the completion date never moved however many were assigned. The
398
+ engine took the largest contribution in each slot rather than the sum, so the
399
+ labour of every resource but one was booked, billed and discarded.
400
+
401
+ Effort is now the amount of work to be done, and each allocated resource
402
+ contributes its own time towards it, as the .tjp format defines it. The same task
403
+ with two resources finishes in half the time and costs what one resource's worth
404
+ of work costs.
405
+
406
+ **Upgrading.** A task whose allocations were meant to work side by side is
407
+ written with `mandatory` and its effort in person-hours:
408
+
409
+ ```
410
+ # before 0.10.0: four hours of a pair working together
411
+ task deploy "Deploy" { effort 4h allocate dev, qa }
412
+
413
+ # 0.10.0 and after
414
+ task deploy "Deploy" { effort 8h allocate dev { mandatory }, qa { mandatory } }
415
+ ```
416
+
417
+ Tasks with a single allocation are unaffected. Of the 24 example projects, 21
418
+ schedule identically to 0.9.2; the three that differ are those that allocate
419
+ more than one resource to a task.
420
+
421
+ ### Breaking: failures are reported as failures
422
+
423
+ `Project.schedule()` always returned `True`, and the CLI exited 0 with empty
424
+ start and end cells. A circular dependency, an effort task with no allocation,
425
+ or a task that did not fit the project window produced a warning nobody saw.
426
+
427
+ Scheduling now returns the real result and names each failing task and why; the
428
+ CLIs exit non-zero. A dependency cycle is rejected before scheduling, naming the
429
+ cycle. An attribute or reference the parser cannot place is an error rather than
430
+ a silent drop, which is how `duration`, `length`, `complete` and `note` reached
431
+ the model for the first time.
432
+
433
+ ### Breaking: the declared project period is honoured
434
+
435
+ The project end was grown by a heuristic before scheduling. It is now taken as
436
+ written, and a task that does not fit is reported. Projects that relied on the
437
+ extension need their period stated honestly.
438
+
439
+ ### Breaking: unimplemented report formats are rejected
440
+
441
+ `ical`, `tjp`, `niku`, `ctags` and MS Project XML were accepted, wrote no file,
442
+ and left the CLI blaming a scheduling problem that did not exist. They now raise
443
+ at parse time. Use `json` or `csv`.
444
+
445
+ ### Fixed
446
+
447
+ - Durations follow one table: `m` is months and `min` is minutes everywhere;
448
+ `duration` and `gapduration` are calendar time, `effort`, `length` and
449
+ `gaplength` working time derived from `dailyworkinghours` and
450
+ `yearlyworkingdays`. `gapduration 2d` was 16 hours; `gaplength 30min` was no
451
+ gap at all; `limits { dailymax 30min }` was a 4800-hour cap.
452
+ - Limits count seconds in the resource's own calendar and admit part of a slot,
453
+ so `dailymax 6.4h` is exact. A resource in Los Angeles capped at four hours a
454
+ day was working five in one of its own days. `dailymin`, `weeklymin`,
455
+ `monthlymax`, `monthlymin`, `maximum` and `minimum` reach the grammar, as do
456
+ `maxend`, `maxstart`, `minend` and `minstart`, and violations are reported.
457
+ - Dates are read in the project's timezone and scheduled in UTC; reports convert
458
+ back. The default working day was compared against the hour of a UTC slot,
459
+ putting a New York project five hours out.
460
+ - Slot size is derived from the times a project uses, so `start 09:30` and a
461
+ shift of `08:13 - 11:59` are exact without setting `timingresolution`. That
462
+ shift was credited with seven hours a day instead of eight and a half.
463
+ - A working-hours interval crossing midnight applies to the following day.
464
+ `fri 22:00 - 06:00` marked Friday morning instead of Saturday.
465
+ - Chains mixing ASAP and ALAP schedule instead of deadlocking.
466
+ - Scheduling twice gives the same dates and the same bookings. The second run
467
+ kept the dates and discarded every booking.
468
+ - Reports honour their own `sorttasks`, `hidetask`, column options and formats,
469
+ and `plan report` renders the reports a project declares rather than
470
+ substituting a three-column one. Descending sort was a no-op, and any filter
471
+ hid every row.
472
+ - `report_id` is a SHA-256 of the rendered result. It hashed the input file, so
473
+ a correct and a broken schedule of the same input shared an id.
474
+ - `mandatory`, `persistent` and per-resource allocation options work; they
475
+ parsed to nothing.
476
+
477
+ ### Removed
478
+
479
+ - The Cython extensions. Under `cdivision` the compiled path computed
480
+ `(0 - 1) % 7` as `-1`, so a resource with a Sunday night shift lost its Monday
481
+ morning in every published wheel and kept it in every source checkout: the
482
+ same file, two schedules, and no test covering the compiled one. The wheel is
483
+ now pure Python and cannot diverge from its source.
484
+ - `scheduler.batch_processor`, `utils.data_cache.DataCache` and `utils.Log`,
485
+ none of which were reachable.
486
+
487
+ ### Performance
488
+
489
+ 500 chained tasks at minute resolution schedule in 3.3s, from 14.4s. A year at
490
+ minute resolution with ten resources takes about 13s, from 58.7s.
491
+
492
+ ### Verification
493
+
494
+ `audit/evaluations/` holds 74 probes across 12 files, each named after the
495
+ behaviour it would falsify and each driving ScriptPlan through its own
496
+ interface. `scripts/ci.sh` runs lint, types, a file-size cap, 411 tests, a
497
+ showcase currency check and the probes. The probes also pass against the built
498
+ wheel installed in a clean virtualenv, so what is verified is what ships.
499
+
500
+ ## 0.9.2 and earlier
501
+
502
+ See the git history.
@@ -4,3 +4,4 @@ include CHANGELOG.md
4
4
  include pyproject.toml
5
5
  recursive-include scriptplan *.lark
6
6
  recursive-include scriptplan py.typed
7
+ recursive-include examples *.tjp *.csv *.md