factorysemantics-mes 0.1.2__tar.gz → 0.2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (630) hide show
  1. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/.env.example +29 -1
  2. factorysemantics_mes-0.2.0/.github/scripts/demo_from_wheel.sh +64 -0
  3. factorysemantics_mes-0.2.0/.github/scripts/upgrade_from_previous_release.sh +95 -0
  4. factorysemantics_mes-0.2.0/.github/workflows/ci.yml +179 -0
  5. factorysemantics_mes-0.2.0/.github/workflows/erpnext-live.yml +165 -0
  6. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/.github/workflows/release.yml +31 -1
  7. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/.gitignore +3 -0
  8. factorysemantics_mes-0.2.0/CHANGELOG.md +965 -0
  9. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/CITATION.cff +2 -1
  10. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/CONTRIBUTING.md +9 -0
  11. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/PKG-INFO +5 -2
  12. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/README.md +1 -1
  13. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/ROADMAP.md +24 -12
  14. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/alembic.ini +1 -1
  15. factorysemantics_mes-0.2.0/config/inbound_mapping.json +48 -0
  16. factorysemantics_mes-0.2.0/config/inbound_sql.json +25 -0
  17. factorysemantics_mes-0.2.0/deploy/README.md +95 -0
  18. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/deploy/fsmes-prod-plant@.service +1 -1
  19. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/deploy/promote.sh +1 -1
  20. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/docker/Dockerfile +1 -2
  21. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/docker/docker-compose.yml +8 -0
  22. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/docs/ARCHITECTURE.md +5 -3
  23. factorysemantics_mes-0.2.0/docs/decisions/0009-organisation-not-personal-account.md +24 -0
  24. factorysemantics_mes-0.2.0/docs/decisions/0010-github-discussions-only.md +25 -0
  25. factorysemantics_mes-0.2.0/docs/decisions/0011-mkdocs-material-generated-reference.md +25 -0
  26. factorysemantics_mes-0.2.0/docs/decisions/0012-contributor-covenant-3.md +24 -0
  27. factorysemantics_mes-0.2.0/docs/decisions/0013-governance-is-one-page.md +24 -0
  28. factorysemantics_mes-0.2.0/docs/decisions/0014-first-public-version-is-0-1-0.md +24 -0
  29. factorysemantics_mes-0.2.0/docs/decisions/0015-mcp-registry-name.md +24 -0
  30. factorysemantics_mes-0.2.0/docs/decisions/0016-no-trademark-registration.md +24 -0
  31. factorysemantics_mes-0.2.0/docs/decisions/0017-one-public-demo-gated-and-bounded.md +25 -0
  32. factorysemantics_mes-0.2.0/docs/decisions/0018-public-on-2026-09-08-and-the-pre-tag-check.md +26 -0
  33. factorysemantics_mes-0.2.0/docs/decisions/0019-count-everything-the-machine-counted.md +75 -0
  34. factorysemantics_mes-0.2.0/docs/decisions/0020-what-supported-means-for-an-erp-connector.md +129 -0
  35. factorysemantics_mes-0.2.0/docs/decisions/0021-one-database-per-plant.md +101 -0
  36. factorysemantics_mes-0.2.0/docs/decisions/0022-what-a-plant-pack-may-contain.md +135 -0
  37. factorysemantics_mes-0.2.0/docs/decisions/0023-the-fleet-console-observes.md +347 -0
  38. factorysemantics_mes-0.2.0/docs/decisions/index.md +34 -0
  39. factorysemantics_mes-0.2.0/docs/design/m8-packs-and-fleet.md +625 -0
  40. factorysemantics_mes-0.2.0/docs/develop/erp-connectors.md +318 -0
  41. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/docs/develop/index.md +9 -1
  42. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/docs/develop/your-first-module.md +13 -3
  43. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/docs/hooks/generate.py +62 -2
  44. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/docs/index.md +3 -2
  45. factorysemantics_mes-0.2.0/docs/operate/backup.md +202 -0
  46. factorysemantics_mes-0.2.0/docs/operate/compatibility.md +55 -0
  47. factorysemantics_mes-0.2.0/docs/operate/confirmation-examples/completion-with-a-lot.json +14 -0
  48. factorysemantics_mes-0.2.0/docs/operate/confirmation-examples/completion-with-a-lot.xml +16 -0
  49. factorysemantics_mes-0.2.0/docs/operate/confirmation-examples/completion-with-an-over-run.json +14 -0
  50. factorysemantics_mes-0.2.0/docs/operate/confirmation-examples/completion-with-an-over-run.xml +16 -0
  51. factorysemantics_mes-0.2.0/docs/operate/confirmation-examples/completion-without-a-lot.json +14 -0
  52. factorysemantics_mes-0.2.0/docs/operate/confirmation-examples/completion-without-a-lot.xml +15 -0
  53. factorysemantics_mes-0.2.0/docs/operate/confirmation-examples/operation-clean.json +22 -0
  54. factorysemantics_mes-0.2.0/docs/operate/confirmation-examples/operation-clean.xml +23 -0
  55. factorysemantics_mes-0.2.0/docs/operate/confirmation-examples/operation-over-run.json +22 -0
  56. factorysemantics_mes-0.2.0/docs/operate/confirmation-examples/operation-over-run.xml +23 -0
  57. factorysemantics_mes-0.2.0/docs/operate/confirmation-examples/operation-with-scrap-and-components.json +35 -0
  58. factorysemantics_mes-0.2.0/docs/operate/confirmation-examples/operation-with-scrap-and-components.xml +35 -0
  59. factorysemantics_mes-0.2.0/docs/operate/confirmation-files.md +131 -0
  60. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/docs/operate/deploy.md +4 -3
  61. factorysemantics_mes-0.2.0/docs/operate/erpnext.md +215 -0
  62. factorysemantics_mes-0.2.0/docs/operate/first-plant.md +395 -0
  63. factorysemantics_mes-0.2.0/docs/operate/first-week.md +113 -0
  64. factorysemantics_mes-0.2.0/docs/operate/fleet.md +155 -0
  65. factorysemantics_mes-0.2.0/docs/operate/inbound.md +588 -0
  66. factorysemantics_mes-0.2.0/docs/operate/index.md +33 -0
  67. factorysemantics_mes-0.2.0/docs/operate/modules.md +152 -0
  68. factorysemantics_mes-0.2.0/docs/operate/opc-readonly.md +243 -0
  69. factorysemantics_mes-0.2.0/docs/operate/packs.md +149 -0
  70. factorysemantics_mes-0.2.0/docs/operate/registry.md +68 -0
  71. factorysemantics_mes-0.2.0/docs/operate/shadow-mode.md +174 -0
  72. factorysemantics_mes-0.2.0/docs/operate/shadow-scorecard.md +189 -0
  73. factorysemantics_mes-0.2.0/docs/operate/tls.md +167 -0
  74. factorysemantics_mes-0.2.0/docs/operate/uns.md +284 -0
  75. factorysemantics_mes-0.2.0/docs/operate/upgrade.md +280 -0
  76. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/docs/plant/first-line.md +1 -1
  77. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/docs/plant/index.md +1 -0
  78. factorysemantics_mes-0.2.0/docs/releases/0.2.0.md +136 -0
  79. factorysemantics_mes-0.2.0/docs/releases/index.md +17 -0
  80. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/labs/cutlery/README.md +15 -2
  81. factorysemantics_mes-0.2.0/labs/cutlery/fleet.toml +14 -0
  82. factorysemantics_mes-0.2.0/labs/cutlery/plant.toml +45 -0
  83. factorysemantics_mes-0.2.0/labs/erpnext/VERSIONS.md +34 -0
  84. factorysemantics_mes-0.2.0/labs/erpnext/docker-compose.yml +202 -0
  85. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/labs/erpnext/seed_erpnext.py +15 -47
  86. factorysemantics_mes-0.2.0/labs/megafactory/fleet.toml +13 -0
  87. factorysemantics_mes-0.2.0/labs/megafactory/full/plant.toml +43 -0
  88. factorysemantics_mes-0.2.0/labs/multiplant/README.md +133 -0
  89. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/labs/multiplant/bottling/init.py +12 -3
  90. factorysemantics_mes-0.2.0/labs/multiplant/bottling/plant.toml +39 -0
  91. factorysemantics_mes-0.2.0/labs/multiplant/bottling/tag_map.json +97 -0
  92. factorysemantics_mes-0.2.0/labs/multiplant/finewire/README.md +59 -0
  93. factorysemantics_mes-0.2.0/labs/multiplant/finewire/mappings/inbound_mapping.json +16 -0
  94. factorysemantics_mes-0.2.0/labs/multiplant/finewire/masterdata/equipment.json +10 -0
  95. factorysemantics_mes-0.2.0/labs/multiplant/finewire/masterdata/lots.json +3 -0
  96. factorysemantics_mes-0.2.0/labs/multiplant/finewire/masterdata/materials.json +4 -0
  97. factorysemantics_mes-0.2.0/labs/multiplant/finewire/masterdata/quality_specs.json +3 -0
  98. factorysemantics_mes-0.2.0/labs/multiplant/finewire/masterdata/routings.json +13 -0
  99. factorysemantics_mes-0.2.0/labs/multiplant/finewire/masterdata/work_orders.json +3 -0
  100. factorysemantics_mes-0.2.0/labs/multiplant/finewire/plant.toml +97 -0
  101. factorysemantics_mes-0.2.0/labs/multiplant/finewire/tag_map.json +62 -0
  102. factorysemantics_mes-0.2.0/labs/multiplant/fleet.toml +15 -0
  103. factorysemantics_mes-0.2.0/labs/multiplant/machining/masterdata/README.md +14 -0
  104. factorysemantics_mes-0.2.0/labs/multiplant/machining/masterdata/equipment.json +9 -0
  105. factorysemantics_mes-0.2.0/labs/multiplant/machining/masterdata/lots.json +3 -0
  106. factorysemantics_mes-0.2.0/labs/multiplant/machining/masterdata/materials.json +4 -0
  107. factorysemantics_mes-0.2.0/labs/multiplant/machining/masterdata/quality_specs.json +3 -0
  108. factorysemantics_mes-0.2.0/labs/multiplant/machining/masterdata/routings.json +12 -0
  109. factorysemantics_mes-0.2.0/labs/multiplant/machining/masterdata/work_orders.json +3 -0
  110. factorysemantics_mes-0.2.0/labs/multiplant/machining/plant.toml +34 -0
  111. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/mkdocs.yml +38 -1
  112. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/pyproject.toml +38 -3
  113. factorysemantics_mes-0.2.0/src/fsmes/__init__.py +17 -0
  114. factorysemantics_mes-0.2.0/src/fsmes/api/app.py +237 -0
  115. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/api/routers/admin.py +1 -1
  116. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/api/routers/assist.py +3 -1
  117. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/api/routers/auth.py +15 -3
  118. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/api/routers/execution.py +23 -1
  119. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/api/routers/maintenance.py +1 -1
  120. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/api/routers/masterdata.py +4 -4
  121. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/api/routers/ops.py +1 -1
  122. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/api/routers/quality.py +2 -2
  123. factorysemantics_mes-0.2.0/src/fsmes/api/routers/system.py +150 -0
  124. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/api/routers/workorders.py +4 -1
  125. factorysemantics_mes-0.2.0/src/fsmes/backup.py +365 -0
  126. factorysemantics_mes-0.2.0/src/fsmes/cli.py +2416 -0
  127. factorysemantics_mes-0.2.0/src/fsmes/config.py +411 -0
  128. factorysemantics_mes-0.2.0/src/fsmes/db.py +111 -0
  129. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/domain/__init__.py +6 -0
  130. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/domain/equipment.py +4 -0
  131. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/domain/execution.py +21 -2
  132. factorysemantics_mes-0.2.0/src/fsmes/domain/inbound.py +106 -0
  133. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/domain/integration.py +7 -1
  134. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/domain/quality.py +6 -0
  135. factorysemantics_mes-0.2.0/src/fsmes/domain/uns.py +43 -0
  136. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/domain/workorders.py +12 -0
  137. factorysemantics_mes-0.2.0/src/fsmes/fleet/__init__.py +28 -0
  138. factorysemantics_mes-0.2.0/src/fsmes/fleet/commands.py +270 -0
  139. factorysemantics_mes-0.2.0/src/fsmes/fleet/console.py +215 -0
  140. factorysemantics_mes-0.2.0/src/fsmes/fleet/observe.py +98 -0
  141. factorysemantics_mes-0.2.0/src/fsmes/fleet/owned.py +465 -0
  142. factorysemantics_mes-0.2.0/src/fsmes/identity.py +286 -0
  143. factorysemantics_mes-0.2.0/src/fsmes/integrations/erp/b2mml.py +190 -0
  144. factorysemantics_mes-0.2.0/src/fsmes/integrations/erp/base.py +243 -0
  145. factorysemantics_mes-0.2.0/src/fsmes/integrations/erp/conformance.py +232 -0
  146. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/integrations/erp/contract.py +17 -0
  147. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/integrations/erp/erpnext_adapter.py +218 -31
  148. factorysemantics_mes-0.2.0/src/fsmes/integrations/erp/erpnext_setup.py +208 -0
  149. factorysemantics_mes-0.2.0/src/fsmes/integrations/erp/examples.py +263 -0
  150. factorysemantics_mes-0.2.0/src/fsmes/integrations/erp/file_adapter.py +228 -0
  151. factorysemantics_mes-0.2.0/src/fsmes/integrations/erp/incumbent.py +324 -0
  152. factorysemantics_mes-0.2.0/src/fsmes/integrations/erp/rest_adapter.py +97 -0
  153. factorysemantics_mes-0.2.0/src/fsmes/integrations/erp/schema.py +406 -0
  154. factorysemantics_mes-0.2.0/src/fsmes/integrations/erp/scorecard.py +620 -0
  155. factorysemantics_mes-0.2.0/src/fsmes/integrations/erp/scorecard_html.py +158 -0
  156. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/integrations/erp/sync.py +16 -5
  157. factorysemantics_mes-0.2.0/src/fsmes/integrations/erp/validate.py +357 -0
  158. factorysemantics_mes-0.2.0/src/fsmes/integrations/events.py +108 -0
  159. factorysemantics_mes-0.2.0/src/fsmes/integrations/inbound/__init__.py +13 -0
  160. factorysemantics_mes-0.2.0/src/fsmes/integrations/inbound/contract.py +232 -0
  161. factorysemantics_mes-0.2.0/src/fsmes/integrations/inbound/folder.py +462 -0
  162. factorysemantics_mes-0.2.0/src/fsmes/integrations/inbound/mqtt.py +620 -0
  163. factorysemantics_mes-0.2.0/src/fsmes/integrations/inbound/sql.py +673 -0
  164. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/integrations/opc/agent.py +59 -10
  165. factorysemantics_mes-0.2.0/src/fsmes/integrations/uns/__init__.py +7 -0
  166. factorysemantics_mes-0.2.0/src/fsmes/integrations/uns/envelope.py +60 -0
  167. factorysemantics_mes-0.2.0/src/fsmes/integrations/uns/publisher.py +169 -0
  168. factorysemantics_mes-0.2.0/src/fsmes/integrations/uns/topics.py +219 -0
  169. factorysemantics_mes-0.2.0/src/fsmes/integrations/uns/transport.py +193 -0
  170. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/mcp/adjustments.py +6 -1
  171. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/mcp_server.py +98 -32
  172. {factorysemantics_mes-0.1.2/alembic → factorysemantics_mes-0.2.0/src/fsmes/migrations}/env.py +8 -1
  173. factorysemantics_mes-0.2.0/src/fsmes/migrations/versions/a3f6c81d09e2_unassigned_production.py +40 -0
  174. factorysemantics_mes-0.2.0/src/fsmes/migrations/versions/a4d9c2e70f18_uns_publications.py +47 -0
  175. factorysemantics_mes-0.2.0/src/fsmes/migrations/versions/b5c1d09e73af_inbound_events_and_their_source.py +61 -0
  176. factorysemantics_mes-0.2.0/src/fsmes/migrations/versions/c8b1e40d7a92_erp_messages_direction_index.py +34 -0
  177. factorysemantics_mes-0.2.0/src/fsmes/migrations/versions/d9a3f61c48e0_inbound_sql_watermarks.py +52 -0
  178. factorysemantics_mes-0.2.0/src/fsmes/modules.py +392 -0
  179. factorysemantics_mes-0.2.0/src/fsmes/pack/__init__.py +23 -0
  180. factorysemantics_mes-0.2.0/src/fsmes/pack/apply.py +354 -0
  181. factorysemantics_mes-0.2.0/src/fsmes/pack/check.py +506 -0
  182. factorysemantics_mes-0.2.0/src/fsmes/pack/fleet.py +124 -0
  183. factorysemantics_mes-0.2.0/src/fsmes/pack/format.py +395 -0
  184. factorysemantics_mes-0.2.0/src/fsmes/pack/masterdata.py +271 -0
  185. factorysemantics_mes-0.2.0/src/fsmes/pack/migrate.py +230 -0
  186. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/plant.py +106 -80
  187. factorysemantics_mes-0.2.0/src/fsmes/schema.py +226 -0
  188. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/services/agent.py +11 -0
  189. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/services/analysis.py +15 -3
  190. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/services/calendar.py +42 -8
  191. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/services/coa.py +1 -1
  192. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/services/design.py +9 -0
  193. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/services/equipment.py +63 -1
  194. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/services/erp.py +56 -13
  195. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/services/execution.py +123 -9
  196. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/services/gauges.py +6 -2
  197. factorysemantics_mes-0.2.0/src/fsmes/services/inbound.py +316 -0
  198. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/services/maintenance.py +2 -2
  199. factorysemantics_mes-0.2.0/src/fsmes/services/outbox.py +133 -0
  200. factorysemantics_mes-0.2.0/src/fsmes/services/uns.py +219 -0
  201. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/services/workorders.py +9 -1
  202. factorysemantics_mes-0.2.0/src/fsmes/shadow.py +575 -0
  203. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/sim/agent_eval.py +3 -1
  204. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/sim/autoloop.py +27 -6
  205. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/sim/mcp_server.py +3 -1
  206. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/sim/runner.py +11 -3
  207. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/sim/ui_check.py +15 -9
  208. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/analysis.js +4 -1
  209. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/app.js +2 -1
  210. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/common.js +106 -10
  211. factorysemantics_mes-0.2.0/src/fsmes/web/fleet.css +61 -0
  212. factorysemantics_mes-0.2.0/src/fsmes/web/fleet.html +64 -0
  213. factorysemantics_mes-0.2.0/src/fsmes/web/fleet.js +132 -0
  214. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/instructions.js +2 -1
  215. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/kit.js +6 -2
  216. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/machine.html +10 -1
  217. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/machine.js +36 -2
  218. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/orders.js +3 -1
  219. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/quality.js +4 -2
  220. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/styles.css +41 -1
  221. factorysemantics_mes-0.2.0/tests/conftest.py +183 -0
  222. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/tests/test_api.py +7 -2
  223. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/tests/test_auth.py +46 -0
  224. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/tests/test_autoloop.py +2 -2
  225. factorysemantics_mes-0.2.0/tests/test_backup.py +274 -0
  226. factorysemantics_mes-0.2.0/tests/test_cli.py +111 -0
  227. factorysemantics_mes-0.2.0/tests/test_core_purity.py +340 -0
  228. factorysemantics_mes-0.2.0/tests/test_demo_verdict.py +63 -0
  229. factorysemantics_mes-0.2.0/tests/test_environments.py +187 -0
  230. factorysemantics_mes-0.2.0/tests/test_erp_confirmation_files.py +275 -0
  231. factorysemantics_mes-0.2.0/tests/test_erp_conformance.py +272 -0
  232. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/tests/test_erp_contract.py +46 -0
  233. factorysemantics_mes-0.2.0/tests/test_erpnext.py +519 -0
  234. factorysemantics_mes-0.2.0/tests/test_erpnext_live.py +517 -0
  235. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/tests/test_execution.py +5 -1
  236. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/tests/test_file_erp.py +2 -2
  237. factorysemantics_mes-0.2.0/tests/test_fleet_console.py +285 -0
  238. factorysemantics_mes-0.2.0/tests/test_fleet_ownership.py +427 -0
  239. factorysemantics_mes-0.2.0/tests/test_inbound.py +285 -0
  240. factorysemantics_mes-0.2.0/tests/test_inbound_folder.py +293 -0
  241. factorysemantics_mes-0.2.0/tests/test_inbound_mqtt.py +626 -0
  242. factorysemantics_mes-0.2.0/tests/test_inbound_sql.py +478 -0
  243. factorysemantics_mes-0.2.0/tests/test_migrations_have_one_head.py +27 -0
  244. factorysemantics_mes-0.2.0/tests/test_module_wall.py +309 -0
  245. factorysemantics_mes-0.2.0/tests/test_no_tenant_literals.py +288 -0
  246. factorysemantics_mes-0.2.0/tests/test_outbox_events.py +255 -0
  247. factorysemantics_mes-0.2.0/tests/test_overproduction.py +162 -0
  248. factorysemantics_mes-0.2.0/tests/test_pack_format.py +517 -0
  249. factorysemantics_mes-0.2.0/tests/test_pack_third.py +225 -0
  250. factorysemantics_mes-0.2.0/tests/test_plant_identity.py +271 -0
  251. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/tests/test_plant_migrate.py +22 -0
  252. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/tests/test_plant_scale_lists.py +9 -0
  253. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/tests/test_route_coverage.py +1 -1
  254. factorysemantics_mes-0.2.0/tests/test_schema_upgrade.py +173 -0
  255. factorysemantics_mes-0.2.0/tests/test_shadow_mode.py +442 -0
  256. factorysemantics_mes-0.2.0/tests/test_shadow_scorecard.py +334 -0
  257. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/tests/test_sim.py +6 -2
  258. factorysemantics_mes-0.2.0/tests/test_sqlite_write_locks.py +150 -0
  259. factorysemantics_mes-0.2.0/tests/test_the_suite_knows_its_database.py +25 -0
  260. factorysemantics_mes-0.2.0/tests/test_uns.py +816 -0
  261. factorysemantics_mes-0.1.2/.github/workflows/ci.yml +0 -55
  262. factorysemantics_mes-0.1.2/CHANGELOG.md +0 -76
  263. factorysemantics_mes-0.1.2/deploy/README.md +0 -68
  264. factorysemantics_mes-0.1.2/docs/decisions/index.md +0 -17
  265. factorysemantics_mes-0.1.2/docs/operate/compatibility.md +0 -20
  266. factorysemantics_mes-0.1.2/docs/operate/erpnext.md +0 -57
  267. factorysemantics_mes-0.1.2/docs/operate/index.md +0 -18
  268. factorysemantics_mes-0.1.2/docs/operate/registry.md +0 -59
  269. factorysemantics_mes-0.1.2/labs/cutlery/registry.toml +0 -29
  270. factorysemantics_mes-0.1.2/labs/megafactory/registry.toml +0 -36
  271. factorysemantics_mes-0.1.2/labs/multiplant/README.md +0 -88
  272. factorysemantics_mes-0.1.2/labs/multiplant/fsplant.ps1 +0 -196
  273. factorysemantics_mes-0.1.2/labs/multiplant/machining/seed.py +0 -156
  274. factorysemantics_mes-0.1.2/labs/multiplant/plants.toml +0 -30
  275. factorysemantics_mes-0.1.2/src/fsmes/__init__.py +0 -11
  276. factorysemantics_mes-0.1.2/src/fsmes/api/app.py +0 -344
  277. factorysemantics_mes-0.1.2/src/fsmes/api/routers/system.py +0 -75
  278. factorysemantics_mes-0.1.2/src/fsmes/cli.py +0 -1152
  279. factorysemantics_mes-0.1.2/src/fsmes/config.py +0 -133
  280. factorysemantics_mes-0.1.2/src/fsmes/db.py +0 -66
  281. factorysemantics_mes-0.1.2/src/fsmes/integrations/erp/b2mml.py +0 -97
  282. factorysemantics_mes-0.1.2/src/fsmes/integrations/erp/base.py +0 -51
  283. factorysemantics_mes-0.1.2/src/fsmes/integrations/erp/file_adapter.py +0 -56
  284. factorysemantics_mes-0.1.2/src/fsmes/integrations/erp/rest_adapter.py +0 -22
  285. factorysemantics_mes-0.1.2/tests/conftest.py +0 -107
  286. factorysemantics_mes-0.1.2/tests/test_cli.py +0 -27
  287. factorysemantics_mes-0.1.2/tests/test_environments.py +0 -124
  288. factorysemantics_mes-0.1.2/tests/test_erpnext.py +0 -253
  289. factorysemantics_mes-0.1.2/tests/test_migrations_have_one_head.py +0 -18
  290. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/.github/CODEOWNERS +0 -0
  291. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/.github/ISSUE_TEMPLATE/bug.yml +0 -0
  292. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  293. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/.github/ISSUE_TEMPLATE/integration.yml +0 -0
  294. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/.github/ISSUE_TEMPLATE/plant-pack.yml +0 -0
  295. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  296. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/.github/dependabot.yml +0 -0
  297. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/.github/workflows/dco.yml +0 -0
  298. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/.github/workflows/docs.yml +0 -0
  299. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/.github/workflows/scorecard.yml +0 -0
  300. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/.github/workflows/welcome.yml +0 -0
  301. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/CODE_OF_CONDUCT.md +0 -0
  302. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/GOVERNANCE.md +0 -0
  303. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/LICENSE +0 -0
  304. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/MAINTAINERS.md +0 -0
  305. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/NOTICE +0 -0
  306. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/SECURITY.md +0 -0
  307. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/config/line_layout.json +0 -0
  308. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/config/tag_map.json +0 -0
  309. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/config/tag_map_kepsim.json +0 -0
  310. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/config/tag_map_kepware.json +0 -0
  311. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/deploy/fsmes-autoloop.service +0 -0
  312. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/deploy/fsmes-autoloop.timer +0 -0
  313. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/docker/nginx.conf +0 -0
  314. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/docs/LANDSCAPE.md +0 -0
  315. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/docs/agents/connect-mcp-client.md +0 -0
  316. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/docs/agents/evals.md +0 -0
  317. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/docs/agents/index.md +0 -0
  318. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/docs/agents/write-discipline.md +0 -0
  319. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/docs/ai/BUDGET.md +0 -0
  320. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/docs/ai/OBSERVABILITY.md +0 -0
  321. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/docs/decisions/0001-apache-2-with-dco.md +0 -0
  322. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/docs/decisions/0002-kernel-and-modules.md +0 -0
  323. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/docs/decisions/0003-one-mcp-server.md +0 -0
  324. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/docs/decisions/0004-never-invent-production.md +0 -0
  325. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/docs/decisions/0005-plain-html-no-build-step.md +0 -0
  326. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/docs/decisions/0006-sqlite-laptop-postgresql-plant.md +0 -0
  327. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/docs/decisions/0007-fresh-public-history.md +0 -0
  328. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/docs/decisions/0008-erp-connectors-are-modules.md +0 -0
  329. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/docs/decisions/TEMPLATE.md +0 -0
  330. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/docs/design/STYLE.md +0 -0
  331. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/docs/design/backlog/README.md +0 -0
  332. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/docs/design/backlog/analysis-cards-scaling.md +0 -0
  333. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/docs/design/backlog/book-output-explicit-order.md +0 -0
  334. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/docs/design/backlog/clickable-kpi-tiles.md +0 -0
  335. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/docs/design/backlog/opc-integration-suite.md +0 -0
  336. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/docs/design/backlog/order-lifecycle-actions.md +0 -0
  337. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/docs/design/backlog/orders-creatable-materials.md +0 -0
  338. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/docs/design/backlog/orders-supervisor-filters.md +0 -0
  339. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/docs/design/backlog/review-orders.md +0 -0
  340. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/docs/design/backlog/review-station.md +0 -0
  341. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/docs/design/backlog/scrap-reason-codes.md +0 -0
  342. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/docs/design/backlog/sixty-machine-plant.md +0 -0
  343. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/docs/design/backlog/spc-capability-withheld.md +0 -0
  344. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/docs/design/backlog/station-spc.md +0 -0
  345. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/docs/design/backlog/station-view.md +0 -0
  346. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/docs/design/backlog/supervisor-drill-down.md +0 -0
  347. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/docs/design/backlog/ui-style-drift-bc58fb4f8e4d.md +0 -0
  348. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/docs/history/private-era.md +0 -0
  349. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/docs/onboarding/GUIDE-ENGINEERING.md +0 -0
  350. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/docs/onboarding/GUIDE-IT.md +0 -0
  351. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/docs/onboarding/README.md +0 -0
  352. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/docs/onboarding/worksheet-example.csv +0 -0
  353. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/docs/onboarding/worksheet-template.csv +0 -0
  354. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/docs/operate/security.md +0 -0
  355. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/docs/plant/never-invent-production.md +0 -0
  356. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/docs/plant/reading-oee.md +0 -0
  357. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/labs/cutlery/analysis/build_notebook.py +0 -0
  358. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/labs/cutlery/analysis/build_report.py +0 -0
  359. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/labs/cutlery/analysis/cutlery_run_analysis.ipynb +0 -0
  360. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/labs/cutlery/analysis/viz.py +0 -0
  361. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/labs/cutlery/build_config.py +0 -0
  362. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/labs/cutlery/fill_day.py +0 -0
  363. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/labs/cutlery/init.py +0 -0
  364. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/labs/cutlery/line.json +0 -0
  365. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/labs/cutlery/make_tag_map.py +0 -0
  366. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/labs/cutlery/run_cutlery.py +0 -0
  367. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/labs/cutlery/tag_map.json +0 -0
  368. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/labs/cutlery/walkthroughs/install_walkthroughs.py +0 -0
  369. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/labs/cutlery/walkthroughs/walkthroughs.json +0 -0
  370. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/labs/kepsim/.env.example +0 -0
  371. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/labs/kepsim/README.md +0 -0
  372. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/labs/kepsim/kepware_setup.py +0 -0
  373. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/labs/kepsim/line.json +0 -0
  374. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/labs/kepsim/scenario.md +0 -0
  375. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/labs/kepsim/setup_dsn.ps1 +0 -0
  376. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/labs/kepsim/verify_readback.py +0 -0
  377. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/labs/megafactory/build_config.py +0 -0
  378. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/labs/megafactory/full/build_config.py +0 -0
  379. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/labs/megafactory/full/init.py +0 -0
  380. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/labs/megafactory/full/line.json +0 -0
  381. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/labs/megafactory/full/run_full.py +0 -0
  382. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/labs/megafactory/full/seed_breadth.py +0 -0
  383. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/labs/megafactory/full/surfaces.py +0 -0
  384. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/labs/megafactory/full/tag_map.json +0 -0
  385. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/labs/megafactory/init.py +0 -0
  386. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/labs/megafactory/line.json +0 -0
  387. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/labs/megafactory/make_tag_map.py +0 -0
  388. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/labs/megafactory/run_spike.py +0 -0
  389. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/labs/megafactory/seed_breadth.py +0 -0
  390. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/labs/megafactory/tag_map.json +0 -0
  391. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/labs/multiplant/machining/line.json +0 -0
  392. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/labs/multiplant/machining/tag_map.json +0 -0
  393. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/api/__init__.py +0 -0
  394. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/api/deps.py +0 -0
  395. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/api/idempotency.py +0 -0
  396. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/api/paging.py +0 -0
  397. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/api/routers/__init__.py +0 -0
  398. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/api/routers/adjustments.py +0 -0
  399. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/api/routers/analysis.py +0 -0
  400. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/api/routers/coa.py +0 -0
  401. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/api/routers/dashboard.py +0 -0
  402. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/api/routers/design.py +0 -0
  403. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/api/routers/documents.py +0 -0
  404. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/api/routers/equipment.py +0 -0
  405. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/api/routers/erp.py +0 -0
  406. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/api/routers/kpis.py +0 -0
  407. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/api/routers/line.py +0 -0
  408. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/api/routers/scheduling.py +0 -0
  409. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/api/routers/serialization.py +0 -0
  410. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/api/routers/triggers.py +0 -0
  411. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/core/__init__.py +0 -0
  412. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/core/oplock.py +0 -0
  413. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/demo_feed.py +0 -0
  414. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/domain/adjustments.py +0 -0
  415. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/domain/audit.py +0 -0
  416. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/domain/calendar.py +0 -0
  417. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/domain/common.py +0 -0
  418. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/domain/documents.py +0 -0
  419. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/domain/gauges.py +0 -0
  420. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/domain/idempotency.py +0 -0
  421. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/domain/maintenance.py +0 -0
  422. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/domain/masterdata.py +0 -0
  423. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/domain/scheduling.py +0 -0
  424. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/domain/serialization.py +0 -0
  425. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/domain/timeseries.py +0 -0
  426. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/domain/triggers.py +0 -0
  427. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/integrations/__init__.py +0 -0
  428. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/integrations/erp/__init__.py +0 -0
  429. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/integrations/erp/mock_erp.py +0 -0
  430. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/integrations/opc/__init__.py +0 -0
  431. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/integrations/opc/csv_replay.py +0 -0
  432. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/integrations/opc/inspect.py +0 -0
  433. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/integrations/opc/security.py +0 -0
  434. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/integrations/opc/simulator.py +0 -0
  435. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/integrations/opc/tag_map.py +0 -0
  436. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/integrations/opc/worksheet.py +0 -0
  437. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/kernel/__init__.py +0 -0
  438. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/kernel/common.py +0 -0
  439. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/kernel/tags.py +0 -0
  440. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/logging.py +0 -0
  441. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/mcp/__init__.py +0 -0
  442. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/mcp/coa.py +0 -0
  443. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/mcp/equipment.py +0 -0
  444. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/mcp/erp.py +0 -0
  445. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/mcp/maintenance.py +0 -0
  446. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/mcp/masterdata.py +0 -0
  447. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/mcp/quality.py +0 -0
  448. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/mcp/scheduling.py +0 -0
  449. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/mcp/serialization.py +0 -0
  450. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/mcp/triggers.py +0 -0
  451. {factorysemantics_mes-0.1.2/alembic → factorysemantics_mes-0.2.0/src/fsmes/migrations}/script.py.mako +0 -0
  452. {factorysemantics_mes-0.1.2/alembic → factorysemantics_mes-0.2.0/src/fsmes/migrations}/versions/153379d6cf19_merge_cutlery_and_walkthrough_chains.py +0 -0
  453. {factorysemantics_mes-0.1.2/alembic → factorysemantics_mes-0.2.0/src/fsmes/migrations}/versions/18af853fc5c4_initial_schema.py +0 -0
  454. {factorysemantics_mes-0.1.2/alembic → factorysemantics_mes-0.2.0/src/fsmes/migrations}/versions/7c1e5a9d2b4f_serial_sequences.py +0 -0
  455. {factorysemantics_mes-0.1.2/alembic → factorysemantics_mes-0.2.0/src/fsmes/migrations}/versions/9c4d2c836d05_add_user_passwords.py +0 -0
  456. {factorysemantics_mes-0.1.2/alembic → factorysemantics_mes-0.2.0/src/fsmes/migrations}/versions/a1b2c3d4e5f6_agent_identity.py +0 -0
  457. {factorysemantics_mes-0.1.2/alembic → factorysemantics_mes-0.2.0/src/fsmes/migrations}/versions/a1c5e83b7602_calendar_and_scheduling.py +0 -0
  458. {factorysemantics_mes-0.1.2/alembic → factorysemantics_mes-0.2.0/src/fsmes/migrations}/versions/a7c1e93b5f20_roles_as_data.py +0 -0
  459. {factorysemantics_mes-0.1.2/alembic → factorysemantics_mes-0.2.0/src/fsmes/migrations}/versions/a7c2e5d1b9f0_document_kind_steps_needs_walkthroughs.py +0 -0
  460. {factorysemantics_mes-0.1.2/alembic → factorysemantics_mes-0.2.0/src/fsmes/migrations}/versions/b2c3d4e5f6a7_outbox_hardening.py +0 -0
  461. {factorysemantics_mes-0.1.2/alembic → factorysemantics_mes-0.2.0/src/fsmes/migrations}/versions/b3f8d2a41c67_controlled_documents.py +0 -0
  462. {factorysemantics_mes-0.1.2/alembic → factorysemantics_mes-0.2.0/src/fsmes/migrations}/versions/b7d2e9f4a1c3_unit_inspections.py +0 -0
  463. {factorysemantics_mes-0.1.2/alembic → factorysemantics_mes-0.2.0/src/fsmes/migrations}/versions/b8f4d27e1a53_serialisation.py +0 -0
  464. {factorysemantics_mes-0.1.2/alembic → factorysemantics_mes-0.2.0/src/fsmes/migrations}/versions/c2e9b74a3f81_gauges_and_calibration.py +0 -0
  465. {factorysemantics_mes-0.1.2/alembic → factorysemantics_mes-0.2.0/src/fsmes/migrations}/versions/c3d4e5f6a7b8_triggers.py +0 -0
  466. {factorysemantics_mes-0.1.2/alembic → factorysemantics_mes-0.2.0/src/fsmes/migrations}/versions/c4e8f1a2d5b6_serial_units_one_index.py +0 -0
  467. {factorysemantics_mes-0.1.2/alembic → factorysemantics_mes-0.2.0/src/fsmes/migrations}/versions/c9e2a4b71d38_material_at_a_station.py +0 -0
  468. {factorysemantics_mes-0.1.2/alembic → factorysemantics_mes-0.2.0/src/fsmes/migrations}/versions/d4a1c7e5b902_equipment_cost_center.py +0 -0
  469. {factorysemantics_mes-0.1.2/alembic → factorysemantics_mes-0.2.0/src/fsmes/migrations}/versions/d4a7f10c8b52_component_may_enter_twice.py +0 -0
  470. {factorysemantics_mes-0.1.2/alembic → factorysemantics_mes-0.2.0/src/fsmes/migrations}/versions/d4e5f6a7b8c9_recommended_adjustments.py +0 -0
  471. {factorysemantics_mes-0.1.2/alembic → factorysemantics_mes-0.2.0/src/fsmes/migrations}/versions/e5f6a7b8c9d0_tag_values_latest_index.py +0 -0
  472. {factorysemantics_mes-0.1.2/alembic → factorysemantics_mes-0.2.0/src/fsmes/migrations}/versions/e6b3c92d4f17_drop_the_old_bom_constraint.py +0 -0
  473. {factorysemantics_mes-0.1.2/alembic → factorysemantics_mes-0.2.0/src/fsmes/migrations}/versions/e7b3c9d18a45_workorder_work_center.py +0 -0
  474. {factorysemantics_mes-0.1.2/alembic → factorysemantics_mes-0.2.0/src/fsmes/migrations}/versions/f0a1b2c3d4e5_equipment_states_ended_index.py +0 -0
  475. {factorysemantics_mes-0.1.2/alembic → factorysemantics_mes-0.2.0/src/fsmes/migrations}/versions/f2a8d31c6b74_routing_durations.py +0 -0
  476. {factorysemantics_mes-0.1.2/alembic → factorysemantics_mes-0.2.0/src/fsmes/migrations}/versions/f7d1a58e2c94_preventive_maintenance.py +0 -0
  477. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/py.typed +0 -0
  478. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/seed.py +0 -0
  479. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/seed_kepsim.py +0 -0
  480. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/seed_line.py +0 -0
  481. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/services/__init__.py +0 -0
  482. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/services/adjustments.py +0 -0
  483. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/services/ai_status.py +0 -0
  484. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/services/assistant.py +0 -0
  485. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/services/audit.py +0 -0
  486. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/services/auth.py +0 -0
  487. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/services/capabilities.py +0 -0
  488. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/services/design_triage.py +0 -0
  489. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/services/documents.py +0 -0
  490. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/services/drafting.py +0 -0
  491. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/services/line.py +0 -0
  492. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/services/masterdata.py +0 -0
  493. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/services/quality.py +0 -0
  494. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/services/retention.py +0 -0
  495. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/services/scheduling.py +0 -0
  496. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/services/serialization.py +0 -0
  497. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/services/spc.py +0 -0
  498. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/services/staging.py +0 -0
  499. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/services/tags.py +0 -0
  500. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/services/triggers.py +0 -0
  501. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/services/walkthroughs.py +0 -0
  502. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/sim/__init__.py +0 -0
  503. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/sim/generate.py +0 -0
  504. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/sim/operations.py +0 -0
  505. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/sim/rollup.py +0 -0
  506. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/sim/score.py +0 -0
  507. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/sim/store.py +0 -0
  508. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/sim/sweep.py +0 -0
  509. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/sim/triage.py +0 -0
  510. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/sim/truth.py +0 -0
  511. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/adjustments.html +0 -0
  512. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/adjustments.js +0 -0
  513. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/admin.css +0 -0
  514. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/admin.html +0 -0
  515. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/admin.js +0 -0
  516. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/analysis.css +0 -0
  517. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/analysis.html +0 -0
  518. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/assist-record.js +0 -0
  519. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/assist.css +0 -0
  520. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/assist.js +0 -0
  521. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/coa.css +0 -0
  522. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/coa.html +0 -0
  523. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/coa.js +0 -0
  524. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/demo/kepsim-hour.json +0 -0
  525. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/design.css +0 -0
  526. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/design.js +0 -0
  527. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/gauges.html +0 -0
  528. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/gauges.js +0 -0
  529. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/index.html +0 -0
  530. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/instructions.css +0 -0
  531. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/instructions.html +0 -0
  532. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/line/app.js +0 -0
  533. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/line/feed.js +0 -0
  534. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/line/flow.js +0 -0
  535. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/line/parts.js +0 -0
  536. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/line/robot.js +0 -0
  537. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/line/scene.js +0 -0
  538. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/line-page.js +0 -0
  539. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/line.css +0 -0
  540. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/line.html +0 -0
  541. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/line3d.html +0 -0
  542. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/machine.css +0 -0
  543. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/machines.html +0 -0
  544. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/machines.js +0 -0
  545. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/maintenance.html +0 -0
  546. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/maintenance.js +0 -0
  547. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/masterdata.html +0 -0
  548. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/masterdata.js +0 -0
  549. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/ops.css +0 -0
  550. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/ops.html +0 -0
  551. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/ops.js +0 -0
  552. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/orders.css +0 -0
  553. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/orders.html +0 -0
  554. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/quality.css +0 -0
  555. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/quality.html +0 -0
  556. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/schedule.html +0 -0
  557. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/schedule.js +0 -0
  558. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/spc.html +0 -0
  559. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/spc.js +0 -0
  560. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/station.css +0 -0
  561. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/station.html +0 -0
  562. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/station.js +0 -0
  563. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/tags.html +0 -0
  564. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/tags.js +0 -0
  565. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/themes.css +0 -0
  566. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/themes.js +0 -0
  567. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/trace.html +0 -0
  568. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/trace.js +0 -0
  569. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/triggers.html +0 -0
  570. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/triggers.js +0 -0
  571. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/vendor/OrbitControls.js +0 -0
  572. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/vendor/README.md +0 -0
  573. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/vendor/three.core.min.js +0 -0
  574. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/vendor/three.module.min.js +0 -0
  575. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/tests/test_adjustments.py +0 -0
  576. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/tests/test_agent.py +0 -0
  577. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/tests/test_agent_batching.py +0 -0
  578. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/tests/test_agent_eval.py +0 -0
  579. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/tests/test_ai_status.py +0 -0
  580. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/tests/test_analysis.py +0 -0
  581. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/tests/test_assistant.py +0 -0
  582. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/tests/test_capabilities.py +0 -0
  583. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/tests/test_coa.py +0 -0
  584. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/tests/test_core_oplock.py +0 -0
  585. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/tests/test_cutlery.py +0 -0
  586. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/tests/test_design.py +0 -0
  587. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/tests/test_design_triage.py +0 -0
  588. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/tests/test_documents.py +0 -0
  589. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/tests/test_equipment_oee.py +0 -0
  590. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/tests/test_erp_roundtrip.py +0 -0
  591. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/tests/test_hierarchy.py +0 -0
  592. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/tests/test_hold.py +0 -0
  593. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/tests/test_kepsim.py +0 -0
  594. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/tests/test_kernel_common.py +0 -0
  595. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/tests/test_line_api.py +0 -0
  596. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/tests/test_line_scoping.py +0 -0
  597. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/tests/test_maintenance.py +0 -0
  598. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/tests/test_mcp_parity.py +0 -0
  599. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/tests/test_mcp_product.py +0 -0
  600. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/tests/test_megafactory.py +0 -0
  601. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/tests/test_onboarding.py +0 -0
  602. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/tests/test_packaged_config.py +0 -0
  603. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/tests/test_paging.py +0 -0
  604. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/tests/test_plant_scale_ui.py +0 -0
  605. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/tests/test_plant_serve_only.py +0 -0
  606. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/tests/test_quality.py +0 -0
  607. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/tests/test_rollup.py +0 -0
  608. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/tests/test_routing_depth.py +0 -0
  609. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/tests/test_scale.py +0 -0
  610. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/tests/test_scheduling_trace.py +0 -0
  611. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/tests/test_serial_scale.py +0 -0
  612. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/tests/test_spc_gauges.py +0 -0
  613. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/tests/test_store.py +0 -0
  614. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/tests/test_tag_fabric.py +0 -0
  615. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/tests/test_tag_fabric_review.py +0 -0
  616. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/tests/test_tags.py +0 -0
  617. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/tests/test_themes.py +0 -0
  618. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/tests/test_triage.py +0 -0
  619. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/tests/test_triggers.py +0 -0
  620. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/tests/test_ui_check.py +0 -0
  621. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/tests/test_walkthroughs.py +0 -0
  622. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/tests/test_washer_story.py +0 -0
  623. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/tests/test_web.py +0 -0
  624. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/tests/test_wip.py +0 -0
  625. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/tests/test_workorders.py +0 -0
  626. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/tests/ui/baselines/control-room.json +0 -0
  627. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/tests/ui/baselines/daylight.json +0 -0
  628. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/tests/ui/baselines/high-contrast.json +0 -0
  629. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/tests/ui/baselines/night-shift.json +0 -0
  630. {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/uv.lock +0 -0
@@ -7,6 +7,32 @@ MES_DATABASE_URL=sqlite:///fsmes.db
7
7
  # PostgreSQL (scale deployment, matches docker-compose):
8
8
  # MES_DATABASE_URL=postgresql+psycopg://mes:mes@localhost:5432/mes_twin
9
9
 
10
+ # --- Which plant is this --------------------------------------------------
11
+ # The shape of this deployment: laptop | plant | fleet. `laptop` is the
12
+ # evaluation profile - `fsmes demo` and the labs - and needs nothing else set
13
+ # here. Anything else refuses to start without a plant name.
14
+ MES_PLANT_PROFILE=laptop
15
+ # What this plant is called. It appears on every screen, in /health, on every
16
+ # metric, in every backup and on every namespace event, so a person looking
17
+ # at two plants can tell which one they are looking at. Letters, digits and
18
+ # _ . : @ = - only: it is published as one segment of the namespace topic.
19
+ # MES_PLANT_NAME=northgate
20
+ # The zone this plant works in, as an IANA name. It decides where a shift
21
+ # starts, when a gauge falls due, and what time every screen shows. Left out,
22
+ # the MES uses this machine's own zone and says "defaulted" wherever it
23
+ # reports it. On Windows the zone database comes from `pip install tzdata`.
24
+ # MES_PLANT_TIMEZONE=America/Chicago
25
+
26
+ # --- Shadow mode ----------------------------------------------------------
27
+ # The MES watches a real plant and can change nothing in it: no PLC
28
+ # write-back, no live ERP, no MQTT publish, nothing about this plant off the
29
+ # box. This is how you run it beside the MES already in charge on a line.
30
+ # Read once at start-up; leaving it is a restart, recorded in the audit
31
+ # trail. With it on, MES_ERP_MODE may only be off or file and MES_UNS_MODE
32
+ # only off or log - anything else refuses to start and says which variable.
33
+ # See docs/operate/shadow-mode.md.
34
+ MES_SHADOW=false
35
+
10
36
  # --- Logging --------------------------------------------------------------
11
37
  MES_LOG_LEVEL=INFO
12
38
  MES_LOG_DIR=logs
@@ -59,7 +85,9 @@ MES_ERPNEXT_PASSWORD=admin # the Frappe dev-bench default; a real site uses th
59
85
  # Preferred for a long-running worker (ERPNext: User -> API Access -> generate):
60
86
  # MES_ERPNEXT_API_KEY=
61
87
  # MES_ERPNEXT_API_SECRET=
62
- MES_ERPNEXT_COMPANY=ACME Beverages
88
+ # Which company's work orders to import. Empty (the default) imports every
89
+ # company's; a bench serving more than one company must set this.
90
+ # MES_ERPNEXT_COMPANY=Your Company
63
91
  # Post finished quantities as real Manufacture stock entries. Off records what
64
92
  # the MES counted without moving ERPNext's stock.
65
93
  MES_ERPNEXT_POST_STOCK_ENTRY=true
@@ -0,0 +1,64 @@
1
+ #!/usr/bin/env bash
2
+ # Prove a built wheel runs the demo, with nothing but the wheel to run it from.
3
+ #
4
+ # 0.1.0 installed cleanly from PyPI and did not work: the wheel carried no
5
+ # config/tag_map.json, so the simulator had no line, nothing was ever booked,
6
+ # and `fsmes demo` exited 0 regardless. The Release Checklist's clean-machine
7
+ # install was the line that would have caught it, and it was skipped for
8
+ # speed. This is that line, automated, so speed cannot skip it.
9
+ #
10
+ # Usage: demo_from_wheel.sh <wheel> [duration-seconds]
11
+ set -euo pipefail
12
+
13
+ wheel_arg="${1:?usage: demo_from_wheel.sh <wheel> [duration-seconds]}"
14
+ wheel="$(cd "$(dirname "$wheel_arg")" && pwd)/$(basename "$wheel_arg")"
15
+ # The demo stops watching after this many seconds; it exits as soon as the
16
+ # order completes, so a generous number costs nothing when the wheel is good.
17
+ duration="${2:-300}"
18
+
19
+ # An empty directory containing none of the repository's files. That is the
20
+ # whole point: no config/, no .env, no fsmes.db, no src/ to import instead of
21
+ # the installed package.
22
+ work="$(mktemp -d)"
23
+ trap 'rm -rf "$work"' EXIT
24
+ cd "$work"
25
+
26
+ python -m venv .venv
27
+ .venv/bin/python -m pip install --quiet --upgrade pip
28
+ .venv/bin/python -m pip install --quiet "$wheel"
29
+ # What the wheel says it is, asked two ways: the distribution metadata pip
30
+ # installed, and the answer a user gets from the command line. These were a
31
+ # version apart in 0.1.2 — the metadata said 0.1.2, `fsmes --version` said
32
+ # 0.1.0 — because the number was written down twice. It is written down once
33
+ # now (src/fsmes/__init__.py, which hatchling stamps the metadata from), and
34
+ # this is the line that keeps it that way: a wheel whose two answers disagree
35
+ # never reaches PyPI.
36
+ echo "wheel: $(basename "$wheel")"
37
+ metadata_version="$(.venv/bin/python -c "from importlib.metadata import version; print(version('factorysemantics-mes'))")"
38
+ reported_version="$(.venv/bin/fsmes --version)"
39
+ echo "installed: ${metadata_version}"
40
+ echo "fsmes --version: ${reported_version}"
41
+ if [ "$reported_version" != "fsmes ${metadata_version}" ]; then
42
+ echo "::error::the wheel's metadata says ${metadata_version} but 'fsmes --version' says '${reported_version}'"
43
+ exit 1
44
+ fi
45
+
46
+ set +e
47
+ timeout 900 .venv/bin/fsmes demo --duration "$duration" 2>&1 | tee demo.log
48
+ exit_code="${PIPESTATUS[0]}"
49
+ set -e
50
+
51
+ # Two separate questions, and both have to be asked. The exit code only became
52
+ # meaningful when the demo learned to fail; an older wheel exits 0 while
53
+ # booking nothing, and only the output tells you which one you have.
54
+ if [ "$exit_code" -ne 0 ]; then
55
+ echo "::error::fsmes demo exited ${exit_code} from the built wheel"
56
+ exit 1
57
+ fi
58
+
59
+ if ! grep -q "Demo result: full loop closed" demo.log; then
60
+ echo "::error::the wheel installed but the demo never closed its loop"
61
+ exit 1
62
+ fi
63
+
64
+ echo "The wheel ran the demo to a closed loop."
@@ -0,0 +1,95 @@
1
+ #!/usr/bin/env bash
2
+ # Prove the upgrade a plant will actually perform: a database made by the
3
+ # release that is on PyPI now, moved to the current schema by the built wheel.
4
+ #
5
+ # 0.1.2 shipped no migration scripts inside the wheel, so `fsmes init-db`
6
+ # outside a source checkout created any missing tables with create_all, ran no
7
+ # ALTER at all, and printed "Database schema is up to date" either way. A plant
8
+ # that installed from PyPI and upgraded would have run new code against an old
9
+ # schema and been told everything was fine. That is an honesty bug caused by
10
+ # packaging, and packaging bugs are invisible to every test that runs in a
11
+ # checkout — so this runs on the bytes that ship.
12
+ #
13
+ # Usage: upgrade_from_previous_release.sh <wheel>
14
+ set -euo pipefail
15
+
16
+ wheel_arg="${1:?usage: upgrade_from_previous_release.sh <wheel>}"
17
+ wheel="$(cd "$(dirname "$wheel_arg")" && pwd)/$(basename "$wheel_arg")"
18
+
19
+ # An empty directory: no config/, no alembic.ini, no src/ to import instead of
20
+ # the installed package. The same nothing a plant PC has.
21
+ work="$(mktemp -d)"
22
+ trap 'rm -rf "$work"' EXIT
23
+ cd "$work"
24
+
25
+ # Counts every row in the database, so the upgrade can be shown not to have
26
+ # lost any. A plant's history is the thing a migration must never trade away.
27
+ cat > rows.py <<'PY'
28
+ import sqlite3
29
+
30
+ conn = sqlite3.connect("fsmes.db")
31
+ tables = [row[0] for row in conn.execute(
32
+ "SELECT name FROM sqlite_master WHERE type='table' "
33
+ "AND name NOT LIKE 'sqlite_%' AND name != 'alembic_version'")]
34
+ print(sum(conn.execute(f'SELECT count(*) FROM "{table}"').fetchone()[0] for table in tables))
35
+ PY
36
+
37
+ # The release a plant is upgrading *from*: whatever PyPI serves today. Named
38
+ # rather than pinned, so this keeps testing the real starting point as
39
+ # releases go by instead of testing 0.1.2 forever.
40
+ python -m venv .venv-previous
41
+ .venv-previous/bin/python -m pip install --quiet --upgrade pip
42
+ .venv-previous/bin/python -m pip install --quiet factorysemantics-mes
43
+ previous="$(.venv-previous/bin/python -c "from importlib.metadata import version; print(version('factorysemantics-mes'))")"
44
+ echo "previous release, from PyPI: ${previous}"
45
+
46
+ # A database, made the way that release makes one, with rows in it.
47
+ .venv-previous/bin/fsmes init-db
48
+ .venv-previous/bin/fsmes seed
49
+ before_rows="$(python rows.py)"
50
+ echo "rows in the ${previous} database: ${before_rows}"
51
+ if [ "$before_rows" -lt 1 ]; then
52
+ echo "::error::the ${previous} wheel produced an empty database, so this would prove nothing"
53
+ exit 1
54
+ fi
55
+
56
+ # The wheel under test, in its own environment, pointed at that same database.
57
+ python -m venv .venv-built
58
+ .venv-built/bin/python -m pip install --quiet --upgrade pip
59
+ .venv-built/bin/python -m pip install --quiet "$wheel"
60
+ built="$(.venv-built/bin/python -c "from importlib.metadata import version; print(version('factorysemantics-mes'))")"
61
+ echo "built wheel: ${built}"
62
+
63
+ .venv-built/bin/fsmes init-db 2>&1 | tee upgrade.log
64
+
65
+ # `db-status` exits non-zero unless the stamp equals the head the wheel ships.
66
+ # That is the promise being made to the plant, asked of the database itself.
67
+ if ! .venv-built/bin/fsmes db-status; then
68
+ echo "::error::a ${previous} database upgraded with the built wheel is not at head"
69
+ exit 1
70
+ fi
71
+
72
+ after_rows="$(python rows.py)"
73
+ echo "rows after the upgrade: ${after_rows}"
74
+ if [ "$after_rows" -lt "$before_rows" ]; then
75
+ echo "::error::the upgrade lost rows: ${before_rows} before, ${after_rows} after"
76
+ exit 1
77
+ fi
78
+
79
+ # And the software still works on the database it just moved: the demo, run
80
+ # against the upgraded file rather than a fresh one. That is the difference
81
+ # between "the migrations ran" and "the plant can carry on".
82
+ set +e
83
+ timeout 900 .venv-built/bin/fsmes demo --duration 300 2>&1 | tee demo.log
84
+ exit_code="${PIPESTATUS[0]}"
85
+ set -e
86
+ if [ "$exit_code" -ne 0 ]; then
87
+ echo "::error::fsmes demo exited ${exit_code} on a database upgraded from ${previous}"
88
+ exit 1
89
+ fi
90
+ if ! grep -q "Demo result: full loop closed" demo.log; then
91
+ echo "::error::the upgraded database ran the demo, but the loop never closed"
92
+ exit 1
93
+ fi
94
+
95
+ echo "A ${previous} database upgraded to head with the built wheel, kept its ${after_rows} rows, and ran the demo."
@@ -0,0 +1,179 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ workflow_call:
8
+
9
+ permissions:
10
+ contents: read
11
+
12
+ jobs:
13
+ test:
14
+ runs-on: ${{ matrix.os }}
15
+ strategy:
16
+ fail-fast: false
17
+ matrix:
18
+ # Windows is a first-class target, not an afterthought: this MES is
19
+ # expected to run on plant PCs, and the single-writer lock exists in
20
+ # its O_EXCL form precisely because there is no fcntl there.
21
+ os: [ubuntu-latest, windows-latest]
22
+ python-version: ["3.12", "3.13"]
23
+
24
+ steps:
25
+ - uses: actions/checkout@v4
26
+
27
+ - uses: actions/setup-python@v5
28
+ with:
29
+ python-version: ${{ matrix.python-version }}
30
+
31
+ - name: Install
32
+ run: python -m pip install --upgrade pip && python -m pip install -e ".[dev,mcp,agent]"
33
+
34
+ - name: Lint
35
+ run: python -m ruff check .
36
+
37
+ - name: Test
38
+ run: python -m pytest
39
+
40
+ postgres:
41
+ # The suite against a real PostgreSQL, because a plant runs one.
42
+ #
43
+ # Everything else here runs on in-memory SQLite. SQLite is forgiving in
44
+ # ways PostgreSQL is not — LIKE ignores case, GROUP BY tolerates a bare
45
+ # column, a failed statement does not poison the transaction — so a bug
46
+ # that only shows on PostgreSQL is invisible to the rest of this file.
47
+ # This cell is where it shows: on a runner, not on a plant PC.
48
+ #
49
+ # One cell, Ubuntu, one Python. What this catches is a dialect
50
+ # difference, not a platform or interpreter difference, so multiplying
51
+ # the matrix would buy nothing and cost four times the minutes.
52
+ runs-on: ubuntu-latest
53
+ timeout-minutes: 30
54
+
55
+ services:
56
+ postgres:
57
+ # Pinned by digest, not by tag: `postgres:16` is a moving target and
58
+ # a green run has to mean the same bytes passed. This is 16.15.
59
+ # Moving the pin is a pull request, which is when it gets re-proven.
60
+ image: postgres@sha256:f1c3376c26f2609ab9f29f71f824103fe2fcd8ee0346485cb6122a4f93df6f94
61
+ env:
62
+ POSTGRES_USER: fsmes
63
+ POSTGRES_PASSWORD: fsmes
64
+ POSTGRES_DB: fsmes
65
+ ports:
66
+ - 5432:5432
67
+ options: >-
68
+ --health-cmd "pg_isready -U fsmes -d fsmes"
69
+ --health-interval 5s
70
+ --health-timeout 5s
71
+ --health-retries 20
72
+
73
+ env:
74
+ # The suite's database. Not MES_DATABASE_URL — see tests/conftest.py for
75
+ # why the two are kept apart.
76
+ MES_TEST_DATABASE_URL: postgresql+psycopg://fsmes:fsmes@127.0.0.1:5432/fsmes
77
+ # Alembic reads the deployment setting, so the migration step below
78
+ # points that at the same server.
79
+ MES_DATABASE_URL: postgresql+psycopg://fsmes:fsmes@127.0.0.1:5432/fsmes
80
+
81
+ steps:
82
+ - uses: actions/checkout@v4
83
+
84
+ - uses: actions/setup-python@v5
85
+ with:
86
+ python-version: "3.12"
87
+
88
+ # The same extras as `test`, plus the PostgreSQL driver.
89
+ - name: Install
90
+ run: python -m pip install --upgrade pip && python -m pip install -e ".[dev,mcp,agent,postgres]"
91
+
92
+ # First, while the database is still empty: the migrations. A chain
93
+ # that has only ever run on SQLite is the likeliest thing here to be
94
+ # quietly wrong, and `alembic upgrade head` from nothing is the only
95
+ # way a plant ever gets its schema. One head, checked here as well as
96
+ # in the suite, because a second head fails this step in a way that is
97
+ # hard to read otherwise.
98
+ - name: alembic upgrade head, from empty, on PostgreSQL
99
+ run: |
100
+ set -euo pipefail
101
+ heads=$(python -m alembic heads | grep -c . || true)
102
+ if [ "$heads" != "1" ]; then
103
+ echo "expected exactly one migration head, found $heads:"
104
+ python -m alembic heads --verbose
105
+ exit 1
106
+ fi
107
+ started=$(date +%s)
108
+ python -m alembic upgrade head
109
+ echo "PG_ALEMBIC_SECONDS=$(( $(date +%s) - started ))" >> "$GITHUB_ENV"
110
+ python -m alembic current
111
+ # And the path a plant actually uses: the migrations resolved from
112
+ # the package rather than from this directory. `db-status` exits
113
+ # non-zero unless the database is at the head the package ships, so
114
+ # the two ways of asking have to agree, on PostgreSQL as well.
115
+ fsmes db-status
116
+
117
+ # The suite drops the migrated schema and builds its own from the
118
+ # model, which is the same thing every other cell does. Running it
119
+ # second means the step above genuinely started from empty.
120
+ - name: Test
121
+ run: |
122
+ set -euo pipefail
123
+ started=$(date +%s)
124
+ python -m pytest
125
+ echo "PG_TEST_SECONDS=$(( $(date +%s) - started ))" >> "$GITHUB_ENV"
126
+
127
+ - name: What this run cost
128
+ if: always()
129
+ run: |
130
+ {
131
+ echo "| Step | Seconds |"
132
+ echo "|---|---|"
133
+ echo "| alembic upgrade head | ${PG_ALEMBIC_SECONDS:-—} |"
134
+ echo "| Suite on PostgreSQL 16.15 | ${PG_TEST_SECONDS:-—} |"
135
+ } >> "$GITHUB_STEP_SUMMARY"
136
+
137
+ wheel-demo:
138
+ # The check that would have caught 0.1.0. `test` above proves the source
139
+ # works; this proves the *artifact* works — installed into a fresh venv in
140
+ # an empty directory, which is all a stranger with pipx ever has. One cell
141
+ # on Ubuntu and one Python is enough: what this catches is missing package
142
+ # data, not a platform difference.
143
+ runs-on: ubuntu-latest
144
+ steps:
145
+ - uses: actions/checkout@v4
146
+ - uses: actions/setup-python@v5
147
+ with:
148
+ python-version: "3.12"
149
+ - run: python -m pip install --upgrade pip build
150
+ - run: python -m build --wheel
151
+ - name: The wheel runs the demo from an empty directory
152
+ run: .github/scripts/demo_from_wheel.sh "$(ls dist/*.whl)"
153
+
154
+ # And the other thing a plant does with a wheel: upgrade the database it
155
+ # already has. Until 2026-09-10 the wheel carried no migration scripts,
156
+ # so `fsmes init-db` outside a checkout ran no ALTER and said the schema
157
+ # was up to date - which would have put a plant on new code and an old
158
+ # schema, quietly. This installs the release that is on PyPI now, makes
159
+ # a database with it, upgrades that database with the wheel under test,
160
+ # and asks the database whether it is at head.
161
+ - name: The wheel upgrades a database made by the previous release
162
+ run: .github/scripts/upgrade_from_previous_release.sh "$(ls dist/*.whl)"
163
+
164
+ audit:
165
+ # Known-vulnerable pins. Advisory until the first public release has
166
+ # shaken it out; then it becomes required.
167
+ runs-on: ubuntu-latest
168
+ continue-on-error: true
169
+ steps:
170
+ - uses: actions/checkout@v4
171
+ - uses: actions/setup-python@v5
172
+ with:
173
+ python-version: "3.13"
174
+ # Editable install and --skip-editable, without --strict: the package
175
+ # under test is not on PyPI at the version being built (or at all,
176
+ # before the first release), and pip-audit must not count that as a
177
+ # finding. Vulnerabilities in the dependencies still fail the job.
178
+ - run: python -m pip install --upgrade pip pip-audit && python -m pip install -e ".[mcp,agent,postgres]"
179
+ - run: python -m pip_audit --skip-editable
@@ -0,0 +1,165 @@
1
+ # The ERPNext round trip, against a real ERPNext.
2
+ #
3
+ # Its own workflow, not a fifth cell in CI's matrix, for two reasons. It is
4
+ # slow — most of the wall clock is ERPNext installing itself into a fresh
5
+ # site — and red here means something different: not "this change is wrong"
6
+ # but "the MES and ERPNext no longer agree". Those deserve separate names in
7
+ # the checks list.
8
+ #
9
+ # WHEN IT RUNS, AND WHY NOT ALWAYS. On pull requests that touch the ERPNext
10
+ # connector, its tests, its lab fixture or this file; on the same paths when
11
+ # they land on main; and on demand. Not on every pull request, because a job
12
+ # that adds this much to an unrelated typo fix is a job people learn to
13
+ # ignore. Not on a schedule either: every image is pinned to a digest, so a
14
+ # nightly run would test the identical bytes it tested last night and prove
15
+ # nothing. Changing the pin is what makes this worth running again, and that
16
+ # is a pull request touching labs/erpnext/.
17
+
18
+ name: ERPNext (live)
19
+
20
+ # The two path lists are the same list written twice: GitHub Actions does not
21
+ # support YAML anchors. Keep them together.
22
+ on:
23
+ pull_request:
24
+ paths:
25
+ - "src/fsmes/integrations/erp/**"
26
+ - "tests/test_erpnext*.py"
27
+ - "labs/erpnext/**"
28
+ - "docs/operate/erpnext.md"
29
+ - ".github/workflows/erpnext-live.yml"
30
+ push:
31
+ branches: [main]
32
+ paths:
33
+ - "src/fsmes/integrations/erp/**"
34
+ - "tests/test_erpnext*.py"
35
+ - "labs/erpnext/**"
36
+ - "docs/operate/erpnext.md"
37
+ - ".github/workflows/erpnext-live.yml"
38
+ workflow_dispatch:
39
+
40
+ permissions:
41
+ contents: read
42
+
43
+ concurrency:
44
+ group: erpnext-live-${{ github.ref }}
45
+ cancel-in-progress: true
46
+
47
+ jobs:
48
+ roundtrip:
49
+ runs-on: ubuntu-latest
50
+ # Generous, because a red job must be a real disagreement and not a
51
+ # runner having a slow morning. If it ever gets near this, the compose
52
+ # is the thing to fix, not the number.
53
+ timeout-minutes: 45
54
+
55
+ env:
56
+ COMPOSE: labs/erpnext/docker-compose.yml
57
+ # The whole connection, set the way docs/operate/erpnext.md tells an
58
+ # operator to set it. MES_ERP_MODE is part of that: the `fsmes erp`
59
+ # commands are the port's own `requirements`, `setup` and `check`, so
60
+ # the mode is what decides which connector they act on. Leave it unset
61
+ # and this job would prepare the file exchange instead.
62
+ MES_ERP_MODE: erpnext
63
+ MES_ERPNEXT_BASE_URL: http://127.0.0.1:8080
64
+ MES_ERPNEXT_SITE: mes.localhost
65
+ MES_ERPNEXT_USER: Administrator
66
+ MES_ERPNEXT_PASSWORD: admin
67
+
68
+ steps:
69
+ - uses: actions/checkout@v4
70
+
71
+ - uses: actions/setup-python@v5
72
+ with:
73
+ python-version: "3.12"
74
+
75
+ # The same extras as ci.yml. Fewer would be enough to run the ERPNext
76
+ # tests, but pytest collects the whole tree before it selects, and a
77
+ # module that cannot import is a collection error rather than a
78
+ # deselected test.
79
+ - name: Install
80
+ run: python -m pip install --upgrade pip && python -m pip install -e ".[dev,mcp,agent]"
81
+
82
+ # Timed on purpose: the cost of this job is an argument people will
83
+ # want to have, and it should be settled with the numbers in the log.
84
+ - name: Start ERPNext and install the site
85
+ run: |
86
+ set -euo pipefail
87
+ started=$(date +%s)
88
+ docker compose -f "$COMPOSE" up -d
89
+ echo "ERPNEXT_UP_SECONDS=$(( $(date +%s) - started ))" >> "$GITHUB_ENV"
90
+ docker compose -f "$COMPOSE" ps
91
+
92
+ - name: Wait for the site to answer on the Host header the MES sends
93
+ run: |
94
+ set -euo pipefail
95
+ started=$(date +%s)
96
+ for attempt in $(seq 1 60); do
97
+ code=$(curl -s -o /dev/null -w '%{http_code}' \
98
+ -H "Host: $MES_ERPNEXT_SITE" \
99
+ "$MES_ERPNEXT_BASE_URL/api/method/frappe.ping" || true)
100
+ if [ "$code" = "200" ]; then
101
+ echo "site answered on attempt $attempt of 60"
102
+ echo "ERPNEXT_READY_SECONDS=$(( $(date +%s) - started ))" >> "$GITHUB_ENV"
103
+ exit 0
104
+ fi
105
+ sleep 5
106
+ done
107
+ echo "the site never answered 200 (last status ${code:-none}) after 60 attempts"
108
+ exit 1
109
+
110
+ # The three commands the docs tell an operator to run, run against a
111
+ # real ERPNext. They are the ERP port's own methods, so this also
112
+ # proves the port answers for a connector that has real requirements.
113
+ # `check` exits non-zero when the connector would not work, so a wrong
114
+ # field type or a missing permission is a red job here rather than a
115
+ # lost number on someone's plant.
116
+ - name: fsmes erp requirements, setup, then check
117
+ run: |
118
+ set -euo pipefail
119
+ fsmes erp requirements
120
+ fsmes erp setup
121
+ fsmes erp check
122
+
123
+ # The same script a person would run against their own bench. It seeds
124
+ # the plant the round trip needs — company, items, routing, BOM, stock.
125
+ # If it breaks, the documented way in is broken, and that is worth a red
126
+ # job on its own.
127
+ - name: Seed the plant
128
+ run: |
129
+ set -euo pipefail
130
+ started=$(date +%s)
131
+ python labs/erpnext/seed_erpnext.py \
132
+ --url "$MES_ERPNEXT_BASE_URL" --site "$MES_ERPNEXT_SITE"
133
+ echo "ERPNEXT_SEED_SECONDS=$(( $(date +%s) - started ))" >> "$GITHUB_ENV"
134
+
135
+ - name: The round trip
136
+ run: |
137
+ set -euo pipefail
138
+ started=$(date +%s)
139
+ # -s so the missing-field probe's measurement is in the log of a
140
+ # passing run. It is the point of that test; captured output that
141
+ # only appears on failure would hide the evidence.
142
+ python -m pytest -m erpnext_live -v -s
143
+ echo "ERPNEXT_TEST_SECONDS=$(( $(date +%s) - started ))" >> "$GITHUB_ENV"
144
+
145
+ # Frappe puts the reason for a 417 in the worker log, not in the
146
+ # response. Without this a failure here is unreadable.
147
+ - name: ERPNext's own logs
148
+ if: failure()
149
+ run: docker compose -f "$COMPOSE" logs --tail=400
150
+
151
+ - name: What this run cost
152
+ if: always()
153
+ run: |
154
+ {
155
+ echo "| Step | Seconds |"
156
+ echo "|---|---|"
157
+ echo "| ERPNext up, site installed | ${ERPNEXT_UP_SECONDS:-—} |"
158
+ echo "| Site answering | ${ERPNEXT_READY_SECONDS:-—} |"
159
+ echo "| Seed | ${ERPNEXT_SEED_SECONDS:-—} |"
160
+ echo "| Round trip | ${ERPNEXT_TEST_SECONDS:-—} |"
161
+ } >> "$GITHUB_STEP_SUMMARY"
162
+
163
+ - name: Stop ERPNext
164
+ if: always()
165
+ run: docker compose -f "$COMPOSE" down -v
@@ -25,6 +25,17 @@ jobs:
25
25
  run: |
26
26
  v="${GITHUB_REF_NAME#v}"
27
27
  ls dist/ | grep -q "factorysemantics_mes-${v}-" || { echo "::error::tag $GITHUB_REF_NAME but wheel is $(ls dist/)"; exit 1; }
28
+ # The wheel's filename comes from src/fsmes/__init__.py now, so the step
29
+ # above already ties the tag to the number the CLI reports. CITATION.cff
30
+ # is the one version left that a human types: the citation file format
31
+ # has no way to read it from the package. It was a release behind when
32
+ # this check was written, and 0.1.2 is what a wrong number costs. A tag
33
+ # whose citation disagrees stops here, before anything is published.
34
+ - name: The tag and the citation file agree
35
+ run: |
36
+ v="${GITHUB_REF_NAME#v}"
37
+ cited="$(sed -n 's/^version: *//p' CITATION.cff)"
38
+ [ "$cited" = "$v" ] || { echo "::error::tag $GITHUB_REF_NAME but CITATION.cff says ${cited:-nothing}"; exit 1; }
28
39
  - name: The wheel carries the demo's config files
29
40
  run: |
30
41
  python - <<'PY'
@@ -39,9 +50,28 @@ jobs:
39
50
  name: dist
40
51
  path: dist/
41
52
 
42
- pypi:
53
+ wheel-demo:
54
+ # The `build` job checks the wheel's filename and that the config files
55
+ # are inside it. Both were true of a wheel that still did not run. This
56
+ # runs the demo from the exact artifact about to be published — not a
57
+ # rebuild of it — so a tag cannot publish a wheel that does not work.
43
58
  needs: build
44
59
  runs-on: ubuntu-latest
60
+ steps:
61
+ - uses: actions/checkout@v4
62
+ - uses: actions/setup-python@v5
63
+ with:
64
+ python-version: "3.12"
65
+ - uses: actions/download-artifact@v4
66
+ with:
67
+ name: dist
68
+ path: dist/
69
+ - name: The wheel that is about to be published runs the demo
70
+ run: .github/scripts/demo_from_wheel.sh "$(ls dist/*.whl)"
71
+
72
+ pypi:
73
+ needs: [build, wheel-demo]
74
+ runs-on: ubuntu-latest
45
75
  environment: pypi
46
76
  permissions:
47
77
  id-token: write
@@ -65,3 +65,6 @@ labs/cutlery/.data/
65
65
  docs/reference/
66
66
  docs/llms.txt
67
67
  site/
68
+
69
+ # A backup folder written by `fsmes backup`.
70
+ backups/