monkeybrain-runtime 1.0.0__py3-none-any.whl

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 (838) hide show
  1. monkeybrain_runtime-1.0.0.dist-info/METADATA +76 -0
  2. monkeybrain_runtime-1.0.0.dist-info/RECORD +838 -0
  3. monkeybrain_runtime-1.0.0.dist-info/WHEEL +5 -0
  4. monkeybrain_runtime-1.0.0.dist-info/entry_points.txt +3 -0
  5. monkeybrain_runtime-1.0.0.dist-info/top_level.txt +2 -0
  6. services/__init__.py +8 -0
  7. services/agentos/__init__.py +0 -0
  8. services/agentos/main.py +1 -0
  9. services/assets/helpers/__init__.py +12 -0
  10. services/assets/helpers/device.py +59 -0
  11. services/assets/helpers/equipment.py +179 -0
  12. services/assets/helpers/instruments.py +72 -0
  13. services/assets/helpers/machines.py +183 -0
  14. services/assets/helpers/materials.py +76 -0
  15. services/assets/helpers/parts.py +116 -0
  16. services/assets/helpers/plc.py +134 -0
  17. services/assets/helpers/tags.py +108 -0
  18. services/assets/helpers/tools.py +101 -0
  19. services/assets/main.py +75 -0
  20. services/assets/models/__init__.py +12 -0
  21. services/assets/models/device.py +79 -0
  22. services/assets/models/equipment.py +222 -0
  23. services/assets/models/instruments.py +85 -0
  24. services/assets/models/machines.py +230 -0
  25. services/assets/models/material.py +266 -0
  26. services/assets/models/parts.py +96 -0
  27. services/assets/models/plc.py +264 -0
  28. services/assets/models/tags.py +76 -0
  29. services/assets/models/tools.py +179 -0
  30. services/assets/routers/__init__.py +12 -0
  31. services/assets/routers/classes.py +65 -0
  32. services/assets/routers/device.py +86 -0
  33. services/assets/routers/equipment.py +145 -0
  34. services/assets/routers/families.py +61 -0
  35. services/assets/routers/instruments.py +70 -0
  36. services/assets/routers/machines.py +136 -0
  37. services/assets/routers/materials.py +105 -0
  38. services/assets/routers/parts.py +130 -0
  39. services/assets/routers/plc.py +94 -0
  40. services/assets/routers/subclasses.py +68 -0
  41. services/assets/routers/tags.py +138 -0
  42. services/assets/routers/tools.py +113 -0
  43. services/auth/helpers/__init__.py +13 -0
  44. services/auth/helpers/approval_decisions.py +261 -0
  45. services/auth/helpers/audit_elasticsearch_sync.py +350 -0
  46. services/auth/helpers/departments.py +53 -0
  47. services/auth/helpers/graph_store.py +848 -0
  48. services/auth/helpers/influx_store.py +280 -0
  49. services/auth/helpers/me.py +33 -0
  50. services/auth/helpers/nats_consumer.py +618 -0
  51. services/auth/helpers/nats_store.py +242 -0
  52. services/auth/helpers/permissions.py +62 -0
  53. services/auth/helpers/roles.py +87 -0
  54. services/auth/helpers/store.py +54 -0
  55. services/auth/helpers/team_members.py +155 -0
  56. services/auth/helpers/teams.py +87 -0
  57. services/auth/helpers/tokens.py +71 -0
  58. services/auth/helpers/users.py +119 -0
  59. services/auth/helpers/websocket_broadcast.py +41 -0
  60. services/auth/main.py +88 -0
  61. services/auth/models/__init__.py +12 -0
  62. services/auth/models/departments.py +55 -0
  63. services/auth/models/login.py +20 -0
  64. services/auth/models/permissions.py +61 -0
  65. services/auth/models/roles.py +53 -0
  66. services/auth/models/session.py +26 -0
  67. services/auth/models/teamMembers.py +59 -0
  68. services/auth/models/teams.py +56 -0
  69. services/auth/models/users.py +77 -0
  70. services/auth/routers/__init__.py +14 -0
  71. services/auth/routers/auth.py +3839 -0
  72. services/auth/routers/departments.py +84 -0
  73. services/auth/routers/integration_config.py +703 -0
  74. services/auth/routers/me.py +28 -0
  75. services/auth/routers/permissions.py +96 -0
  76. services/auth/routers/roles.py +139 -0
  77. services/auth/routers/session.py +224 -0
  78. services/auth/routers/team_members.py +152 -0
  79. services/auth/routers/teams.py +112 -0
  80. services/auth/routers/users.py +131 -0
  81. services/auth/routers/websocket_events.py +247 -0
  82. services/batch_execution/__init__.py +19 -0
  83. services/batch_execution/pipeline_triggers/__init__.py +53 -0
  84. services/batch_execution/pipeline_triggers/pipeline_parameter_adjuster.py +440 -0
  85. services/batch_execution/pipeline_triggers/pipeline_trigger_engine.py +445 -0
  86. services/batch_execution/pipeline_triggers/re_evaluation_queue.py +341 -0
  87. services/batch_execution/pipeline_triggers/test_phase3_implementation.py +553 -0
  88. services/batch_execution/pipeline_triggers/workflow_reevaluator.py +367 -0
  89. services/batch_execution/smoke_test_e2e_feedback_loop.py +704 -0
  90. services/batch_execution/workflow_executor.py +478 -0
  91. services/changeover/helpers/__init__.py +11 -0
  92. services/changeover/helpers/changeover.py +87 -0
  93. services/changeover/helpers/changeover_common.py +55 -0
  94. services/changeover/helpers/changeover_events.py +66 -0
  95. services/changeover/helpers/changeover_kpis.py +33 -0
  96. services/changeover/helpers/changeover_matrix.py +60 -0
  97. services/changeover/helpers/changeover_procedures.py +164 -0
  98. services/changeover/helpers/changeover_windows.py +96 -0
  99. services/changeover/main.py +52 -0
  100. services/changeover/models/__init__.py +11 -0
  101. services/changeover/models/changeover.py +73 -0
  102. services/changeover/models/changeover_events.py +142 -0
  103. services/changeover/models/changeover_kpis.py +75 -0
  104. services/changeover/models/changeover_matrix.py +63 -0
  105. services/changeover/models/changeover_procedures.py +108 -0
  106. services/changeover/models/changeover_tasks.py +87 -0
  107. services/changeover/models/changeover_windows.py +72 -0
  108. services/changeover/routers/__init__.py +9 -0
  109. services/changeover/routers/changeover_events.py +127 -0
  110. services/changeover/routers/changeover_kpis.py +80 -0
  111. services/changeover/routers/changeover_matrix.py +80 -0
  112. services/changeover/routers/changeover_procedures.py +118 -0
  113. services/changeover/routers/changeover_windows.py +98 -0
  114. services/common/__init__.py +2 -0
  115. services/common/approval_chains.py +648 -0
  116. services/common/auth.py +56 -0
  117. services/common/cdc.py +52 -0
  118. services/common/compat.py +217 -0
  119. services/common/compliance.py +562 -0
  120. services/common/config.py +134 -0
  121. services/common/cors.py +17 -0
  122. services/common/data_transformation.py +195 -0
  123. services/common/db.py +577 -0
  124. services/common/embeddings.py +97 -0
  125. services/common/event_reducers.py +194 -0
  126. services/common/event_types.py +51 -0
  127. services/common/integration_ingestion.py +169 -0
  128. services/common/logging.py +204 -0
  129. services/common/models/__init__.py +2 -0
  130. services/common/models/databricks.py +25 -0
  131. services/common/models/enums.py +64 -0
  132. services/common/module_control.py +422 -0
  133. services/common/mongo_cdc_watcher.py +106 -0
  134. services/common/n8n_auth.py +22 -0
  135. services/common/neo4j_mirror.py +1087 -0
  136. services/common/ontology_registry.py +110 -0
  137. services/common/reasoning_traces.py +52 -0
  138. services/common/supply_chain_cdc.py +555 -0
  139. services/common/tracing.py +159 -0
  140. services/common/utils.py +30 -0
  141. services/customers/helpers/__init__.py +8 -0
  142. services/customers/helpers/customer_details.py +64 -0
  143. services/customers/helpers/customer_metadata.py +64 -0
  144. services/customers/helpers/customer_order_metrics.py +67 -0
  145. services/customers/helpers/customer_payment_data.py +67 -0
  146. services/customers/main.py +50 -0
  147. services/customers/models/__init__.py +8 -0
  148. services/customers/models/customer_details.py +42 -0
  149. services/customers/models/customer_metadata.py +97 -0
  150. services/customers/models/customer_order_metrics.py +86 -0
  151. services/customers/models/customer_payment_data.py +60 -0
  152. services/customers/routers/__init__.py +8 -0
  153. services/customers/routers/customer_details.py +88 -0
  154. services/customers/routers/customer_metadata.py +88 -0
  155. services/customers/routers/customer_order_metrics.py +88 -0
  156. services/customers/routers/customer_payment_data.py +88 -0
  157. services/documents/__init__.py +1 -0
  158. services/documents/helpers/__init__.py +6 -0
  159. services/documents/helpers/document_metadata.py +569 -0
  160. services/documents/helpers/document_workflows.py +215 -0
  161. services/documents/helpers/report_templates.py +113 -0
  162. services/documents/main.py +49 -0
  163. services/documents/models/__init__.py +6 -0
  164. services/documents/models/document_metadata.py +215 -0
  165. services/documents/models/document_workflows.py +136 -0
  166. services/documents/models/report_templates.py +132 -0
  167. services/documents/routers/__init__.py +6 -0
  168. services/documents/routers/document_metadata.py +654 -0
  169. services/documents/routers/document_workflows.py +146 -0
  170. services/documents/routers/report_templates.py +86 -0
  171. services/events/helpers/__init__.py +5 -0
  172. services/events/helpers/events.py +394 -0
  173. services/events/main.py +40 -0
  174. services/events/models/__init__.py +5 -0
  175. services/events/models/events.py +50 -0
  176. services/events/routers/__init__.py +6 -0
  177. services/events/routers/count_events.py +109 -0
  178. services/events/routers/events.py +75 -0
  179. services/events/seed_events.py +196 -0
  180. services/facilities/helpers/__init__.py +8 -0
  181. services/facilities/helpers/lines.py +74 -0
  182. services/facilities/helpers/locations.py +231 -0
  183. services/facilities/helpers/plants.py +59 -0
  184. services/facilities/helpers/stages.py +110 -0
  185. services/facilities/helpers/workstation.py +213 -0
  186. services/facilities/main.py +60 -0
  187. services/facilities/models/__init__.py +10 -0
  188. services/facilities/models/industrialLine.py +72 -0
  189. services/facilities/models/industrialPlant.py +164 -0
  190. services/facilities/models/locations.py +74 -0
  191. services/facilities/models/stages.py +92 -0
  192. services/facilities/models/worker.py +73 -0
  193. services/facilities/models/workstation.py +117 -0
  194. services/facilities/models/workstation_live_state.py +59 -0
  195. services/facilities/routers/__init__.py +8 -0
  196. services/facilities/routers/bays.py +81 -0
  197. services/facilities/routers/buildings.py +92 -0
  198. services/facilities/routers/floors.py +81 -0
  199. services/facilities/routers/lines.py +154 -0
  200. services/facilities/routers/locations.py +208 -0
  201. services/facilities/routers/plant.py +203 -0
  202. services/facilities/routers/rooms.py +81 -0
  203. services/facilities/routers/stages.py +152 -0
  204. services/facilities/routers/workstation.py +173 -0
  205. services/file/backup.py +71 -0
  206. services/file/main.py +45 -0
  207. services/file/recieve.py +54 -0
  208. services/file/send.py +55 -0
  209. services/file/src/core/config.py +90 -0
  210. services/file/src/core/keycloak.py +152 -0
  211. services/file/src/core/logging_config.py +9 -0
  212. services/file/src/core/security.py +33 -0
  213. services/file/src/helpers/cad_conversion.py +331 -0
  214. services/file/src/helpers/helpers.py +825 -0
  215. services/file/src/routes/cad_conversion.py +26 -0
  216. services/file/src/routes/files.py +136 -0
  217. services/file/src/routes/presigned.py +154 -0
  218. services/file/src/services/websocket.py +293 -0
  219. services/floor_layout/helpers/__init__.py +8 -0
  220. services/floor_layout/helpers/bays.py +92 -0
  221. services/floor_layout/helpers/buildings.py +54 -0
  222. services/floor_layout/helpers/floors.py +65 -0
  223. services/floor_layout/helpers/rooms.py +76 -0
  224. services/floor_layout/main.py +52 -0
  225. services/floor_layout/models/__init__.py +8 -0
  226. services/floor_layout/models/bays.py +65 -0
  227. services/floor_layout/models/buildings.py +52 -0
  228. services/floor_layout/models/floors.py +45 -0
  229. services/floor_layout/models/rooms.py +61 -0
  230. services/floor_layout/routers/__init__.py +9 -0
  231. services/floor_layout/routers/bays.py +143 -0
  232. services/floor_layout/routers/buildings.py +116 -0
  233. services/floor_layout/routers/floors.py +89 -0
  234. services/floor_layout/routers/locations.py +80 -0
  235. services/floor_layout/routers/rooms.py +134 -0
  236. services/inventory/helpers/__init__.py +13 -0
  237. services/inventory/helpers/cycle_counts.py +124 -0
  238. services/inventory/helpers/inventory_allocations.py +134 -0
  239. services/inventory/helpers/inventory_item_counts.py +114 -0
  240. services/inventory/helpers/inventory_item_quantities.py +114 -0
  241. services/inventory/helpers/inventory_items.py +103 -0
  242. services/inventory/helpers/inventory_stage_outputs.py +134 -0
  243. services/inventory/helpers/inventory_transactions.py +112 -0
  244. services/inventory/helpers/stock_adjustment_requests.py +101 -0
  245. services/inventory/helpers/warehouse_cycle_counts.py +133 -0
  246. services/inventory/helpers/warehouse_locations.py +213 -0
  247. services/inventory/helpers/warehouse_regulated_records.py +123 -0
  248. services/inventory/main.py +62 -0
  249. services/inventory/models/__init__.py +17 -0
  250. services/inventory/models/cycle_counts.py +99 -0
  251. services/inventory/models/inventory_allocations.py +121 -0
  252. services/inventory/models/inventory_common.py +65 -0
  253. services/inventory/models/inventory_enums.py +21 -0
  254. services/inventory/models/inventory_item_count.py +65 -0
  255. services/inventory/models/inventory_item_quantity.py +82 -0
  256. services/inventory/models/inventory_items.py +168 -0
  257. services/inventory/models/inventory_responses.py +44 -0
  258. services/inventory/models/inventory_stage_outputs.py +96 -0
  259. services/inventory/models/inventory_state.py +15 -0
  260. services/inventory/models/inventory_transactions.py +80 -0
  261. services/inventory/models/stock_adjustment_requests.py +109 -0
  262. services/inventory/models/warehouse_cycle_counts.py +119 -0
  263. services/inventory/models/warehouse_location_models.py +708 -0
  264. services/inventory/models/warehouse_regulated_records.py +358 -0
  265. services/inventory/routers/__init__.py +13 -0
  266. services/inventory/routers/cycle_counts.py +106 -0
  267. services/inventory/routers/inventory_allocations.py +125 -0
  268. services/inventory/routers/inventory_item_counts.py +105 -0
  269. services/inventory/routers/inventory_item_quantities.py +105 -0
  270. services/inventory/routers/inventory_items.py +109 -0
  271. services/inventory/routers/inventory_stage_outputs.py +122 -0
  272. services/inventory/routers/inventory_transactions.py +96 -0
  273. services/inventory/routers/stock_adjustment_requests.py +124 -0
  274. services/inventory/routers/warehouse_cycle_counts.py +124 -0
  275. services/inventory/routers/warehouse_locations.py +426 -0
  276. services/inventory/routers/warehouse_regulated_records.py +273 -0
  277. services/iot/helpers/__init__.py +8 -0
  278. services/iot/helpers/ble_device.py +87 -0
  279. services/iot/helpers/mqtt_bridge.py +115 -0
  280. services/iot/helpers/sensor_readings.py +63 -0
  281. services/iot/helpers/sensors.py +77 -0
  282. services/iot/helpers/servers.py +72 -0
  283. services/iot/helpers/uwb_device.py +95 -0
  284. services/iot/main.py +53 -0
  285. services/iot/models/__init__.py +8 -0
  286. services/iot/models/ble_device.py +118 -0
  287. services/iot/models/sensors.py +256 -0
  288. services/iot/models/servers.py +206 -0
  289. services/iot/models/uwb_device.py +106 -0
  290. services/iot/routers/__init__.py +8 -0
  291. services/iot/routers/ble_device.py +110 -0
  292. services/iot/routers/sensors.py +144 -0
  293. services/iot/routers/servers.py +141 -0
  294. services/iot/routers/uwb_device.py +148 -0
  295. services/module_control/__init__.py +1 -0
  296. services/module_control/helpers/__init__.py +1 -0
  297. services/module_control/helpers/integration_config.py +243 -0
  298. services/module_control/helpers/security.py +104 -0
  299. services/module_control/main.py +44 -0
  300. services/module_control/models/__init__.py +1 -0
  301. services/module_control/models/module_control.py +65 -0
  302. services/module_control/routers/__init__.py +1 -0
  303. services/module_control/routers/module_control.py +219 -0
  304. services/orders/helpers/__init__.py +11 -0
  305. services/orders/helpers/invoices.py +123 -0
  306. services/orders/helpers/order_customer_metrics.py +61 -0
  307. services/orders/helpers/order_details.py +71 -0
  308. services/orders/helpers/order_metadata.py +61 -0
  309. services/orders/helpers/order_payment_metadata.py +74 -0
  310. services/orders/helpers/orders.py +119 -0
  311. services/orders/helpers/sales_orders.py +136 -0
  312. services/orders/main.py +56 -0
  313. services/orders/models/__init__.py +11 -0
  314. services/orders/models/invoices.py +415 -0
  315. services/orders/models/order_customer_metrics.py +78 -0
  316. services/orders/models/order_details.py +46 -0
  317. services/orders/models/order_metadata.py +60 -0
  318. services/orders/models/order_payment_metadata.py +63 -0
  319. services/orders/models/orders.py +64 -0
  320. services/orders/models/sales_orders.py +130 -0
  321. services/orders/routers/__init__.py +11 -0
  322. services/orders/routers/invoices.py +111 -0
  323. services/orders/routers/order_customer_metrics.py +87 -0
  324. services/orders/routers/order_details.py +87 -0
  325. services/orders/routers/order_metadata.py +87 -0
  326. services/orders/routers/order_payment_metadata.py +87 -0
  327. services/orders/routers/orders.py +74 -0
  328. services/orders/routers/sales_orders.py +111 -0
  329. services/pm/helpers/__init__.py +14 -0
  330. services/pm/helpers/calendar_bookings.py +114 -0
  331. services/pm/helpers/calibration_point.py +110 -0
  332. services/pm/helpers/calibrations.py +196 -0
  333. services/pm/helpers/checklists.py +318 -0
  334. services/pm/helpers/cleaning.py +333 -0
  335. services/pm/helpers/downtime.py +376 -0
  336. services/pm/helpers/kanban_boards.py +186 -0
  337. services/pm/helpers/maintainance.py +177 -0
  338. services/pm/helpers/sop.py +1155 -0
  339. services/pm/helpers/sop_cdc.py +324 -0
  340. services/pm/helpers/weekly_schedules.py +79 -0
  341. services/pm/main.py +62 -0
  342. services/pm/models/__init__.py +14 -0
  343. services/pm/models/calendar_booking.py +82 -0
  344. services/pm/models/calibration_point.py +44 -0
  345. services/pm/models/calibrations.py +167 -0
  346. services/pm/models/checklists.py +117 -0
  347. services/pm/models/cleaning.py +203 -0
  348. services/pm/models/downtime.py +109 -0
  349. services/pm/models/kanban_board.py +178 -0
  350. services/pm/models/maintainanceLog.py +148 -0
  351. services/pm/models/sop.py +152 -0
  352. services/pm/models/weekly_schedule.py +91 -0
  353. services/pm/routers/__init__.py +14 -0
  354. services/pm/routers/calendar_bookings.py +143 -0
  355. services/pm/routers/calibration_point.py +94 -0
  356. services/pm/routers/calibrations.py +232 -0
  357. services/pm/routers/checklists.py +188 -0
  358. services/pm/routers/cleaning.py +127 -0
  359. services/pm/routers/downtime.py +143 -0
  360. services/pm/routers/kanban_boards.py +283 -0
  361. services/pm/routers/maintainance.py +241 -0
  362. services/pm/routers/sop.py +437 -0
  363. services/pm/routers/weekly_schedules.py +108 -0
  364. services/process_definitions/helpers/__init__.py +11 -0
  365. services/process_definitions/helpers/cpp_cqa_registry.py +120 -0
  366. services/process_definitions/helpers/mbmr_templates.py +107 -0
  367. services/process_definitions/helpers/packing_instructions.py +113 -0
  368. services/process_definitions/helpers/process_constraints.py +495 -0
  369. services/process_definitions/helpers/process_corrections.py +279 -0
  370. services/process_definitions/helpers/process_definition.py +996 -0
  371. services/process_definitions/helpers/process_node_catalog.py +786 -0
  372. services/process_definitions/helpers/process_post_checks.py +441 -0
  373. services/process_definitions/helpers/process_pre_checks.py +351 -0
  374. services/process_definitions/helpers/process_steps.py +220 -0
  375. services/process_definitions/main.py +71 -0
  376. services/process_definitions/models/__init__.py +13 -0
  377. services/process_definitions/models/cpp_cqa_registry.py +145 -0
  378. services/process_definitions/models/gxp_change_controls.py +38 -0
  379. services/process_definitions/models/gxp_risk_assessments.py +30 -0
  380. services/process_definitions/models/gxp_validation_evidence.py +33 -0
  381. services/process_definitions/models/mbmr_templates.py +173 -0
  382. services/process_definitions/models/packing_instructions.py +176 -0
  383. services/process_definitions/models/process_constraints.py +159 -0
  384. services/process_definitions/models/process_corrections.py +118 -0
  385. services/process_definitions/models/process_definition.py +685 -0
  386. services/process_definitions/models/process_definition_common.py +48 -0
  387. services/process_definitions/models/process_node_catalog.py +25 -0
  388. services/process_definitions/models/process_post_checks.py +171 -0
  389. services/process_definitions/models/process_pre_checks.py +168 -0
  390. services/process_definitions/models/process_steps.py +170 -0
  391. services/process_definitions/node_services/__init__.py +8 -0
  392. services/process_definitions/node_services/common.py +95 -0
  393. services/process_definitions/node_services/executor.py +499 -0
  394. services/process_definitions/node_services/flow_simulator.py +733 -0
  395. services/process_definitions/node_services/functions.py +193 -0
  396. services/process_definitions/node_services/messaging.py +44 -0
  397. services/process_definitions/node_services/models.py +221 -0
  398. services/process_definitions/node_services/network.py +161 -0
  399. services/process_definitions/node_services/parsers.py +87 -0
  400. services/process_definitions/node_services/sequence.py +95 -0
  401. services/process_definitions/node_services/storage.py +50 -0
  402. services/process_definitions/node_services/webhooks.py +52 -0
  403. services/process_definitions/routers/__init__.py +10 -0
  404. services/process_definitions/routers/cpp_cqa_registry.py +86 -0
  405. services/process_definitions/routers/mbmr_templates.py +84 -0
  406. services/process_definitions/routers/packing_instructions.py +84 -0
  407. services/process_definitions/routers/process_constraints.py +564 -0
  408. services/process_definitions/routers/process_corrections.py +343 -0
  409. services/process_definitions/routers/process_definition.py +992 -0
  410. services/process_definitions/routers/process_post_checks.py +529 -0
  411. services/process_definitions/routers/process_pre_checks.py +435 -0
  412. services/process_definitions/routers/process_steps.py +274 -0
  413. services/procurement/helpers/__init__.py +9 -0
  414. services/procurement/helpers/goods_receipts.py +240 -0
  415. services/procurement/helpers/purchase_order_shipping_information.py +85 -0
  416. services/procurement/helpers/purchase_orders.py +68 -0
  417. services/procurement/helpers/quality_control.py +235 -0
  418. services/procurement/helpers/sampling.py +404 -0
  419. services/procurement/main.py +52 -0
  420. services/procurement/models/__init__.py +9 -0
  421. services/procurement/models/goods_receipts.py +165 -0
  422. services/procurement/models/purchase_orders.py +54 -0
  423. services/procurement/models/quality_control.py +464 -0
  424. services/procurement/models/reinspection_records.py +28 -0
  425. services/procurement/models/sampling.py +262 -0
  426. services/procurement/models/shipping_information.py +51 -0
  427. services/procurement/routers/__init__.py +9 -0
  428. services/procurement/routers/goods_receipts.py +201 -0
  429. services/procurement/routers/purchase_orders.py +106 -0
  430. services/procurement/routers/quality_control.py +386 -0
  431. services/procurement/routers/sampling.py +296 -0
  432. services/procurement/routers/shipping_information.py +97 -0
  433. services/production/__init__.py +1 -0
  434. services/production/agents/__init__.py +5 -0
  435. services/production/agents/batch_planning_agent.py +815 -0
  436. services/production/models/__init__.py +25 -0
  437. services/production/models/batch.py +253 -0
  438. services/products/helpers/__init__.py +10 -0
  439. services/products/helpers/boms.py +100 -0
  440. services/products/helpers/drug_research.py +644 -0
  441. services/products/helpers/product_component.py +168 -0
  442. services/products/helpers/product_inventory.py +221 -0
  443. services/products/helpers/product_pricing.py +123 -0
  444. services/products/helpers/product_utils.py +32 -0
  445. services/products/helpers/products.py +81 -0
  446. services/products/main.py +59 -0
  447. services/products/models/__init__.py +9 -0
  448. services/products/models/drug_research.py +138 -0
  449. services/products/models/product_common.py +60 -0
  450. services/products/models/product_component.py +1028 -0
  451. services/products/models/product_inventory.py +118 -0
  452. services/products/models/product_pricing.py +73 -0
  453. services/products/models/products.py +151 -0
  454. services/products/routers/__init__.py +9 -0
  455. services/products/routers/boms.py +116 -0
  456. services/products/routers/drug_research.py +115 -0
  457. services/products/routers/product_components.py +123 -0
  458. services/products/routers/product_inventory.py +185 -0
  459. services/products/routers/product_pricing.py +136 -0
  460. services/products/routers/products.py +165 -0
  461. services/replenishment/__init__.py +1 -0
  462. services/replenishment/main.py +46 -0
  463. services/replenishment/routers/__init__.py +1 -0
  464. services/replenishment/routers/replenishment.py +20 -0
  465. services/shifts/helpers/__init__.py +7 -0
  466. services/shifts/helpers/shift_templates.py +124 -0
  467. services/shifts/helpers/shifts.py +79 -0
  468. services/shifts/helpers/timesheets.py +137 -0
  469. services/shifts/main.py +48 -0
  470. services/shifts/models/__init__.py +8 -0
  471. services/shifts/models/shift.py +62 -0
  472. services/shifts/models/shift_template.py +82 -0
  473. services/shifts/models/time_range.py +31 -0
  474. services/shifts/models/timesheet.py +196 -0
  475. services/shifts/routers/__init__.py +7 -0
  476. services/shifts/routers/shift_templates.py +97 -0
  477. services/shifts/routers/shifts.py +117 -0
  478. services/shifts/routers/timesheets.py +117 -0
  479. services/shipping/helpers/__init__.py +15 -0
  480. services/shipping/helpers/carrier.py +78 -0
  481. services/shipping/helpers/customs_declaration.py +104 -0
  482. services/shipping/helpers/delivery_note.py +99 -0
  483. services/shipping/helpers/package.py +95 -0
  484. services/shipping/helpers/pallet.py +85 -0
  485. services/shipping/helpers/route.py +93 -0
  486. services/shipping/helpers/shipping_information.py +82 -0
  487. services/shipping/helpers/shipping_provider_details.py +59 -0
  488. services/shipping/helpers/shipping_provider_metadata.py +59 -0
  489. services/shipping/helpers/vehicle.py +85 -0
  490. services/shipping/helpers/waybill.py +86 -0
  491. services/shipping/main.py +64 -0
  492. services/shipping/models/__init__.py +15 -0
  493. services/shipping/models/carrier.py +97 -0
  494. services/shipping/models/customs_declaration.py +138 -0
  495. services/shipping/models/delivery_note.py +163 -0
  496. services/shipping/models/package.py +152 -0
  497. services/shipping/models/pallet.py +137 -0
  498. services/shipping/models/route.py +120 -0
  499. services/shipping/models/shipping_information.py +55 -0
  500. services/shipping/models/shipping_provider_details.py +42 -0
  501. services/shipping/models/shipping_provider_metadata.py +54 -0
  502. services/shipping/models/vehicle.py +129 -0
  503. services/shipping/models/waybill.py +189 -0
  504. services/shipping/routers/__init__.py +15 -0
  505. services/shipping/routers/carrier.py +99 -0
  506. services/shipping/routers/customs_declaration.py +132 -0
  507. services/shipping/routers/delivery_note.py +150 -0
  508. services/shipping/routers/package.py +141 -0
  509. services/shipping/routers/pallet.py +108 -0
  510. services/shipping/routers/route.py +128 -0
  511. services/shipping/routers/shipping_information.py +97 -0
  512. services/shipping/routers/shipping_provider_details.py +80 -0
  513. services/shipping/routers/shipping_provider_metadata.py +80 -0
  514. services/shipping/routers/vehicle.py +117 -0
  515. services/shipping/routers/waybill.py +119 -0
  516. services/suppliers/helpers/__init__.py +13 -0
  517. services/suppliers/helpers/supplier_capabilities.py +58 -0
  518. services/suppliers/helpers/supplier_certifications.py +67 -0
  519. services/suppliers/helpers/supplier_details.py +58 -0
  520. services/suppliers/helpers/supplier_financials.py +58 -0
  521. services/suppliers/helpers/supplier_inventory.py +74 -0
  522. services/suppliers/helpers/supplier_locations.py +60 -0
  523. services/suppliers/helpers/supplier_pricing.py +69 -0
  524. services/suppliers/helpers/supplier_quality.py +69 -0
  525. services/suppliers/helpers/supplier_shipping.py +69 -0
  526. services/suppliers/main.py +60 -0
  527. services/suppliers/models/__init__.py +13 -0
  528. services/suppliers/models/supplier_capabilities.py +70 -0
  529. services/suppliers/models/supplier_certifications.py +64 -0
  530. services/suppliers/models/supplier_details.py +75 -0
  531. services/suppliers/models/supplier_financials.py +69 -0
  532. services/suppliers/models/supplier_inventory.py +76 -0
  533. services/suppliers/models/supplier_locations.py +70 -0
  534. services/suppliers/models/supplier_pricing.py +74 -0
  535. services/suppliers/models/supplier_quality.py +74 -0
  536. services/suppliers/models/supplier_shipping.py +76 -0
  537. services/suppliers/routers/__init__.py +13 -0
  538. services/suppliers/routers/supplier_capabilities.py +88 -0
  539. services/suppliers/routers/supplier_certifications.py +87 -0
  540. services/suppliers/routers/supplier_details.py +83 -0
  541. services/suppliers/routers/supplier_financials.py +83 -0
  542. services/suppliers/routers/supplier_inventory.py +105 -0
  543. services/suppliers/routers/supplier_locations.py +89 -0
  544. services/suppliers/routers/supplier_pricing.py +96 -0
  545. services/suppliers/routers/supplier_quality.py +96 -0
  546. services/suppliers/routers/supplier_shipping.py +96 -0
  547. services/supply_allocation/main.py +46 -0
  548. services/supply_allocation/routers/__init__.py +1 -0
  549. services/supply_allocation/routers/allocation.py +20 -0
  550. services/taxonomy/helpers/__init__.py +7 -0
  551. services/taxonomy/helpers/classes.py +48 -0
  552. services/taxonomy/helpers/family.py +53 -0
  553. services/taxonomy/helpers/subclass.py +58 -0
  554. services/taxonomy/main.py +48 -0
  555. services/taxonomy/models/__init__.py +7 -0
  556. services/taxonomy/models/classes.py +52 -0
  557. services/taxonomy/models/family.py +60 -0
  558. services/taxonomy/models/subclass.py +50 -0
  559. services/taxonomy/routers/__init__.py +7 -0
  560. services/taxonomy/routers/classes.py +78 -0
  561. services/taxonomy/routers/family.py +77 -0
  562. services/taxonomy/routers/subclass.py +82 -0
  563. services/warehouse_execution/__init__.py +1 -0
  564. services/warehouse_execution/main.py +46 -0
  565. services/warehouse_execution/routers/__init__.py +1 -0
  566. services/warehouse_execution/routers/execution.py +21 -0
  567. services/work_order_agent/__init__.py +17 -0
  568. services/work_order_agent/agent/__init__.py +17 -0
  569. services/work_order_agent/agent/work_order_agent.py +658 -0
  570. services/work_order_agent/tracking/__init__.py +101 -0
  571. services/work_order_agent/tracking/event_system.py +182 -0
  572. services/work_order_agent/tracking/state_machine.py +163 -0
  573. services/work_order_agent/tracking/state_machine_integrator.py +295 -0
  574. services/work_order_agent/tracking/test_phase2_implementation.py +302 -0
  575. services/work_order_agent/tracking/time_analysis.py +301 -0
  576. services/work_order_agent/tracking/tracked_work_order.py +255 -0
  577. services/work_order_agent/tracking/work_order_adapter.py +367 -0
  578. services/work_order_agent/tracking/work_order_batch_manager.py +406 -0
  579. services/work_order_agent/tracking/work_order_repository.py +431 -0
  580. services/workorders/helpers/__init__.py +5 -0
  581. services/workorders/helpers/area_room_usage_ledger.py +139 -0
  582. services/workorders/helpers/batch_execution_records.py +265 -0
  583. services/workorders/helpers/batch_release_workflows.py +158 -0
  584. services/workorders/helpers/batch_step_executions.py +145 -0
  585. services/workorders/helpers/equipment_usage_ledger.py +209 -0
  586. services/workorders/helpers/executed_bmr_records.py +170 -0
  587. services/workorders/helpers/executed_bpr_records.py +170 -0
  588. services/workorders/helpers/executed_instruction_evidence.py +155 -0
  589. services/workorders/helpers/ipc_result_records.py +134 -0
  590. services/workorders/helpers/production_batches.py +117 -0
  591. services/workorders/helpers/work_orders.py +367 -0
  592. services/workorders/helpers/yield_reconciliation_records.py +158 -0
  593. services/workorders/main.py +110 -0
  594. services/workorders/models/__init__.py +5 -0
  595. services/workorders/models/area_room_usage_ledger.py +154 -0
  596. services/workorders/models/batch_execution_records.py +575 -0
  597. services/workorders/models/batch_release_workflows.py +190 -0
  598. services/workorders/models/batch_step_executions.py +142 -0
  599. services/workorders/models/equipment_usage_ledger.py +144 -0
  600. services/workorders/models/executed_bmr_records.py +220 -0
  601. services/workorders/models/executed_bpr_records.py +220 -0
  602. services/workorders/models/executed_instruction_evidence.py +128 -0
  603. services/workorders/models/ipc_result_records.py +164 -0
  604. services/workorders/models/production_batches.py +181 -0
  605. services/workorders/models/work_orders.py +255 -0
  606. services/workorders/models/yield_reconciliation_records.py +175 -0
  607. services/workorders/routers/__init__.py +5 -0
  608. services/workorders/routers/area_room_usage_ledger.py +117 -0
  609. services/workorders/routers/batch_execution_records.py +103 -0
  610. services/workorders/routers/batch_release_workflows.py +86 -0
  611. services/workorders/routers/batch_step_executions.py +88 -0
  612. services/workorders/routers/equipment_usage_ledger.py +115 -0
  613. services/workorders/routers/executed_bmr_records.py +86 -0
  614. services/workorders/routers/executed_bpr_records.py +86 -0
  615. services/workorders/routers/executed_instruction_evidence.py +86 -0
  616. services/workorders/routers/ipc_result_records.py +86 -0
  617. services/workorders/routers/production_batches.py +86 -0
  618. services/workorders/routers/work_orders.py +257 -0
  619. services/workorders/routers/yield_reconciliation_records.py +86 -0
  620. src/broca/__init__.py +5 -0
  621. src/broca/agent.py +201 -0
  622. src/cerebellum/__init__.py +0 -0
  623. src/cerebellum/adapter.py +84 -0
  624. src/cerebellum/capabilities/__init__.py +0 -0
  625. src/cerebellum/capabilities/agent/__init__.py +0 -0
  626. src/cerebellum/capabilities/agent/agents.py +65 -0
  627. src/cerebellum/capabilities/ai/__init__.py +0 -0
  628. src/cerebellum/capabilities/ai/providers.py +106 -0
  629. src/cerebellum/capabilities/api/__init__.py +0 -0
  630. src/cerebellum/capabilities/api/graphql.py +35 -0
  631. src/cerebellum/capabilities/api/rest_api.py +45 -0
  632. src/cerebellum/capabilities/api/webhook.py +30 -0
  633. src/cerebellum/capabilities/browser/__init__.py +0 -0
  634. src/cerebellum/capabilities/browser/browsers.py +27 -0
  635. src/cerebellum/capabilities/cloud/__init__.py +0 -0
  636. src/cerebellum/capabilities/cloud/cloud.py +46 -0
  637. src/cerebellum/capabilities/communication/__init__.py +0 -0
  638. src/cerebellum/capabilities/communication/communication.py +62 -0
  639. src/cerebellum/capabilities/database/__init__.py +0 -0
  640. src/cerebellum/capabilities/database/elasticsearch.py +40 -0
  641. src/cerebellum/capabilities/database/influxdb.py +37 -0
  642. src/cerebellum/capabilities/database/mongodb.py +50 -0
  643. src/cerebellum/capabilities/database/neo4j.py +32 -0
  644. src/cerebellum/capabilities/database/redis.py +44 -0
  645. src/cerebellum/capabilities/enterprise/__init__.py +0 -0
  646. src/cerebellum/capabilities/enterprise/opensource.py +180 -0
  647. src/cerebellum/capabilities/enterprise/proprietary.py +313 -0
  648. src/cerebellum/capabilities/event_streaming/__init__.py +0 -0
  649. src/cerebellum/capabilities/event_streaming/streaming.py +38 -0
  650. src/cerebellum/capabilities/infrastructure/__init__.py +0 -0
  651. src/cerebellum/capabilities/infrastructure/infrastructure.py +30 -0
  652. src/cerebellum/capabilities/productivity/__init__.py +0 -0
  653. src/cerebellum/capabilities/productivity/productivity.py +158 -0
  654. src/cerebellum/capabilities/robotics/__init__.py +0 -0
  655. src/cerebellum/capabilities/robotics/robotics.py +124 -0
  656. src/cerebellum/capabilities/runtime/__init__.py +0 -0
  657. src/cerebellum/capabilities/runtime/runtimes.py +92 -0
  658. src/cerebellum/capabilities/search/__init__.py +0 -0
  659. src/cerebellum/capabilities/search/search.py +63 -0
  660. src/cerebellum/capabilities/source_control/__init__.py +0 -0
  661. src/cerebellum/capabilities/source_control/source_control.py +113 -0
  662. src/cerebellum/capabilities/storage/__init__.py +0 -0
  663. src/cerebellum/capabilities/storage/storage.py +94 -0
  664. src/cerebellum/capabilities/workflow/__init__.py +0 -0
  665. src/cerebellum/capabilities/workflow/workflows.py +49 -0
  666. src/cerebellum/capability.py +108 -0
  667. src/cerebellum/config.py +157 -0
  668. src/cerebellum/fallback.py +147 -0
  669. src/cerebellum/fallback_engine.py +121 -0
  670. src/cerebellum/key_manager.py +129 -0
  671. src/cerebellum/keystore.py +179 -0
  672. src/cerebellum/lifecycle.py +54 -0
  673. src/cerebellum/metadata.py +61 -0
  674. src/cerebellum/operator/base.py +25 -0
  675. src/cerebellum/peripheral.py +92 -0
  676. src/cerebellum/registry.py +98 -0
  677. src/cerebellum/resolve_entity_capability.py +259 -0
  678. src/cingulate/benchmark/__init__.py +23 -0
  679. src/cingulate/benchmark/reporter.py +102 -0
  680. src/cingulate/benchmark/runner.py +159 -0
  681. src/cingulate/benchmark/scenario_runner.py +150 -0
  682. src/cingulate/benchmark/validator.py +102 -0
  683. src/cingulate/governance/__init__.py +21 -0
  684. src/cingulate/governance/architecture_validator.py +194 -0
  685. src/cingulate/governance/compliance.py +104 -0
  686. src/cingulate/governance/governance.py +77 -0
  687. src/cingulate/governance/policy_registry.py +91 -0
  688. src/cortex/__init__.py +33 -0
  689. src/cortex/cost.py +71 -0
  690. src/cortex/counterfactual.py +162 -0
  691. src/cortex/digital_twin.py +90 -0
  692. src/cortex/experience.py +83 -0
  693. src/cortex/feedback.py +144 -0
  694. src/cortex/loss.py +116 -0
  695. src/cortex/prediction.py +142 -0
  696. src/cortex/replay.py +130 -0
  697. src/cortex/reward.py +113 -0
  698. src/cortex/simulator.py +102 -0
  699. src/cortex/world_model.py +180 -0
  700. src/cortex/world_model_simulation.py +1591 -0
  701. src/cortex/world_state.py +121 -0
  702. src/cortex/xavier.py +250 -0
  703. src/deepdive/__init__.py +29 -0
  704. src/deepdive/aggregation.py +113 -0
  705. src/deepdive/digital_twin_aggregator.py +128 -0
  706. src/deepdive/elasticsearch_adapter.py +110 -0
  707. src/deepdive/fleet_analytics.py +131 -0
  708. src/deepdive/knowledge_aggregator.py +130 -0
  709. src/homeostasis/__init__.py +19 -0
  710. src/homeostasis/control_plane.py +159 -0
  711. src/introspection/__init__.py +38 -0
  712. src/introspection/alerting.py +142 -0
  713. src/introspection/health.py +101 -0
  714. src/introspection/lemon.py +243 -0
  715. src/introspection/logging.py +147 -0
  716. src/introspection/metrics.py +106 -0
  717. src/introspection/tracing.py +162 -0
  718. src/monkey_brain/__init__.py +1 -0
  719. src/monkey_brain/api/main.py +148 -0
  720. src/monkey_brain/api/models.py +81 -0
  721. src/monkey_brain/api/routes/routes/keys.py +106 -0
  722. src/monkey_brain/api/routes/routes/run.py +169 -0
  723. src/monkey_brain/api/routes/routes/simulate.py +485 -0
  724. src/monkey_brain/dlm/__init__.py +44 -0
  725. src/monkey_brain/dlm/dlm.py +139 -0
  726. src/monkey_brain/dlm/gc.py +115 -0
  727. src/monkey_brain/dlm/lifecycle.py +149 -0
  728. src/monkey_brain/dlm/orphans.py +99 -0
  729. src/monkey_brain/dlm/storage.py +149 -0
  730. src/monkey_brain/dlm/ttl.py +140 -0
  731. src/monkey_brain/documents/__init__.py +0 -0
  732. src/monkey_brain/documents/document_ocr.py +6 -0
  733. src/monkey_brain/kernel/__init__.py +53 -0
  734. src/monkey_brain/kernel/capability_interface.py +144 -0
  735. src/monkey_brain/kernel/classifier/__init__.py +1 -0
  736. src/monkey_brain/kernel/classifier/embed_classifier.py +125 -0
  737. src/monkey_brain/kernel/classifier/intent_examples.py +106 -0
  738. src/monkey_brain/kernel/dag.py +23 -0
  739. src/monkey_brain/kernel/execution_state.py +257 -0
  740. src/monkey_brain/kernel/goal_planner.py +85 -0
  741. src/monkey_brain/kernel/goal_router.py +20 -0
  742. src/monkey_brain/kernel/goals/__init__.py +1 -0
  743. src/monkey_brain/kernel/goals/goal.py +130 -0
  744. src/monkey_brain/kernel/goals/goal_bootstrap.py +38 -0
  745. src/monkey_brain/kernel/goals/goal_classifier.py +132 -0
  746. src/monkey_brain/kernel/goals/goal_registry.py +75 -0
  747. src/monkey_brain/kernel/intents/__init__.py +1 -0
  748. src/monkey_brain/kernel/intents/event_adapter.py +246 -0
  749. src/monkey_brain/kernel/intents/helpers.py +13 -0
  750. src/monkey_brain/kernel/intents/intent_registry.py +705 -0
  751. src/monkey_brain/kernel/intents/intent_router.py +102 -0
  752. src/monkey_brain/kernel/intents/predicates/approval_create.py +9 -0
  753. src/monkey_brain/kernel/intents/predicates/approval_decision.py +9 -0
  754. src/monkey_brain/kernel/intents/predicates/approval_hold.py +9 -0
  755. src/monkey_brain/kernel/intents/predicates/approval_query.py +9 -0
  756. src/monkey_brain/kernel/intents/predicates/batch_close.py +9 -0
  757. src/monkey_brain/kernel/intents/predicates/batch_creation.py +9 -0
  758. src/monkey_brain/kernel/intents/predicates/batch_delete.py +9 -0
  759. src/monkey_brain/kernel/intents/predicates/batch_hold.py +9 -0
  760. src/monkey_brain/kernel/intents/predicates/batch_record.py +9 -0
  761. src/monkey_brain/kernel/intents/predicates/batch_update.py +9 -0
  762. src/monkey_brain/kernel/intents/predicates/change_control.py +49 -0
  763. src/monkey_brain/kernel/intents/predicates/compliance_audit.py +14 -0
  764. src/monkey_brain/kernel/intents/predicates/decision_intelligence.py +9 -0
  765. src/monkey_brain/kernel/intents/predicates/drug_research.py +9 -0
  766. src/monkey_brain/kernel/intents/predicates/fuzzy_match.py +19 -0
  767. src/monkey_brain/kernel/intents/predicates/production_kpi.py +9 -0
  768. src/monkey_brain/kernel/intents/predicates/sop_create.py +9 -0
  769. src/monkey_brain/kernel/intents/predicates/sop_query.py +9 -0
  770. src/monkey_brain/kernel/intents/predicates/sop_update.py +9 -0
  771. src/monkey_brain/kernel/intents/predicates/warehouse_shipping.py +9 -0
  772. src/monkey_brain/kernel/intents/predicates/work_order_create.py +9 -0
  773. src/monkey_brain/kernel/intents/predicates/work_order_delete.py +9 -0
  774. src/monkey_brain/kernel/intents/predicates/work_order_hold.py +9 -0
  775. src/monkey_brain/kernel/intents/predicates/work_order_query.py +9 -0
  776. src/monkey_brain/kernel/intents/predicates/work_order_status.py +9 -0
  777. src/monkey_brain/kernel/intents/predicates/work_order_update.py +9 -0
  778. src/monkey_brain/kernel/intents/predicates/worker.py +9 -0
  779. src/monkey_brain/kernel/intents/telemetry_adapter.py +274 -0
  780. src/monkey_brain/kernel/intents/utils.py +68 -0
  781. src/monkey_brain/kernel/learning.py +98 -0
  782. src/monkey_brain/kernel/llm_explorer.py +188 -0
  783. src/monkey_brain/kernel/loss.py +81 -0
  784. src/monkey_brain/kernel/nlp/__init__.py +1 -0
  785. src/monkey_brain/kernel/nlp/compat.py +23 -0
  786. src/monkey_brain/kernel/nlp/models.py +10 -0
  787. src/monkey_brain/kernel/nlp/question_analyzer.py +203 -0
  788. src/monkey_brain/kernel/nlp/spacy_parser.py +53 -0
  789. src/monkey_brain/kernel/observer.py +97 -0
  790. src/monkey_brain/kernel/parser/__init__.py +3 -0
  791. src/monkey_brain/kernel/parser/ast.py +28 -0
  792. src/monkey_brain/kernel/parser/extractors/__init__.py +11 -0
  793. src/monkey_brain/kernel/parser/extractors/entities.py +21 -0
  794. src/monkey_brain/kernel/parser/extractors/filters.py +16 -0
  795. src/monkey_brain/kernel/parser/extractors/projections.py +36 -0
  796. src/monkey_brain/kernel/parser/extractors/verbs.py +31 -0
  797. src/monkey_brain/kernel/parser/parser.py +57 -0
  798. src/monkey_brain/kernel/parser/rules.py +75 -0
  799. src/monkey_brain/kernel/pipeline.py +44 -0
  800. src/monkey_brain/kernel/planner.py +57 -0
  801. src/monkey_brain/kernel/rl/__init__.py +33 -0
  802. src/monkey_brain/kernel/rl/learner.py +98 -0
  803. src/monkey_brain/kernel/rl/policy.py +254 -0
  804. src/monkey_brain/kernel/rl/reward.py +117 -0
  805. src/monkey_brain/kernel/rl/transition.py +112 -0
  806. src/monkey_brain/persistence/__init__.py +47 -0
  807. src/monkey_brain/persistence/adapters.py +49 -0
  808. src/monkey_brain/persistence/events.py +105 -0
  809. src/monkey_brain/persistence/manager.py +124 -0
  810. src/monkey_brain/persistence/mongodb_adapter.py +91 -0
  811. src/monkey_brain/persistence/redis_adapter.py +93 -0
  812. src/monkey_brain/persistence/reducer.py +111 -0
  813. src/monkey_brain/runtime/__init__.py +49 -0
  814. src/monkey_brain/runtime/depedencies.py +8 -0
  815. src/monkey_brain/runtime/engine.py +183 -0
  816. src/monkey_brain/runtime/message_bus.py +82 -0
  817. src/monkey_brain/runtime/process.py +144 -0
  818. src/monkey_brain/runtime/resource_manager.py +100 -0
  819. src/monkey_brain/runtime/routers.py +8 -0
  820. src/monkey_brain/runtime/runtime.py +199 -0
  821. src/monkey_brain/runtime/scheduler.py +165 -0
  822. src/monkey_brain/runtime/supervisor.py +133 -0
  823. src/monkey_brain/runtime/worker_pool.py +111 -0
  824. src/plasticity/seed/__init__.py +30 -0
  825. src/plasticity/seed/benchmark_generator.py +105 -0
  826. src/plasticity/seed/event_generator.py +122 -0
  827. src/plasticity/seed/scenario_builder.py +134 -0
  828. src/plasticity/seed/seed_data.py +206 -0
  829. src/plasticity/seed/seeder.py +122 -0
  830. src/plasticity/testing/__init__.py +28 -0
  831. src/plasticity/testing/performance.py +131 -0
  832. src/plasticity/testing/profiler.py +255 -0
  833. src/plasticity/testing/reporter.py +84 -0
  834. src/plasticity/testing/runner.py +209 -0
  835. src/sync/__init__.py +12 -0
  836. src/sync/cloud_aggregator.py +63 -0
  837. src/sync/edge_node.py +51 -0
  838. src/sync/sync_manager.py +74 -0
