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,71 @@
1
+ from datetime import datetime, timedelta, timezone
2
+ from typing import Any
3
+
4
+ from jose import JWTError, jwt
5
+
6
+ from services.common.config import settings
7
+
8
+
9
+ def _create_token(data: dict, secret: str, expires_delta: timedelta) -> str:
10
+ payload = data.copy()
11
+ payload["exp"] = datetime.now(timezone.utc) + expires_delta
12
+ return jwt.encode(payload, secret, algorithm=settings.ALGORITHM)
13
+
14
+
15
+ def _permission_claim(permission: Any) -> str | None:
16
+ if hasattr(permission, "model_dump"):
17
+ permission = permission.model_dump(mode="python")
18
+ if isinstance(permission, str):
19
+ return permission
20
+ if not isinstance(permission, dict):
21
+ return None
22
+ permission_id = permission.get("permission_id")
23
+ return str(permission_id) if permission_id else None
24
+
25
+
26
+ def create_access_token(user_id: str, email: str, role: str, permissions: list | None = None) -> str:
27
+ serialized = sorted({
28
+ claim
29
+ for permission in (permissions or [])
30
+ if (claim := _permission_claim(permission))
31
+ })
32
+ return _create_token(
33
+ {"sub": user_id, "email": email, "role": role, "permissions": serialized},
34
+ settings.ACCESS_TOKEN_SECRET,
35
+ timedelta(minutes=settings.ACCESS_TOKEN_EXPIRE_MINUTES),
36
+ )
37
+
38
+ def create_refresh_token(user_id: str) -> str:
39
+ return _create_token(
40
+ {"sub": user_id},
41
+ settings.REFRESH_TOKEN_SECRET,
42
+ timedelta(days=settings.REFRESH_TOKEN_EXPIRE_DAYS),
43
+ )
44
+
45
+
46
+ def create_mfa_challenge_token(user_id: str) -> str:
47
+ return _create_token(
48
+ {"sub": user_id, "purpose": "mfa_challenge"},
49
+ settings.ACCESS_TOKEN_SECRET,
50
+ timedelta(minutes=5),
51
+ )
52
+
53
+
54
+ def decode_access_token(token: str) -> dict:
55
+ """Raises JWTError on invalid/expired token."""
56
+ payload = jwt.decode(token, settings.ACCESS_TOKEN_SECRET, algorithms=[settings.ALGORITHM])
57
+ if "permissions" not in payload and isinstance(payload.get("perms"), str):
58
+ payload["permissions"] = [permission for permission in payload["perms"].split(",") if permission]
59
+ return payload
60
+
61
+
62
+ def decode_refresh_token(token: str) -> dict:
63
+ """Raises JWTError on invalid/expired token."""
64
+ return jwt.decode(token, settings.REFRESH_TOKEN_SECRET, algorithms=[settings.ALGORITHM])
65
+
66
+
67
+ def decode_mfa_challenge_token(token: str) -> dict:
68
+ payload = jwt.decode(token, settings.ACCESS_TOKEN_SECRET, algorithms=[settings.ALGORITHM])
69
+ if payload.get("purpose") != "mfa_challenge":
70
+ raise JWTError("Invalid MFA challenge token")
71
+ return payload
@@ -0,0 +1,119 @@
1
+ from typing import Optional
2
+ import bcrypt
3
+ import re
4
+ from motor.motor_asyncio import AsyncIOMotorDatabase
5
+ from services.auth.models.users import UserEntryCreate, UserEntryResponse, UserEntryUpdate
6
+
7
+ COLLECTION = "users"
8
+
9
+ def _serialize(doc: dict) -> dict:
10
+ doc = dict(doc)
11
+ doc.pop("_id", None)
12
+ return doc
13
+
14
+
15
+ # ── Read ──────────────────────────────────────────────────────────────────────
16
+
17
+ async def get_all(
18
+ db: AsyncIOMotorDatabase,
19
+ page: int = 1,
20
+ page_size: int = 20,
21
+ ) -> tuple[list[dict], int]:
22
+ query: dict = {}
23
+ total = await db[COLLECTION].count_documents(query)
24
+ cursor = db[COLLECTION].find(query).skip((page - 1) * page_size).limit(page_size)
25
+ results = [_serialize(d) async for d in cursor]
26
+ return results, total
27
+
28
+
29
+ async def get_by_id(db: AsyncIOMotorDatabase, user_id: str) -> Optional[dict]:
30
+ doc = await db[COLLECTION].find_one({"user_id": user_id})
31
+ return _serialize(doc) if doc else None
32
+
33
+
34
+ async def get_by_employee_id(db: AsyncIOMotorDatabase, employee_id: str) -> Optional[dict]:
35
+ doc = await db[COLLECTION].find_one({"employee_id": employee_id})
36
+ return _serialize(doc) if doc else None
37
+
38
+
39
+ async def get_by_department(db: AsyncIOMotorDatabase, department: str) -> list[dict]:
40
+ cursor = db[COLLECTION].find({"department": department})
41
+ return [_serialize(d) async for d in cursor]
42
+
43
+
44
+ async def get_by_team(db: AsyncIOMotorDatabase, team: str) -> list[dict]:
45
+ cursor = db[COLLECTION].find({"team": team})
46
+ return [_serialize(d) async for d in cursor]
47
+
48
+ async def get_by_email(db: AsyncIOMotorDatabase, email: str) -> list[dict]:
49
+ normalized_email = email.strip().lower()
50
+ cursor = db[COLLECTION].find({"email": normalized_email})
51
+ return [_serialize(d) async for d in cursor]
52
+
53
+ async def get_by_username(db: AsyncIOMotorDatabase, username: str):
54
+ cursor = db[COLLECTION].find({"name": username})
55
+ return [_serialize(d) async for d in cursor]
56
+
57
+ # ── Create ────────────────────────────────────────────────────────────────────
58
+
59
+ async def create(db: AsyncIOMotorDatabase, data: UserEntryCreate) -> dict:
60
+ doc = data.model_dump()
61
+ password = data.password.get_secret_value()
62
+ validate_password_policy(password)
63
+ doc["password"] = _hash(password)
64
+ await db[COLLECTION].insert_one(doc)
65
+ return _serialize(doc)
66
+
67
+ # ── Update ────────────────────────────────────────────────────────────────────
68
+
69
+ async def update(
70
+ db: AsyncIOMotorDatabase,
71
+ user_id: str,
72
+ data: UserEntryUpdate,
73
+ ) -> Optional[dict]:
74
+ fields = data.model_dump(exclude_unset=True)
75
+ if not fields:
76
+ return await get_by_id(db, user_id)
77
+ password = fields.get("password")
78
+ if password is None:
79
+ fields.pop("password", None)
80
+ else:
81
+ password_value = password.get_secret_value() if hasattr(password, "get_secret_value") else str(password)
82
+ validate_password_policy(password_value)
83
+ fields["password"] = _hash(password_value)
84
+ if not fields:
85
+ return await get_by_id(db, user_id)
86
+ result = await db[COLLECTION].find_one_and_update(
87
+ {"user_id": user_id},
88
+ {"$set": fields},
89
+ return_document=True,
90
+ )
91
+ return _serialize(result) if result else None
92
+
93
+
94
+ # ── Delete ────────────────────────────────────────────────────────────────────
95
+
96
+ async def delete(db: AsyncIOMotorDatabase, user_id: str) -> bool:
97
+ result = await db[COLLECTION].delete_one({"user_id": user_id})
98
+ return result.deleted_count == 1
99
+
100
+
101
+ def _hash(password: str) -> str:
102
+ return bcrypt.hashpw(password.encode(), bcrypt.gensalt()).decode()
103
+
104
+
105
+ def verify_password(plain: str, hashed: str) -> bool:
106
+ return bcrypt.checkpw(plain.encode(), hashed.encode())
107
+
108
+
109
+ def validate_password_policy(password: str) -> None:
110
+ checks = [
111
+ (len(password) >= 12, "at least 12 characters"),
112
+ (re.search(r"[A-Z]", password), "an uppercase letter"),
113
+ (re.search(r"[a-z]", password), "a lowercase letter"),
114
+ (re.search(r"\d", password), "a number"),
115
+ (re.search(r"[^A-Za-z0-9]", password), "a special character"),
116
+ ]
117
+ missing = [message for ok, message in checks if not ok]
118
+ if missing:
119
+ raise ValueError("Password must contain " + ", ".join(missing))
@@ -0,0 +1,41 @@
1
+ import asyncio
2
+ import logging
3
+
4
+ from fastapi import WebSocket
5
+ from starlette.websockets import WebSocketState
6
+
7
+
8
+ log = logging.getLogger(__name__)
9
+ _connections: set[WebSocket] = set()
10
+ _lock = asyncio.Lock()
11
+
12
+
13
+ async def add_connection(websocket: WebSocket) -> None:
14
+ async with _lock:
15
+ _connections.add(websocket)
16
+
17
+
18
+ async def remove_connection(websocket: WebSocket) -> None:
19
+ async with _lock:
20
+ _connections.discard(websocket)
21
+
22
+
23
+ async def broadcast_event(event: dict) -> None:
24
+ async with _lock:
25
+ connections = list(_connections)
26
+
27
+ stale_connections: list[WebSocket] = []
28
+ for websocket in connections:
29
+ if websocket.application_state != WebSocketState.CONNECTED:
30
+ stale_connections.append(websocket)
31
+ continue
32
+ try:
33
+ await websocket.send_json(event)
34
+ except Exception:
35
+ stale_connections.append(websocket)
36
+ log.exception("Failed to send NATS event to websocket client")
37
+
38
+ if stale_connections:
39
+ async with _lock:
40
+ for websocket in stale_connections:
41
+ _connections.discard(websocket)
services/auth/main.py ADDED
@@ -0,0 +1,88 @@
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.mongo_cdc_watcher import cdc_watcher_status, start_mongo_cdc_watcher, stop_mongo_cdc_watcher
8
+ from services.common.tracing import install_route_tracing
9
+
10
+ from services.common.db import close_db, connect_db, get_database
11
+ from services.auth.helpers.audit_elasticsearch_sync import start_audit_elasticsearch_sync, stop_audit_elasticsearch_sync
12
+ from services.auth.helpers.graph_store import close_graph_driver
13
+ from services.auth.helpers.influx_store import ensure_event_measurements
14
+ from services.auth.helpers.nats_consumer import consumer_status, start_influx_event_consumer, stop_influx_event_consumer
15
+ from services.auth.helpers.nats_store import close_nats_client
16
+ from services.auth.routers.auth import router as auth_router
17
+ from services.auth.routers.me import router as me_router
18
+ from services.auth.routers.users import router as users_router
19
+ from services.auth.routers.roles import router as roles_router
20
+ from services.auth.routers.permissions import router as permissions_router
21
+ from services.auth.routers.departments import router as departments_router
22
+ from services.auth.routers.teams import router as teams_router
23
+ from services.auth.routers.team_members import router as members_router
24
+ from services.auth.routers.session import router as session_router
25
+ from services.auth.routers.websocket_events import router as websocket_events_router
26
+ from services.auth.routers.integration_config import router as integration_config_router
27
+
28
+
29
+ logger = configure_service_logging("auth")
30
+
31
+ @asynccontextmanager
32
+ async def lifespan(app: FastAPI):
33
+ await connect_db()
34
+ await ensure_event_measurements()
35
+ await start_audit_elasticsearch_sync(get_database())
36
+ await start_influx_event_consumer()
37
+ await start_mongo_cdc_watcher(get_database().raw_database)
38
+ yield
39
+ await stop_mongo_cdc_watcher()
40
+ await stop_audit_elasticsearch_sync()
41
+ await stop_influx_event_consumer()
42
+ await close_nats_client()
43
+ await close_graph_driver()
44
+ await close_db()
45
+
46
+
47
+ app = FastAPI(
48
+ title="Auth and Organization Service",
49
+ description="Microservice for auth and organization service.",
50
+ version="1.0.0",
51
+ lifespan=lifespan,
52
+ )
53
+ install_request_logging(app, "auth")
54
+ install_route_tracing(app, "auth")
55
+
56
+ app.add_middleware(
57
+ CORSMiddleware,
58
+ allow_origins=["*"],
59
+ allow_credentials=True,
60
+ allow_methods=["*"],
61
+ allow_headers=["*"],
62
+ )
63
+
64
+ app.include_router(auth_router, prefix="/api/v1/auth", tags=["Auth"])
65
+ app.include_router(auth_router, prefix="/api/auth", tags=["Auth-Frontend"]) # Frontend compatibility
66
+ app.include_router(me_router, prefix="/api/v1/me", tags=["Me"])
67
+ app.include_router(users_router, prefix="/api/v1/users", tags=["Users"])
68
+ app.include_router(roles_router, prefix="/api/v1/roles", tags=["Roles"])
69
+ app.include_router(permissions_router, prefix="/api/v1/permissions", tags=["Permissions"])
70
+ app.include_router(departments_router, prefix="/api/v1/departments", tags=["Departments"])
71
+ app.include_router(teams_router, prefix="/api/v1/teams", tags=["Teams"])
72
+ app.include_router(members_router, prefix="/api/v1/members", tags=["Members"])
73
+ app.include_router(session_router, prefix="/api/v1/session", tags=["Session"])
74
+ app.include_router(websocket_events_router, prefix="/api/v1/ws", tags=["WebSocket Events"])
75
+ app.include_router(integration_config_router, prefix="/integration-config", tags=["Integration Config"])
76
+ app.include_router(integration_config_router, prefix="/api/v1/integration-config", tags=["Integration Config"])
77
+
78
+
79
+ @app.get("/health", tags=["Health"])
80
+ async def health_check():
81
+ nats_status = consumer_status()
82
+ return {
83
+ "status": "healthy",
84
+ "nats_consumers": nats_status,
85
+ "approval_audit_consumer": nats_status["approval_audit_consumer"],
86
+ "audit_consumer": nats_status["audit_consumer"],
87
+ "mongo_cdc_watcher": cdc_watcher_status(),
88
+ }
@@ -0,0 +1,12 @@
1
+ """auth service models package."""
2
+
3
+ __all__ = [
4
+ "departments",
5
+ "login",
6
+ "permissions",
7
+ "roles",
8
+ "session",
9
+ "teamMembers",
10
+ "teams",
11
+ "users",
12
+ ]
@@ -0,0 +1,55 @@
1
+ from datetime import datetime, timezone
2
+ from typing import Optional, List
3
+ from pydantic import BaseModel, Field, model_validator
4
+
5
+
6
+ def utc_now() -> datetime:
7
+ return datetime.now(timezone.utc)
8
+
9
+
10
+ def ensure_utc(dt: Optional[datetime]) -> Optional[datetime]:
11
+ if dt is None:
12
+ return None
13
+ if dt.tzinfo is None:
14
+ return dt.replace(tzinfo=timezone.utc)
15
+ return dt.astimezone(timezone.utc)
16
+
17
+ class Department(BaseModel):
18
+ department_id: str = Field(..., min_length=1)
19
+ name: str = Field(..., min_length=1)
20
+ description: Optional[str] = None
21
+ head_user_id: Optional[str] = None # references UserEntry.user_id
22
+ is_active: bool = True
23
+
24
+ created_at: datetime = Field(default_factory=utc_now)
25
+ updated_at: datetime = Field(default_factory=utc_now)
26
+
27
+ @model_validator(mode="after")
28
+ def normalize_datetimes(self) -> "Department":
29
+ self.created_at = ensure_utc(self.created_at)
30
+ self.updated_at = ensure_utc(self.updated_at)
31
+ return self
32
+
33
+
34
+ class DepartmentCreate(Department):
35
+ pass
36
+
37
+
38
+ class DepartmentUpdate(BaseModel):
39
+ name: Optional[str] = None
40
+ description: Optional[str] = None
41
+ head_user_id: Optional[str] = None
42
+ is_active: Optional[bool] = None
43
+ updated_at: datetime = Field(default_factory=utc_now)
44
+
45
+
46
+ class DepartmentResponse(Department):
47
+ class Config:
48
+ from_attributes = True
49
+
50
+
51
+ class PaginatedDepartmentResponse(BaseModel):
52
+ total: int
53
+ page: int
54
+ page_size: int
55
+ results: List[DepartmentResponse]
@@ -0,0 +1,20 @@
1
+ from typing import Optional
2
+ from pydantic import BaseModel
3
+
4
+
5
+ class LoginRequest(BaseModel):
6
+ email: str
7
+ password: str
8
+
9
+
10
+ class TokenResponse(BaseModel):
11
+ access_token: str | None = None
12
+ refresh_token: str | None = None
13
+ token_type: str = "bearer"
14
+ mfa_required: bool = False
15
+ mfa_challenge_token: str | None = None
16
+
17
+ class RefreshTokenRequest(BaseModel):
18
+ refresh_token: str
19
+
20
+
@@ -0,0 +1,61 @@
1
+ from datetime import datetime, timezone
2
+ from typing import Optional, List
3
+ from pydantic import BaseModel, Field, model_validator
4
+
5
+ def utc_now() -> datetime:
6
+ return datetime.now(timezone.utc)
7
+
8
+
9
+ def ensure_utc(dt: Optional[datetime]) -> Optional[datetime]:
10
+ if dt is None:
11
+ return None
12
+ if dt.tzinfo is None:
13
+ return dt.replace(tzinfo=timezone.utc)
14
+ return dt.astimezone(timezone.utc)
15
+
16
+
17
+ # ---------------------------------------------------------------------------
18
+ # Permission
19
+ # ---------------------------------------------------------------------------
20
+ class Permission(BaseModel):
21
+ permission_id: str = Field(..., min_length=1)
22
+ role_id: Optional[str] = None
23
+ name: str = Field(..., min_length=1)
24
+ resource: str = Field(..., min_length=1)
25
+ action: str = Field(..., min_length=1)
26
+ description: Optional[str] = None
27
+ is_active: bool = True
28
+ created_at: datetime = Field(default_factory=utc_now)
29
+ updated_at: datetime = Field(default_factory=utc_now)
30
+
31
+ @model_validator(mode="after")
32
+ def normalize_datetimes(self) -> "Permission":
33
+ self.created_at = ensure_utc(self.created_at)
34
+ self.updated_at = ensure_utc(self.updated_at)
35
+ return self
36
+
37
+
38
+ class PermissionCreate(Permission):
39
+ pass
40
+
41
+
42
+ class PermissionUpdate(BaseModel):
43
+ role_id: Optional[str] = None
44
+ name: Optional[str] = None
45
+ resource: Optional[str] = None
46
+ action: Optional[str] = None
47
+ description: Optional[str] = None
48
+ is_active: Optional[bool] = None
49
+ updated_at: datetime = Field(default_factory=utc_now)
50
+
51
+
52
+ class PermissionResponse(Permission):
53
+ class Config:
54
+ from_attributes = True
55
+
56
+
57
+ class PaginatedPermissionResponse(BaseModel):
58
+ total: int
59
+ page: int
60
+ page_size: int
61
+ results: List[PermissionResponse]
@@ -0,0 +1,53 @@
1
+ from datetime import datetime, timezone
2
+ from typing import Optional, List
3
+ from pydantic import BaseModel, Field, model_validator
4
+
5
+ def utc_now() -> datetime:
6
+ return datetime.now(timezone.utc)
7
+
8
+
9
+ def ensure_utc(dt: Optional[datetime]) -> Optional[datetime]:
10
+ if dt is None:
11
+ return None
12
+ if dt.tzinfo is None:
13
+ return dt.replace(tzinfo=timezone.utc)
14
+ return dt.astimezone(timezone.utc)
15
+
16
+ class Role(BaseModel):
17
+ role_id: str = Field(..., min_length=1)
18
+ name: str = Field(..., min_length=1)
19
+ description: Optional[str] = None
20
+ permissions: List[str] = Field(default_factory=list) # references Permission.permission_id
21
+ is_active: bool = True
22
+ created_at: datetime = Field(default_factory=utc_now)
23
+ updated_at: datetime = Field(default_factory=utc_now)
24
+
25
+ @model_validator(mode="after")
26
+ def normalize_datetimes(self) -> "Role":
27
+ self.created_at = ensure_utc(self.created_at)
28
+ self.updated_at = ensure_utc(self.updated_at)
29
+ return self
30
+
31
+
32
+ class RoleCreate(Role):
33
+ pass
34
+
35
+
36
+ class RoleUpdate(BaseModel):
37
+ name: Optional[str] = None
38
+ description: Optional[str] = None
39
+ permissions: Optional[List[str]] = None
40
+ is_active: Optional[bool] = None
41
+ updated_at: datetime = Field(default_factory=utc_now)
42
+
43
+
44
+ class RoleResponse(Role):
45
+ class Config:
46
+ from_attributes = True
47
+
48
+
49
+ class PaginatedRoleResponse(BaseModel):
50
+ total: int
51
+ page: int
52
+ page_size: int
53
+ results: List[RoleResponse]
@@ -0,0 +1,26 @@
1
+ from typing import Any
2
+
3
+ from pydantic import BaseModel, Field
4
+
5
+
6
+ class SessionValueRequest(BaseModel):
7
+ value: Any
8
+
9
+
10
+ class SessionValueResponse(BaseModel):
11
+ key: str
12
+ value: Any = None
13
+ found: bool = True
14
+
15
+
16
+ class SessionBulkSaveRequest(BaseModel):
17
+ items: dict[str, Any] = Field(default_factory=dict)
18
+
19
+
20
+ class SessionBulkGetRequest(BaseModel):
21
+ keys: list[str] = Field(default_factory=list)
22
+
23
+
24
+ class SessionBulkResponse(BaseModel):
25
+ items: dict[str, Any | None] = Field(default_factory=dict)
26
+ missing: list[str] = Field(default_factory=list)
@@ -0,0 +1,59 @@
1
+ from datetime import datetime, timezone
2
+ from typing import Optional, List
3
+ from pydantic import BaseModel, Field, model_validator
4
+
5
+
6
+ # ── Helpers (reuse same) ──────────────────────────────────────────────────────
7
+ def utc_now() -> datetime:
8
+ return datetime.now(timezone.utc)
9
+
10
+
11
+ def ensure_utc(dt: Optional[datetime]) -> Optional[datetime]:
12
+ if dt is None:
13
+ return None
14
+ if dt.tzinfo is None:
15
+ return dt.replace(tzinfo=timezone.utc)
16
+ return dt.astimezone(timezone.utc)
17
+
18
+
19
+ # ── Team Member ───────────────────────────────────────────────────────────────
20
+ class TeamMember(BaseModel):
21
+ user_id: str = Field(..., min_length=1)
22
+ employee_id: str = Field(..., min_length=1)
23
+ name: str = Field(..., min_length=1)
24
+
25
+ department: Optional[str] = None
26
+ email: Optional[str] = None
27
+ role: Optional[str] = None
28
+
29
+ is_active: bool = True
30
+ joined_at: datetime = Field(default_factory=utc_now)
31
+
32
+ @model_validator(mode="after")
33
+ def normalize_datetimes(self) -> "TeamMember":
34
+ self.joined_at = ensure_utc(self.joined_at)
35
+ return self
36
+
37
+
38
+ # ── Create ────────────────────────────────────────────────────────────────────
39
+ class TeamMemberCreate(TeamMember):
40
+ pass
41
+
42
+
43
+ # ── Update ────────────────────────────────────────────────────────────────────
44
+ class TeamMemberUpdate(BaseModel):
45
+ department: Optional[str] = None
46
+ email: Optional[str] = None
47
+ role: Optional[str] = None
48
+ is_active: Optional[bool] = None
49
+
50
+
51
+ # ── Response ──────────────────────────────────────────────────────────────────
52
+ class TeamMemberResponse(TeamMember):
53
+ class Config:
54
+ from_attributes = True
55
+
56
+
57
+ # ── Mapping: team_id → members[] ──────────────────────────────────────────────
58
+ class TeamMembersMapResponse(BaseModel):
59
+ data: dict[str, List[TeamMemberResponse]]
@@ -0,0 +1,56 @@
1
+ from datetime import datetime, timezone
2
+ from typing import Optional, List
3
+ from pydantic import BaseModel, Field, model_validator
4
+
5
+ def utc_now() -> datetime:
6
+ return datetime.now(timezone.utc)
7
+
8
+
9
+ def ensure_utc(dt: Optional[datetime]) -> Optional[datetime]:
10
+ if dt is None:
11
+ return None
12
+ if dt.tzinfo is None:
13
+ return dt.replace(tzinfo=timezone.utc)
14
+ return dt.astimezone(timezone.utc)
15
+
16
+ class Team(BaseModel):
17
+ team_id: str = Field(..., min_length=1)
18
+ name: str = Field(..., min_length=1)
19
+ description: Optional[str] = None
20
+ department_id: str = Field(..., min_length=1) # parent department
21
+ lead_user_id: Optional[str] = None # references UserEntry.user_id
22
+ is_active: bool = True
23
+ created_at: datetime = Field(default_factory=utc_now)
24
+ updated_at: datetime = Field(default_factory=utc_now)
25
+
26
+ @model_validator(mode="after")
27
+ def normalize_datetimes(self) -> "Team":
28
+ self.created_at = ensure_utc(self.created_at)
29
+ self.updated_at = ensure_utc(self.updated_at)
30
+ return self
31
+
32
+
33
+
34
+ class TeamCreate(Team):
35
+ pass
36
+
37
+
38
+ class TeamUpdate(BaseModel):
39
+ name: Optional[str] = None
40
+ description: Optional[str] = None
41
+ department_id: Optional[str] = None
42
+ lead_user_id: Optional[str] = None
43
+ is_active: Optional[bool] = None
44
+ updated_at: datetime = Field(default_factory=utc_now)
45
+
46
+
47
+ class TeamResponse(Team):
48
+ class Config:
49
+ from_attributes = True
50
+
51
+
52
+ class PaginatedTeamResponse(BaseModel):
53
+ total: int
54
+ page: int
55
+ page_size: int
56
+ results: List[TeamResponse]