@@ -0,0 +1,33 @@
1
+ from typing import Optional
2
+
3
+ from motor.motor_asyncio import AsyncIOMotorDatabase
4
+
5
+ from services.changeover.helpers.changeover_common import create, delete, get_all, get_by_id, update
6
+ from services.changeover.models.changeover_kpis import ChangeoverKPICreate, ChangeoverKPIUpdate
7
+
8
+ COLLECTION = "changeover_kpis"
9
+
10
+
11
+ async def get_all_kpis(db: AsyncIOMotorDatabase, page: int = 1, page_size: int = 20) -> tuple[list[dict], int]:
12
+ return await get_all(db, COLLECTION, page, page_size)
13
+
14
+
15
+ async def get_kpi_by_id(db: AsyncIOMotorDatabase, kpi_id: str) -> Optional[dict]:
16
+ return await get_by_id(db, COLLECTION, kpi_id)
17
+
18
+
19
+ async def get_kpis_by_workstation(db: AsyncIOMotorDatabase, workstation_id: str) -> list[dict]:
20
+ records, _ = await get_all(db, COLLECTION, query={"workstation_id": workstation_id}, page_size=1000)
21
+ return records
22
+
23
+
24
+ async def create_kpi(db: AsyncIOMotorDatabase, data: ChangeoverKPICreate) -> dict:
25
+ return await create(db, COLLECTION, data)
26
+
27
+
28
+ async def update_kpi(db: AsyncIOMotorDatabase, kpi_id: str, data: ChangeoverKPIUpdate) -> Optional[dict]:
29
+ return await update(db, COLLECTION, kpi_id, data)
30
+
31
+
32
+ async def delete_kpi(db: AsyncIOMotorDatabase, kpi_id: str) -> bool:
33
+ return await delete(db, COLLECTION, kpi_id)
@@ -0,0 +1,60 @@
1
+ from typing import Optional
2
+
3
+ from motor.motor_asyncio import AsyncIOMotorDatabase
4
+
5
+ from services.changeover.helpers.changeover_common import create, delete, get_all, get_by_id, update
6
+ from services.changeover.models.changeover_matrix import (
7
+ ChangeoverMatrixEntryCreate,
8
+ ChangeoverMatrixEntryResponse,
9
+ ChangeoverMatrixEntryUpdate,
10
+ )
11
+
12
+ COLLECTION = "changeover_matrix"
13
+
14
+
15
+ def _normalize_matrix_record(doc: Optional[dict]) -> Optional[dict]:
16
+ if not doc:
17
+ return None
18
+
19
+ record = dict(doc)
20
+ record.pop("_id", None)
21
+ entry_id = str(record.get("id") or record.get("entry_id") or "CHANGEOVER-MATRIX")
22
+ record["id"] = entry_id
23
+ record.setdefault("workstation_id", str(record.get("workstation") or "UNKNOWN-WORKSTATION"))
24
+ record["from_product_id"] = str(record.get("from_product_id") or record.get("from_product") or "UNKNOWN-FROM-PRODUCT")
25
+ record["to_product_id"] = str(record.get("to_product_id") or record.get("to_product") or record["from_product_id"])
26
+ record["standard_minutes"] = int(record.get("standard_minutes") or record.get("target_minutes") or record.get("duration_minutes") or 1)
27
+ record["requires_cleaning"] = bool(record.get("requires_cleaning") or False)
28
+ record["requires_tooling"] = bool(record.get("requires_tooling") or False)
29
+ record["min_operators"] = int(record.get("min_operators") or 1)
30
+ best = record.get("best_achieved_minutes")
31
+ if best is not None and int(best) > record["standard_minutes"]:
32
+ record["best_achieved_minutes"] = record["standard_minutes"]
33
+
34
+ return ChangeoverMatrixEntryResponse.model_validate(record).model_dump()
35
+
36
+
37
+ async def get_all_matrix(db: AsyncIOMotorDatabase, page: int = 1, page_size: int = 20) -> tuple[list[dict], int]:
38
+ records, total = await get_all(db, COLLECTION, page, page_size)
39
+ return [_normalize_matrix_record(record) for record in records], total
40
+
41
+
42
+ async def get_matrix_by_id(db: AsyncIOMotorDatabase, entry_id: str) -> Optional[dict]:
43
+ return _normalize_matrix_record(await get_by_id(db, COLLECTION, entry_id))
44
+
45
+
46
+ async def get_matrix_by_workstation(db: AsyncIOMotorDatabase, workstation_id: str) -> list[dict]:
47
+ records, _ = await get_all(db, COLLECTION, query={"workstation_id": workstation_id}, page_size=1000)
48
+ return [_normalize_matrix_record(record) for record in records]
49
+
50
+
51
+ async def create_matrix(db: AsyncIOMotorDatabase, data: ChangeoverMatrixEntryCreate) -> dict:
52
+ return _normalize_matrix_record(await create(db, COLLECTION, data))
53
+
54
+
55
+ async def update_matrix(db: AsyncIOMotorDatabase, entry_id: str, data: ChangeoverMatrixEntryUpdate) -> Optional[dict]:
56
+ return _normalize_matrix_record(await update(db, COLLECTION, entry_id, data))
57
+
58
+
59
+ async def delete_matrix(db: AsyncIOMotorDatabase, entry_id: str) -> bool:
60
+ return await delete(db, COLLECTION, entry_id)
@@ -0,0 +1,164 @@
1
+ from datetime import datetime, timezone
2
+ from typing import Optional
3
+
4
+ from motor.motor_asyncio import AsyncIOMotorDatabase
5
+ from pymongo import ReturnDocument
6
+
7
+ from services.changeover.helpers.changeover_common import create, delete, dump, get_all, get_by_id, serialize, update
8
+ from services.changeover.models.changeover_procedures import ChangeoverProcedureCreate, ChangeoverProcedureUpdate
9
+ from services.changeover.models.changeover_tasks import ChangeoverTaskUpdate
10
+ from services.common.models.enums import ChangeoverStatus, TaskStatus
11
+
12
+ COLLECTION = "changeover_procedures"
13
+
14
+
15
+ def _now() -> str:
16
+ return datetime.now(timezone.utc).isoformat()
17
+
18
+
19
+ def _task_is_complete(task: dict) -> bool:
20
+ return bool(task.get("is_complete")) or task.get("status") == TaskStatus.DONE.value
21
+
22
+
23
+ def _procedure_completion_fields(tasks: list[dict]) -> dict:
24
+ if tasks and all(_task_is_complete(task) for task in tasks):
25
+ return {
26
+ "status": ChangeoverStatus.COMPLETED.value,
27
+ "completed_at": _now(),
28
+ }
29
+ return {
30
+ "status": ChangeoverStatus.IN_PROGRESS.value,
31
+ "completed_at": None,
32
+ }
33
+
34
+
35
+ def _apply_task_completion(task: dict, is_complete: bool) -> None:
36
+ task["is_complete"] = is_complete
37
+ if is_complete:
38
+ now = _now()
39
+ task["status"] = TaskStatus.DONE.value
40
+ if not task.get("started_at"):
41
+ task["started_at"] = now
42
+ task["completed_at"] = task.get("completed_at") or now
43
+ task["blocked_reason"] = None
44
+ else:
45
+ task["status"] = TaskStatus.PENDING.value
46
+ task["completed_at"] = None
47
+
48
+
49
+ async def get_all_procedures(db: AsyncIOMotorDatabase, page: int = 1, page_size: int = 20) -> tuple[list[dict], int]:
50
+ return await get_all(db, COLLECTION, page, page_size)
51
+
52
+
53
+ async def get_procedure_by_id(db: AsyncIOMotorDatabase, procedure_id: str) -> Optional[dict]:
54
+ return await get_by_id(db, COLLECTION, procedure_id)
55
+
56
+
57
+ async def get_procedures_by_factory(db: AsyncIOMotorDatabase, factory_id: str) -> list[dict]:
58
+ records, _ = await get_all(
59
+ db,
60
+ COLLECTION,
61
+ query={"$or": [{"plant_id": factory_id}, {"factory_id": factory_id}]},
62
+ page_size=1000,
63
+ )
64
+ return records
65
+
66
+
67
+ async def get_procedures_by_plant(db: AsyncIOMotorDatabase, plant_id: str) -> list[dict]:
68
+ records, _ = await get_all(db, COLLECTION, query={"plant_id": plant_id}, page_size=1000)
69
+ return records
70
+
71
+
72
+ async def create_procedure(db: AsyncIOMotorDatabase, data: ChangeoverProcedureCreate) -> dict:
73
+ doc = await create(db, COLLECTION, data)
74
+ completion_fields = _procedure_completion_fields(doc.get("tasks", []))
75
+ if completion_fields["status"] == ChangeoverStatus.COMPLETED.value:
76
+ await db[COLLECTION].update_one({"id": doc["id"]}, {"$set": completion_fields})
77
+ doc.update(completion_fields)
78
+ return doc
79
+
80
+
81
+ async def update_procedure(db: AsyncIOMotorDatabase, procedure_id: str, data: ChangeoverProcedureUpdate) -> Optional[dict]:
82
+ updated = await update(db, COLLECTION, procedure_id, data)
83
+ if not updated or "tasks" not in data.model_dump(exclude_unset=True):
84
+ return updated
85
+
86
+ completion_fields = _procedure_completion_fields(updated.get("tasks", []))
87
+ result = await db[COLLECTION].find_one_and_update(
88
+ {"id": procedure_id},
89
+ {"$set": completion_fields},
90
+ return_document=ReturnDocument.AFTER,
91
+ )
92
+ return serialize(result) if result else None
93
+
94
+
95
+ async def update_procedure_task(
96
+ db: AsyncIOMotorDatabase,
97
+ procedure_id: str,
98
+ task_id: str,
99
+ data: ChangeoverTaskUpdate,
100
+ ) -> Optional[dict]:
101
+ procedure = await get_procedure_by_id(db, procedure_id)
102
+ if not procedure:
103
+ return None
104
+
105
+ tasks = procedure.get("tasks", [])
106
+ fields = dump(data)
107
+ matched = False
108
+ for task in tasks:
109
+ if str(task.get("id")) != task_id:
110
+ continue
111
+ matched = True
112
+ task.update(fields)
113
+ if fields.get("is_complete") is not None:
114
+ _apply_task_completion(task, fields["is_complete"])
115
+ elif fields.get("status") == TaskStatus.DONE.value:
116
+ _apply_task_completion(task, True)
117
+ elif fields.get("completed_at") is not None:
118
+ task["is_complete"] = True
119
+ break
120
+
121
+ if not matched:
122
+ return None
123
+
124
+ update_fields = {"tasks": tasks, **_procedure_completion_fields(tasks)}
125
+ result = await db[COLLECTION].find_one_and_update(
126
+ {"id": procedure_id},
127
+ {"$set": update_fields},
128
+ return_document=ReturnDocument.AFTER,
129
+ )
130
+ return serialize(result) if result else None
131
+
132
+
133
+ async def set_procedure_task_complete(
134
+ db: AsyncIOMotorDatabase,
135
+ procedure_id: str,
136
+ task_id: str,
137
+ is_complete: bool,
138
+ ) -> Optional[dict]:
139
+ procedure = await get_procedure_by_id(db, procedure_id)
140
+ if not procedure:
141
+ return None
142
+
143
+ tasks = procedure.get("tasks", [])
144
+ matched = False
145
+ for task in tasks:
146
+ if str(task.get("id")) == task_id:
147
+ matched = True
148
+ _apply_task_completion(task, is_complete)
149
+ break
150
+
151
+ if not matched:
152
+ return None
153
+
154
+ update_fields = {"tasks": tasks, **_procedure_completion_fields(tasks)}
155
+ result = await db[COLLECTION].find_one_and_update(
156
+ {"id": procedure_id},
157
+ {"$set": update_fields},
158
+ return_document=ReturnDocument.AFTER,
159
+ )
160
+ return serialize(result) if result else None
161
+
162
+
163
+ async def delete_procedure(db: AsyncIOMotorDatabase, procedure_id: str) -> bool:
164
+ return await delete(db, COLLECTION, procedure_id)
@@ -0,0 +1,96 @@
1
+ from datetime import datetime, timedelta
2
+ from typing import Optional
3
+
4
+ from motor.motor_asyncio import AsyncIOMotorDatabase
5
+ from pymongo import ReturnDocument
6
+
7
+ from services.pm.helpers import calendar_bookings
8
+ from services.changeover.helpers.changeover_common import create, delete, get_all, get_by_id, update
9
+ from services.pm.models.calendar_booking import CalendarBookingCreate
10
+ from services.changeover.models.changeover_windows import (
11
+ ChangeoverWindowCalendarBookingCreate,
12
+ ChangeoverWindowCreate,
13
+ ChangeoverWindowUpdate,
14
+ )
15
+
16
+ COLLECTION = "changeover_windows"
17
+
18
+
19
+ def _to_datetime(value) -> datetime:
20
+ if isinstance(value, datetime):
21
+ return value
22
+ return datetime.fromisoformat(value.replace("Z", "+00:00"))
23
+
24
+
25
+ def _calendar_title(window: dict) -> str:
26
+ return f"Changeover window - workstation {window['workstation_id']}"
27
+
28
+
29
+ async def get_all_windows(db: AsyncIOMotorDatabase, page: int = 1, page_size: int = 20) -> tuple[list[dict], int]:
30
+ return await get_all(db, COLLECTION, page, page_size)
31
+
32
+
33
+ async def get_window_by_id(db: AsyncIOMotorDatabase, window_id: str) -> Optional[dict]:
34
+ return await get_by_id(db, COLLECTION, window_id)
35
+
36
+
37
+ async def get_windows_by_workstation(db: AsyncIOMotorDatabase, workstation_id: str) -> list[dict]:
38
+ records, _ = await get_all(db, COLLECTION, query={"workstation_id": workstation_id}, page_size=1000)
39
+ return records
40
+
41
+
42
+ async def create_window(db: AsyncIOMotorDatabase, data: ChangeoverWindowCreate) -> dict:
43
+ return await create(db, COLLECTION, data)
44
+
45
+
46
+ async def update_window(db: AsyncIOMotorDatabase, window_id: str, data: ChangeoverWindowUpdate) -> Optional[dict]:
47
+ return await update(db, COLLECTION, window_id, data)
48
+
49
+
50
+ async def add_window_to_calendar(
51
+ db: AsyncIOMotorDatabase,
52
+ window_id: str,
53
+ data: ChangeoverWindowCalendarBookingCreate,
54
+ ) -> Optional[dict]:
55
+ window = await get_window_by_id(db, window_id)
56
+ if not window:
57
+ return None
58
+
59
+ existing_booking_id = window.get("calendar_booking_id")
60
+ if existing_booking_id:
61
+ existing_booking = await calendar_bookings.get_by_id(db, str(existing_booking_id))
62
+ if existing_booking:
63
+ return existing_booking
64
+
65
+ start_at = _to_datetime(window["start_dt"])
66
+ end_at = _to_datetime(window["end_dt"])
67
+ if data.include_buffer:
68
+ end_at = end_at + timedelta(minutes=window.get("buffer_minutes", 0))
69
+
70
+ booking = CalendarBookingCreate(
71
+ calendar_id=data.calendar_id or str(window["workstation_id"]),
72
+ title=data.title or _calendar_title(window),
73
+ start_at=start_at,
74
+ end_at=end_at,
75
+ booked_by=data.booked_by,
76
+ attendee_ids=data.attendee_ids,
77
+ description=data.description
78
+ or f"Changeover window {window_id} for workstation {window['workstation_id']}.",
79
+ )
80
+
81
+ if await calendar_bookings.has_conflict(db, booking.calendar_id, booking.start_at, booking.end_at):
82
+ return {"conflict": True}
83
+
84
+ created = await calendar_bookings.create(db, booking)
85
+ booking_id = created.get("id") or str(booking.id)
86
+ await db[COLLECTION].find_one_and_update(
87
+ {"id": window_id},
88
+ {"$set": {"calendar_booking_id": booking_id}},
89
+ return_document=ReturnDocument.AFTER,
90
+ )
91
+ created["id"] = booking_id
92
+ return created
93
+
94
+
95
+ async def delete_window(db: AsyncIOMotorDatabase, window_id: str) -> bool:
96
+ return await delete(db, COLLECTION, window_id)
@@ -0,0 +1,52 @@
1
+ from contextlib import asynccontextmanager
2
+
3
+ from fastapi import FastAPI
4
+ from fastapi.middleware.cors import CORSMiddleware
5
+
6
+ from services.common.logging import configure_service_logging, install_request_logging
7
+ from services.common.tracing import install_route_tracing
8
+
9
+ from services.common.db import close_db, connect_db
10
+ from services.changeover.routers.changeover_matrix import router as changeover_matrix_router
11
+ from services.changeover.routers.changeover_procedures import router as changeover_procedures_router
12
+ from services.changeover.routers.changeover_windows import router as changeover_windows_router
13
+ from services.changeover.routers.changeover_kpis import router as changeover_kpis_router
14
+ from services.changeover.routers.changeover_events import router as changeover_events_router
15
+
16
+
17
+ logger = configure_service_logging("changeover")
18
+
19
+ @asynccontextmanager
20
+ async def lifespan(app: FastAPI):
21
+ await connect_db()
22
+ yield
23
+ await close_db()
24
+
25
+
26
+ app = FastAPI(
27
+ title="Changeover Service",
28
+ description="Microservice for changeover service.",
29
+ version="1.0.0",
30
+ lifespan=lifespan,
31
+ )
32
+ install_request_logging(app, "changeover")
33
+ install_route_tracing(app, "changeover")
34
+
35
+ app.add_middleware(
36
+ CORSMiddleware,
37
+ allow_origins=["*"],
38
+ allow_credentials=True,
39
+ allow_methods=["*"],
40
+ allow_headers=["*"],
41
+ )
42
+
43
+ app.include_router(changeover_matrix_router, prefix="/api/v1/changeovers/matrix", tags=["Changeover Matrix"])
44
+ app.include_router(changeover_procedures_router, prefix="/api/v1/changeovers/procedures", tags=["Changeover Procedures"])
45
+ app.include_router(changeover_windows_router, prefix="/api/v1/changeovers", tags=["Changeover Windows"])
46
+ app.include_router(changeover_kpis_router, prefix="/api/v1/changeovers", tags=["Changeover KPIs"])
47
+ app.include_router(changeover_events_router, prefix="/api/v1/changeovers", tags=["Changeover Events"])
48
+
49
+
50
+ @app.get("/health", tags=["Health"])
51
+ async def health_check():
52
+ return {"status": "healthy"}
@@ -0,0 +1,11 @@
1
+ """changeover service models package."""
2
+
3
+ __all__ = [
4
+ "changeover",
5
+ "changeover_events",
6
+ "changeover_kpis",
7
+ "changeover_matrix",
8
+ "changeover_procedures",
9
+ "changeover_tasks",
10
+ "changeover_windows",
11
+ ]
@@ -0,0 +1,73 @@
1
+ from services.changeover.models.changeover_events import (
2
+ ChangeoverEvent,
3
+ ChangeoverEventCreate,
4
+ ChangeoverEventResponse,
5
+ ChangeoverEventUpdate,
6
+ PaginatedChangeoverEventResponse,
7
+ )
8
+ from services.changeover.models.changeover_kpis import (
9
+ ChangeoverKPI,
10
+ ChangeoverKPICreate,
11
+ ChangeoverKPIResponse,
12
+ ChangeoverKPIUpdate,
13
+ PaginatedChangeoverKPIResponse,
14
+ )
15
+ from services.changeover.models.changeover_matrix import (
16
+ ChangeoverMatrixEntry,
17
+ ChangeoverMatrixEntryCreate,
18
+ ChangeoverMatrixEntryResponse,
19
+ ChangeoverMatrixEntryUpdate,
20
+ PaginatedChangeoverMatrixEntryResponse,
21
+ )
22
+ from services.changeover.models.changeover_procedures import (
23
+ ChangeoverProcedure,
24
+ ChangeoverProcedureCreate,
25
+ ChangeoverProcedureResponse,
26
+ ChangeoverProcedureUpdate,
27
+ PaginatedChangeoverProcedureResponse,
28
+ )
29
+ from services.changeover.models.changeover_tasks import (
30
+ ChangeoverTask,
31
+ ChangeoverTaskCreate,
32
+ ChangeoverTaskUpdate,
33
+ )
34
+ from services.changeover.models.changeover_windows import (
35
+ ChangeoverWindow,
36
+ ChangeoverWindowCalendarBookingCreate,
37
+ ChangeoverWindowCreate,
38
+ ChangeoverWindowResponse,
39
+ ChangeoverWindowUpdate,
40
+ PaginatedChangeoverWindowResponse,
41
+ )
42
+
43
+ __all__ = [
44
+ "ChangeoverEvent",
45
+ "ChangeoverEventCreate",
46
+ "ChangeoverEventResponse",
47
+ "ChangeoverEventUpdate",
48
+ "ChangeoverKPI",
49
+ "ChangeoverKPICreate",
50
+ "ChangeoverKPIResponse",
51
+ "ChangeoverKPIUpdate",
52
+ "ChangeoverMatrixEntry",
53
+ "ChangeoverMatrixEntryCreate",
54
+ "ChangeoverMatrixEntryResponse",
55
+ "ChangeoverMatrixEntryUpdate",
56
+ "ChangeoverProcedure",
57
+ "ChangeoverProcedureCreate",
58
+ "ChangeoverProcedureResponse",
59
+ "ChangeoverProcedureUpdate",
60
+ "ChangeoverTask",
61
+ "ChangeoverTaskCreate",
62
+ "ChangeoverTaskUpdate",
63
+ "ChangeoverWindow",
64
+ "ChangeoverWindowCalendarBookingCreate",
65
+ "ChangeoverWindowCreate",
66
+ "ChangeoverWindowResponse",
67
+ "ChangeoverWindowUpdate",
68
+ "PaginatedChangeoverEventResponse",
69
+ "PaginatedChangeoverKPIResponse",
70
+ "PaginatedChangeoverMatrixEntryResponse",
71
+ "PaginatedChangeoverProcedureResponse",
72
+ "PaginatedChangeoverWindowResponse",
73
+ ]
@@ -0,0 +1,142 @@
1
+ from datetime import datetime
2
+ from typing import Optional
3
+ from uuid import uuid4
4
+
5
+ from pydantic import BaseModel, ConfigDict, Field, computed_field, field_validator, model_validator
6
+
7
+ from services.changeover.models.changeover_tasks import ChangeoverTask
8
+ from services.common.models.enums import ChangeoverStatus, ChangeoverTrigger, ChangeoverType, TaskStatus
9
+
10
+
11
+ class ChangeoverEvent(BaseModel):
12
+ """Concrete live or historical workstation changeover."""
13
+
14
+ model_config = ConfigDict(str_strip_whitespace=True)
15
+
16
+ id: str = Field(default_factory=lambda: str(uuid4()))
17
+ workstation_id: str
18
+ factory_id: str
19
+ procedure_id: Optional[str] = Field(None, description="Source ChangeoverProcedure template")
20
+ shift_schedule_id: Optional[str] = Field(None, description="Shift during which the changeover occurs")
21
+ changeover_type: ChangeoverType
22
+ trigger: ChangeoverTrigger = ChangeoverTrigger.SCHEDULED
23
+ status: ChangeoverStatus = ChangeoverStatus.PLANNED
24
+ from_product_id: Optional[str] = None
25
+ to_product_id: Optional[str] = None
26
+ planned_start: datetime
27
+ planned_end: datetime
28
+ actual_start: Optional[datetime] = None
29
+ actual_end: Optional[datetime] = None
30
+ lead_operator_id: Optional[str] = None
31
+ team_member_ids: list[str] = Field(default_factory=list)
32
+ tasks: list[ChangeoverTask] = Field(default_factory=list)
33
+ downtime_minutes: Optional[float] = Field(None, ge=0, description="Unplanned stoppage time added during changeover")
34
+ quality_check_passed: Optional[bool] = Field(None, description="First-article / first-off quality result after changeover")
35
+ notes: Optional[str] = Field(None, max_length=800)
36
+
37
+ @field_validator("changeover_type", "trigger", "status", mode="before")
38
+ @classmethod
39
+ def normalize_enum_value(cls, value):
40
+ return value.lower() if isinstance(value, str) else value
41
+
42
+ @model_validator(mode="after")
43
+ def planned_end_after_start(self):
44
+ if self.planned_end <= self.planned_start:
45
+ raise ValueError("planned_end must be after planned_start")
46
+ return self
47
+
48
+ @model_validator(mode="after")
49
+ def actual_end_after_actual_start(self):
50
+ if self.actual_start and self.actual_end and self.actual_end <= self.actual_start:
51
+ raise ValueError("actual_end must be after actual_start")
52
+ return self
53
+
54
+ @model_validator(mode="after")
55
+ def completed_needs_actual_times(self):
56
+ if self.status == ChangeoverStatus.COMPLETED and (not self.actual_start or not self.actual_end):
57
+ raise ValueError("status=completed requires both actual_start and actual_end")
58
+ return self
59
+
60
+ @computed_field # type: ignore[misc]
61
+ @property
62
+ def planned_duration_minutes(self) -> float:
63
+ return (self.planned_end - self.planned_start).total_seconds() / 60
64
+
65
+ @computed_field # type: ignore[misc]
66
+ @property
67
+ def actual_duration_minutes(self) -> Optional[float]:
68
+ if self.actual_start and self.actual_end:
69
+ return (self.actual_end - self.actual_start).total_seconds() / 60
70
+ return None
71
+
72
+ @computed_field # type: ignore[misc]
73
+ @property
74
+ def variance_minutes(self) -> Optional[float]:
75
+ if self.actual_duration_minutes is not None:
76
+ return self.actual_duration_minutes - self.planned_duration_minutes
77
+ return None
78
+
79
+ @computed_field # type: ignore[misc]
80
+ @property
81
+ def completion_pct(self) -> float:
82
+ if not self.tasks:
83
+ return 0.0
84
+ done = sum(1 for t in self.tasks if t.status in {TaskStatus.DONE, TaskStatus.SKIPPED})
85
+ return round(done / len(self.tasks) * 100, 1)
86
+
87
+ @computed_field # type: ignore[misc]
88
+ @property
89
+ def is_running_late(self) -> bool:
90
+ if self.status != ChangeoverStatus.IN_PROGRESS or not self.actual_start:
91
+ return False
92
+ elapsed = (datetime.utcnow() - self.actual_start).total_seconds() / 60
93
+ return elapsed > self.planned_duration_minutes
94
+
95
+ def pending_tasks(self) -> list[ChangeoverTask]:
96
+ return [t for t in self.tasks if t.status == TaskStatus.PENDING]
97
+
98
+ def blocked_tasks(self) -> list[ChangeoverTask]:
99
+ return [t for t in self.tasks if t.status == TaskStatus.BLOCKED]
100
+
101
+
102
+ class ChangeoverEventCreate(ChangeoverEvent):
103
+ pass
104
+
105
+
106
+ class ChangeoverEventUpdate(BaseModel):
107
+ workstation_id: Optional[str] = None
108
+ factory_id: Optional[str] = None
109
+ procedure_id: Optional[str] = None
110
+ shift_schedule_id: Optional[str] = None
111
+ changeover_type: Optional[ChangeoverType] = None
112
+ trigger: Optional[ChangeoverTrigger] = None
113
+ status: Optional[ChangeoverStatus] = None
114
+ from_product_id: Optional[str] = None
115
+ to_product_id: Optional[str] = None
116
+ planned_start: Optional[datetime] = None
117
+ planned_end: Optional[datetime] = None
118
+ actual_start: Optional[datetime] = None
119
+ actual_end: Optional[datetime] = None
120
+ lead_operator_id: Optional[str] = None
121
+ team_member_ids: Optional[list[str]] = None
122
+ tasks: Optional[list[ChangeoverTask]] = None
123
+ downtime_minutes: Optional[float] = Field(None, ge=0)
124
+ quality_check_passed: Optional[bool] = None
125
+ notes: Optional[str] = Field(None, max_length=800)
126
+
127
+ @field_validator("changeover_type", "trigger", "status", mode="before")
128
+ @classmethod
129
+ def normalize_enum_value(cls, value):
130
+ return value.lower() if isinstance(value, str) else value
131
+
132
+
133
+ class ChangeoverEventResponse(ChangeoverEvent):
134
+ class Config:
135
+ from_attributes = True
136
+
137
+
138
+ class PaginatedChangeoverEventResponse(BaseModel):
139
+ total: int
140
+ page: int
141
+ page_size: int
142
+ results: list[ChangeoverEventResponse]