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.
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/.env.example +29 -1
- factorysemantics_mes-0.2.0/.github/scripts/demo_from_wheel.sh +64 -0
- factorysemantics_mes-0.2.0/.github/scripts/upgrade_from_previous_release.sh +95 -0
- factorysemantics_mes-0.2.0/.github/workflows/ci.yml +179 -0
- factorysemantics_mes-0.2.0/.github/workflows/erpnext-live.yml +165 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/.github/workflows/release.yml +31 -1
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/.gitignore +3 -0
- factorysemantics_mes-0.2.0/CHANGELOG.md +965 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/CITATION.cff +2 -1
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/CONTRIBUTING.md +9 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/PKG-INFO +5 -2
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/README.md +1 -1
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/ROADMAP.md +24 -12
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/alembic.ini +1 -1
- factorysemantics_mes-0.2.0/config/inbound_mapping.json +48 -0
- factorysemantics_mes-0.2.0/config/inbound_sql.json +25 -0
- factorysemantics_mes-0.2.0/deploy/README.md +95 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/deploy/fsmes-prod-plant@.service +1 -1
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/deploy/promote.sh +1 -1
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/docker/Dockerfile +1 -2
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/docker/docker-compose.yml +8 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/docs/ARCHITECTURE.md +5 -3
- factorysemantics_mes-0.2.0/docs/decisions/0009-organisation-not-personal-account.md +24 -0
- factorysemantics_mes-0.2.0/docs/decisions/0010-github-discussions-only.md +25 -0
- factorysemantics_mes-0.2.0/docs/decisions/0011-mkdocs-material-generated-reference.md +25 -0
- factorysemantics_mes-0.2.0/docs/decisions/0012-contributor-covenant-3.md +24 -0
- factorysemantics_mes-0.2.0/docs/decisions/0013-governance-is-one-page.md +24 -0
- factorysemantics_mes-0.2.0/docs/decisions/0014-first-public-version-is-0-1-0.md +24 -0
- factorysemantics_mes-0.2.0/docs/decisions/0015-mcp-registry-name.md +24 -0
- factorysemantics_mes-0.2.0/docs/decisions/0016-no-trademark-registration.md +24 -0
- factorysemantics_mes-0.2.0/docs/decisions/0017-one-public-demo-gated-and-bounded.md +25 -0
- factorysemantics_mes-0.2.0/docs/decisions/0018-public-on-2026-09-08-and-the-pre-tag-check.md +26 -0
- factorysemantics_mes-0.2.0/docs/decisions/0019-count-everything-the-machine-counted.md +75 -0
- factorysemantics_mes-0.2.0/docs/decisions/0020-what-supported-means-for-an-erp-connector.md +129 -0
- factorysemantics_mes-0.2.0/docs/decisions/0021-one-database-per-plant.md +101 -0
- factorysemantics_mes-0.2.0/docs/decisions/0022-what-a-plant-pack-may-contain.md +135 -0
- factorysemantics_mes-0.2.0/docs/decisions/0023-the-fleet-console-observes.md +347 -0
- factorysemantics_mes-0.2.0/docs/decisions/index.md +34 -0
- factorysemantics_mes-0.2.0/docs/design/m8-packs-and-fleet.md +625 -0
- factorysemantics_mes-0.2.0/docs/develop/erp-connectors.md +318 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/docs/develop/index.md +9 -1
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/docs/develop/your-first-module.md +13 -3
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/docs/hooks/generate.py +62 -2
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/docs/index.md +3 -2
- factorysemantics_mes-0.2.0/docs/operate/backup.md +202 -0
- factorysemantics_mes-0.2.0/docs/operate/compatibility.md +55 -0
- factorysemantics_mes-0.2.0/docs/operate/confirmation-examples/completion-with-a-lot.json +14 -0
- factorysemantics_mes-0.2.0/docs/operate/confirmation-examples/completion-with-a-lot.xml +16 -0
- factorysemantics_mes-0.2.0/docs/operate/confirmation-examples/completion-with-an-over-run.json +14 -0
- factorysemantics_mes-0.2.0/docs/operate/confirmation-examples/completion-with-an-over-run.xml +16 -0
- factorysemantics_mes-0.2.0/docs/operate/confirmation-examples/completion-without-a-lot.json +14 -0
- factorysemantics_mes-0.2.0/docs/operate/confirmation-examples/completion-without-a-lot.xml +15 -0
- factorysemantics_mes-0.2.0/docs/operate/confirmation-examples/operation-clean.json +22 -0
- factorysemantics_mes-0.2.0/docs/operate/confirmation-examples/operation-clean.xml +23 -0
- factorysemantics_mes-0.2.0/docs/operate/confirmation-examples/operation-over-run.json +22 -0
- factorysemantics_mes-0.2.0/docs/operate/confirmation-examples/operation-over-run.xml +23 -0
- factorysemantics_mes-0.2.0/docs/operate/confirmation-examples/operation-with-scrap-and-components.json +35 -0
- factorysemantics_mes-0.2.0/docs/operate/confirmation-examples/operation-with-scrap-and-components.xml +35 -0
- factorysemantics_mes-0.2.0/docs/operate/confirmation-files.md +131 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/docs/operate/deploy.md +4 -3
- factorysemantics_mes-0.2.0/docs/operate/erpnext.md +215 -0
- factorysemantics_mes-0.2.0/docs/operate/first-plant.md +395 -0
- factorysemantics_mes-0.2.0/docs/operate/first-week.md +113 -0
- factorysemantics_mes-0.2.0/docs/operate/fleet.md +155 -0
- factorysemantics_mes-0.2.0/docs/operate/inbound.md +588 -0
- factorysemantics_mes-0.2.0/docs/operate/index.md +33 -0
- factorysemantics_mes-0.2.0/docs/operate/modules.md +152 -0
- factorysemantics_mes-0.2.0/docs/operate/opc-readonly.md +243 -0
- factorysemantics_mes-0.2.0/docs/operate/packs.md +149 -0
- factorysemantics_mes-0.2.0/docs/operate/registry.md +68 -0
- factorysemantics_mes-0.2.0/docs/operate/shadow-mode.md +174 -0
- factorysemantics_mes-0.2.0/docs/operate/shadow-scorecard.md +189 -0
- factorysemantics_mes-0.2.0/docs/operate/tls.md +167 -0
- factorysemantics_mes-0.2.0/docs/operate/uns.md +284 -0
- factorysemantics_mes-0.2.0/docs/operate/upgrade.md +280 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/docs/plant/first-line.md +1 -1
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/docs/plant/index.md +1 -0
- factorysemantics_mes-0.2.0/docs/releases/0.2.0.md +136 -0
- factorysemantics_mes-0.2.0/docs/releases/index.md +17 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/labs/cutlery/README.md +15 -2
- factorysemantics_mes-0.2.0/labs/cutlery/fleet.toml +14 -0
- factorysemantics_mes-0.2.0/labs/cutlery/plant.toml +45 -0
- factorysemantics_mes-0.2.0/labs/erpnext/VERSIONS.md +34 -0
- factorysemantics_mes-0.2.0/labs/erpnext/docker-compose.yml +202 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/labs/erpnext/seed_erpnext.py +15 -47
- factorysemantics_mes-0.2.0/labs/megafactory/fleet.toml +13 -0
- factorysemantics_mes-0.2.0/labs/megafactory/full/plant.toml +43 -0
- factorysemantics_mes-0.2.0/labs/multiplant/README.md +133 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/labs/multiplant/bottling/init.py +12 -3
- factorysemantics_mes-0.2.0/labs/multiplant/bottling/plant.toml +39 -0
- factorysemantics_mes-0.2.0/labs/multiplant/bottling/tag_map.json +97 -0
- factorysemantics_mes-0.2.0/labs/multiplant/finewire/README.md +59 -0
- factorysemantics_mes-0.2.0/labs/multiplant/finewire/mappings/inbound_mapping.json +16 -0
- factorysemantics_mes-0.2.0/labs/multiplant/finewire/masterdata/equipment.json +10 -0
- factorysemantics_mes-0.2.0/labs/multiplant/finewire/masterdata/lots.json +3 -0
- factorysemantics_mes-0.2.0/labs/multiplant/finewire/masterdata/materials.json +4 -0
- factorysemantics_mes-0.2.0/labs/multiplant/finewire/masterdata/quality_specs.json +3 -0
- factorysemantics_mes-0.2.0/labs/multiplant/finewire/masterdata/routings.json +13 -0
- factorysemantics_mes-0.2.0/labs/multiplant/finewire/masterdata/work_orders.json +3 -0
- factorysemantics_mes-0.2.0/labs/multiplant/finewire/plant.toml +97 -0
- factorysemantics_mes-0.2.0/labs/multiplant/finewire/tag_map.json +62 -0
- factorysemantics_mes-0.2.0/labs/multiplant/fleet.toml +15 -0
- factorysemantics_mes-0.2.0/labs/multiplant/machining/masterdata/README.md +14 -0
- factorysemantics_mes-0.2.0/labs/multiplant/machining/masterdata/equipment.json +9 -0
- factorysemantics_mes-0.2.0/labs/multiplant/machining/masterdata/lots.json +3 -0
- factorysemantics_mes-0.2.0/labs/multiplant/machining/masterdata/materials.json +4 -0
- factorysemantics_mes-0.2.0/labs/multiplant/machining/masterdata/quality_specs.json +3 -0
- factorysemantics_mes-0.2.0/labs/multiplant/machining/masterdata/routings.json +12 -0
- factorysemantics_mes-0.2.0/labs/multiplant/machining/masterdata/work_orders.json +3 -0
- factorysemantics_mes-0.2.0/labs/multiplant/machining/plant.toml +34 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/mkdocs.yml +38 -1
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/pyproject.toml +38 -3
- factorysemantics_mes-0.2.0/src/fsmes/__init__.py +17 -0
- factorysemantics_mes-0.2.0/src/fsmes/api/app.py +237 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/api/routers/admin.py +1 -1
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/api/routers/assist.py +3 -1
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/api/routers/auth.py +15 -3
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/api/routers/execution.py +23 -1
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/api/routers/maintenance.py +1 -1
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/api/routers/masterdata.py +4 -4
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/api/routers/ops.py +1 -1
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/api/routers/quality.py +2 -2
- factorysemantics_mes-0.2.0/src/fsmes/api/routers/system.py +150 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/api/routers/workorders.py +4 -1
- factorysemantics_mes-0.2.0/src/fsmes/backup.py +365 -0
- factorysemantics_mes-0.2.0/src/fsmes/cli.py +2416 -0
- factorysemantics_mes-0.2.0/src/fsmes/config.py +411 -0
- factorysemantics_mes-0.2.0/src/fsmes/db.py +111 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/domain/__init__.py +6 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/domain/equipment.py +4 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/domain/execution.py +21 -2
- factorysemantics_mes-0.2.0/src/fsmes/domain/inbound.py +106 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/domain/integration.py +7 -1
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/domain/quality.py +6 -0
- factorysemantics_mes-0.2.0/src/fsmes/domain/uns.py +43 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/domain/workorders.py +12 -0
- factorysemantics_mes-0.2.0/src/fsmes/fleet/__init__.py +28 -0
- factorysemantics_mes-0.2.0/src/fsmes/fleet/commands.py +270 -0
- factorysemantics_mes-0.2.0/src/fsmes/fleet/console.py +215 -0
- factorysemantics_mes-0.2.0/src/fsmes/fleet/observe.py +98 -0
- factorysemantics_mes-0.2.0/src/fsmes/fleet/owned.py +465 -0
- factorysemantics_mes-0.2.0/src/fsmes/identity.py +286 -0
- factorysemantics_mes-0.2.0/src/fsmes/integrations/erp/b2mml.py +190 -0
- factorysemantics_mes-0.2.0/src/fsmes/integrations/erp/base.py +243 -0
- factorysemantics_mes-0.2.0/src/fsmes/integrations/erp/conformance.py +232 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/integrations/erp/contract.py +17 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/integrations/erp/erpnext_adapter.py +218 -31
- factorysemantics_mes-0.2.0/src/fsmes/integrations/erp/erpnext_setup.py +208 -0
- factorysemantics_mes-0.2.0/src/fsmes/integrations/erp/examples.py +263 -0
- factorysemantics_mes-0.2.0/src/fsmes/integrations/erp/file_adapter.py +228 -0
- factorysemantics_mes-0.2.0/src/fsmes/integrations/erp/incumbent.py +324 -0
- factorysemantics_mes-0.2.0/src/fsmes/integrations/erp/rest_adapter.py +97 -0
- factorysemantics_mes-0.2.0/src/fsmes/integrations/erp/schema.py +406 -0
- factorysemantics_mes-0.2.0/src/fsmes/integrations/erp/scorecard.py +620 -0
- factorysemantics_mes-0.2.0/src/fsmes/integrations/erp/scorecard_html.py +158 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/integrations/erp/sync.py +16 -5
- factorysemantics_mes-0.2.0/src/fsmes/integrations/erp/validate.py +357 -0
- factorysemantics_mes-0.2.0/src/fsmes/integrations/events.py +108 -0
- factorysemantics_mes-0.2.0/src/fsmes/integrations/inbound/__init__.py +13 -0
- factorysemantics_mes-0.2.0/src/fsmes/integrations/inbound/contract.py +232 -0
- factorysemantics_mes-0.2.0/src/fsmes/integrations/inbound/folder.py +462 -0
- factorysemantics_mes-0.2.0/src/fsmes/integrations/inbound/mqtt.py +620 -0
- factorysemantics_mes-0.2.0/src/fsmes/integrations/inbound/sql.py +673 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/integrations/opc/agent.py +59 -10
- factorysemantics_mes-0.2.0/src/fsmes/integrations/uns/__init__.py +7 -0
- factorysemantics_mes-0.2.0/src/fsmes/integrations/uns/envelope.py +60 -0
- factorysemantics_mes-0.2.0/src/fsmes/integrations/uns/publisher.py +169 -0
- factorysemantics_mes-0.2.0/src/fsmes/integrations/uns/topics.py +219 -0
- factorysemantics_mes-0.2.0/src/fsmes/integrations/uns/transport.py +193 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/mcp/adjustments.py +6 -1
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/mcp_server.py +98 -32
- {factorysemantics_mes-0.1.2/alembic → factorysemantics_mes-0.2.0/src/fsmes/migrations}/env.py +8 -1
- factorysemantics_mes-0.2.0/src/fsmes/migrations/versions/a3f6c81d09e2_unassigned_production.py +40 -0
- factorysemantics_mes-0.2.0/src/fsmes/migrations/versions/a4d9c2e70f18_uns_publications.py +47 -0
- factorysemantics_mes-0.2.0/src/fsmes/migrations/versions/b5c1d09e73af_inbound_events_and_their_source.py +61 -0
- factorysemantics_mes-0.2.0/src/fsmes/migrations/versions/c8b1e40d7a92_erp_messages_direction_index.py +34 -0
- factorysemantics_mes-0.2.0/src/fsmes/migrations/versions/d9a3f61c48e0_inbound_sql_watermarks.py +52 -0
- factorysemantics_mes-0.2.0/src/fsmes/modules.py +392 -0
- factorysemantics_mes-0.2.0/src/fsmes/pack/__init__.py +23 -0
- factorysemantics_mes-0.2.0/src/fsmes/pack/apply.py +354 -0
- factorysemantics_mes-0.2.0/src/fsmes/pack/check.py +506 -0
- factorysemantics_mes-0.2.0/src/fsmes/pack/fleet.py +124 -0
- factorysemantics_mes-0.2.0/src/fsmes/pack/format.py +395 -0
- factorysemantics_mes-0.2.0/src/fsmes/pack/masterdata.py +271 -0
- factorysemantics_mes-0.2.0/src/fsmes/pack/migrate.py +230 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/plant.py +106 -80
- factorysemantics_mes-0.2.0/src/fsmes/schema.py +226 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/services/agent.py +11 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/services/analysis.py +15 -3
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/services/calendar.py +42 -8
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/services/coa.py +1 -1
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/services/design.py +9 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/services/equipment.py +63 -1
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/services/erp.py +56 -13
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/services/execution.py +123 -9
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/services/gauges.py +6 -2
- factorysemantics_mes-0.2.0/src/fsmes/services/inbound.py +316 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/services/maintenance.py +2 -2
- factorysemantics_mes-0.2.0/src/fsmes/services/outbox.py +133 -0
- factorysemantics_mes-0.2.0/src/fsmes/services/uns.py +219 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/services/workorders.py +9 -1
- factorysemantics_mes-0.2.0/src/fsmes/shadow.py +575 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/sim/agent_eval.py +3 -1
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/sim/autoloop.py +27 -6
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/sim/mcp_server.py +3 -1
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/sim/runner.py +11 -3
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/sim/ui_check.py +15 -9
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/analysis.js +4 -1
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/app.js +2 -1
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/common.js +106 -10
- factorysemantics_mes-0.2.0/src/fsmes/web/fleet.css +61 -0
- factorysemantics_mes-0.2.0/src/fsmes/web/fleet.html +64 -0
- factorysemantics_mes-0.2.0/src/fsmes/web/fleet.js +132 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/instructions.js +2 -1
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/kit.js +6 -2
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/machine.html +10 -1
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/machine.js +36 -2
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/orders.js +3 -1
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/quality.js +4 -2
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/styles.css +41 -1
- factorysemantics_mes-0.2.0/tests/conftest.py +183 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/tests/test_api.py +7 -2
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/tests/test_auth.py +46 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/tests/test_autoloop.py +2 -2
- factorysemantics_mes-0.2.0/tests/test_backup.py +274 -0
- factorysemantics_mes-0.2.0/tests/test_cli.py +111 -0
- factorysemantics_mes-0.2.0/tests/test_core_purity.py +340 -0
- factorysemantics_mes-0.2.0/tests/test_demo_verdict.py +63 -0
- factorysemantics_mes-0.2.0/tests/test_environments.py +187 -0
- factorysemantics_mes-0.2.0/tests/test_erp_confirmation_files.py +275 -0
- factorysemantics_mes-0.2.0/tests/test_erp_conformance.py +272 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/tests/test_erp_contract.py +46 -0
- factorysemantics_mes-0.2.0/tests/test_erpnext.py +519 -0
- factorysemantics_mes-0.2.0/tests/test_erpnext_live.py +517 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/tests/test_execution.py +5 -1
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/tests/test_file_erp.py +2 -2
- factorysemantics_mes-0.2.0/tests/test_fleet_console.py +285 -0
- factorysemantics_mes-0.2.0/tests/test_fleet_ownership.py +427 -0
- factorysemantics_mes-0.2.0/tests/test_inbound.py +285 -0
- factorysemantics_mes-0.2.0/tests/test_inbound_folder.py +293 -0
- factorysemantics_mes-0.2.0/tests/test_inbound_mqtt.py +626 -0
- factorysemantics_mes-0.2.0/tests/test_inbound_sql.py +478 -0
- factorysemantics_mes-0.2.0/tests/test_migrations_have_one_head.py +27 -0
- factorysemantics_mes-0.2.0/tests/test_module_wall.py +309 -0
- factorysemantics_mes-0.2.0/tests/test_no_tenant_literals.py +288 -0
- factorysemantics_mes-0.2.0/tests/test_outbox_events.py +255 -0
- factorysemantics_mes-0.2.0/tests/test_overproduction.py +162 -0
- factorysemantics_mes-0.2.0/tests/test_pack_format.py +517 -0
- factorysemantics_mes-0.2.0/tests/test_pack_third.py +225 -0
- factorysemantics_mes-0.2.0/tests/test_plant_identity.py +271 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/tests/test_plant_migrate.py +22 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/tests/test_plant_scale_lists.py +9 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/tests/test_route_coverage.py +1 -1
- factorysemantics_mes-0.2.0/tests/test_schema_upgrade.py +173 -0
- factorysemantics_mes-0.2.0/tests/test_shadow_mode.py +442 -0
- factorysemantics_mes-0.2.0/tests/test_shadow_scorecard.py +334 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/tests/test_sim.py +6 -2
- factorysemantics_mes-0.2.0/tests/test_sqlite_write_locks.py +150 -0
- factorysemantics_mes-0.2.0/tests/test_the_suite_knows_its_database.py +25 -0
- factorysemantics_mes-0.2.0/tests/test_uns.py +816 -0
- factorysemantics_mes-0.1.2/.github/workflows/ci.yml +0 -55
- factorysemantics_mes-0.1.2/CHANGELOG.md +0 -76
- factorysemantics_mes-0.1.2/deploy/README.md +0 -68
- factorysemantics_mes-0.1.2/docs/decisions/index.md +0 -17
- factorysemantics_mes-0.1.2/docs/operate/compatibility.md +0 -20
- factorysemantics_mes-0.1.2/docs/operate/erpnext.md +0 -57
- factorysemantics_mes-0.1.2/docs/operate/index.md +0 -18
- factorysemantics_mes-0.1.2/docs/operate/registry.md +0 -59
- factorysemantics_mes-0.1.2/labs/cutlery/registry.toml +0 -29
- factorysemantics_mes-0.1.2/labs/megafactory/registry.toml +0 -36
- factorysemantics_mes-0.1.2/labs/multiplant/README.md +0 -88
- factorysemantics_mes-0.1.2/labs/multiplant/fsplant.ps1 +0 -196
- factorysemantics_mes-0.1.2/labs/multiplant/machining/seed.py +0 -156
- factorysemantics_mes-0.1.2/labs/multiplant/plants.toml +0 -30
- factorysemantics_mes-0.1.2/src/fsmes/__init__.py +0 -11
- factorysemantics_mes-0.1.2/src/fsmes/api/app.py +0 -344
- factorysemantics_mes-0.1.2/src/fsmes/api/routers/system.py +0 -75
- factorysemantics_mes-0.1.2/src/fsmes/cli.py +0 -1152
- factorysemantics_mes-0.1.2/src/fsmes/config.py +0 -133
- factorysemantics_mes-0.1.2/src/fsmes/db.py +0 -66
- factorysemantics_mes-0.1.2/src/fsmes/integrations/erp/b2mml.py +0 -97
- factorysemantics_mes-0.1.2/src/fsmes/integrations/erp/base.py +0 -51
- factorysemantics_mes-0.1.2/src/fsmes/integrations/erp/file_adapter.py +0 -56
- factorysemantics_mes-0.1.2/src/fsmes/integrations/erp/rest_adapter.py +0 -22
- factorysemantics_mes-0.1.2/tests/conftest.py +0 -107
- factorysemantics_mes-0.1.2/tests/test_cli.py +0 -27
- factorysemantics_mes-0.1.2/tests/test_environments.py +0 -124
- factorysemantics_mes-0.1.2/tests/test_erpnext.py +0 -253
- factorysemantics_mes-0.1.2/tests/test_migrations_have_one_head.py +0 -18
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/.github/CODEOWNERS +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/.github/ISSUE_TEMPLATE/bug.yml +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/.github/ISSUE_TEMPLATE/config.yml +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/.github/ISSUE_TEMPLATE/integration.yml +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/.github/ISSUE_TEMPLATE/plant-pack.yml +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/.github/dependabot.yml +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/.github/workflows/dco.yml +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/.github/workflows/docs.yml +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/.github/workflows/scorecard.yml +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/.github/workflows/welcome.yml +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/CODE_OF_CONDUCT.md +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/GOVERNANCE.md +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/LICENSE +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/MAINTAINERS.md +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/NOTICE +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/SECURITY.md +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/config/line_layout.json +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/config/tag_map.json +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/config/tag_map_kepsim.json +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/config/tag_map_kepware.json +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/deploy/fsmes-autoloop.service +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/deploy/fsmes-autoloop.timer +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/docker/nginx.conf +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/docs/LANDSCAPE.md +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/docs/agents/connect-mcp-client.md +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/docs/agents/evals.md +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/docs/agents/index.md +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/docs/agents/write-discipline.md +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/docs/ai/BUDGET.md +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/docs/ai/OBSERVABILITY.md +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/docs/decisions/0001-apache-2-with-dco.md +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/docs/decisions/0002-kernel-and-modules.md +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/docs/decisions/0003-one-mcp-server.md +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/docs/decisions/0004-never-invent-production.md +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/docs/decisions/0005-plain-html-no-build-step.md +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/docs/decisions/0006-sqlite-laptop-postgresql-plant.md +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/docs/decisions/0007-fresh-public-history.md +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/docs/decisions/0008-erp-connectors-are-modules.md +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/docs/decisions/TEMPLATE.md +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/docs/design/STYLE.md +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/docs/design/backlog/README.md +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/docs/design/backlog/analysis-cards-scaling.md +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/docs/design/backlog/book-output-explicit-order.md +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/docs/design/backlog/clickable-kpi-tiles.md +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/docs/design/backlog/opc-integration-suite.md +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/docs/design/backlog/order-lifecycle-actions.md +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/docs/design/backlog/orders-creatable-materials.md +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/docs/design/backlog/orders-supervisor-filters.md +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/docs/design/backlog/review-orders.md +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/docs/design/backlog/review-station.md +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/docs/design/backlog/scrap-reason-codes.md +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/docs/design/backlog/sixty-machine-plant.md +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/docs/design/backlog/spc-capability-withheld.md +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/docs/design/backlog/station-spc.md +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/docs/design/backlog/station-view.md +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/docs/design/backlog/supervisor-drill-down.md +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/docs/design/backlog/ui-style-drift-bc58fb4f8e4d.md +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/docs/history/private-era.md +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/docs/onboarding/GUIDE-ENGINEERING.md +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/docs/onboarding/GUIDE-IT.md +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/docs/onboarding/README.md +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/docs/onboarding/worksheet-example.csv +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/docs/onboarding/worksheet-template.csv +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/docs/operate/security.md +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/docs/plant/never-invent-production.md +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/docs/plant/reading-oee.md +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/labs/cutlery/analysis/build_notebook.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/labs/cutlery/analysis/build_report.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/labs/cutlery/analysis/cutlery_run_analysis.ipynb +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/labs/cutlery/analysis/viz.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/labs/cutlery/build_config.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/labs/cutlery/fill_day.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/labs/cutlery/init.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/labs/cutlery/line.json +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/labs/cutlery/make_tag_map.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/labs/cutlery/run_cutlery.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/labs/cutlery/tag_map.json +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/labs/cutlery/walkthroughs/install_walkthroughs.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/labs/cutlery/walkthroughs/walkthroughs.json +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/labs/kepsim/.env.example +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/labs/kepsim/README.md +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/labs/kepsim/kepware_setup.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/labs/kepsim/line.json +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/labs/kepsim/scenario.md +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/labs/kepsim/setup_dsn.ps1 +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/labs/kepsim/verify_readback.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/labs/megafactory/build_config.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/labs/megafactory/full/build_config.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/labs/megafactory/full/init.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/labs/megafactory/full/line.json +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/labs/megafactory/full/run_full.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/labs/megafactory/full/seed_breadth.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/labs/megafactory/full/surfaces.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/labs/megafactory/full/tag_map.json +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/labs/megafactory/init.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/labs/megafactory/line.json +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/labs/megafactory/make_tag_map.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/labs/megafactory/run_spike.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/labs/megafactory/seed_breadth.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/labs/megafactory/tag_map.json +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/labs/multiplant/machining/line.json +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/labs/multiplant/machining/tag_map.json +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/api/__init__.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/api/deps.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/api/idempotency.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/api/paging.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/api/routers/__init__.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/api/routers/adjustments.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/api/routers/analysis.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/api/routers/coa.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/api/routers/dashboard.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/api/routers/design.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/api/routers/documents.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/api/routers/equipment.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/api/routers/erp.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/api/routers/kpis.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/api/routers/line.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/api/routers/scheduling.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/api/routers/serialization.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/api/routers/triggers.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/core/__init__.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/core/oplock.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/demo_feed.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/domain/adjustments.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/domain/audit.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/domain/calendar.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/domain/common.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/domain/documents.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/domain/gauges.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/domain/idempotency.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/domain/maintenance.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/domain/masterdata.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/domain/scheduling.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/domain/serialization.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/domain/timeseries.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/domain/triggers.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/integrations/__init__.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/integrations/erp/__init__.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/integrations/erp/mock_erp.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/integrations/opc/__init__.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/integrations/opc/csv_replay.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/integrations/opc/inspect.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/integrations/opc/security.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/integrations/opc/simulator.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/integrations/opc/tag_map.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/integrations/opc/worksheet.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/kernel/__init__.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/kernel/common.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/kernel/tags.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/logging.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/mcp/__init__.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/mcp/coa.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/mcp/equipment.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/mcp/erp.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/mcp/maintenance.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/mcp/masterdata.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/mcp/quality.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/mcp/scheduling.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/mcp/serialization.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/mcp/triggers.py +0 -0
- {factorysemantics_mes-0.1.2/alembic → factorysemantics_mes-0.2.0/src/fsmes/migrations}/script.py.mako +0 -0
- {factorysemantics_mes-0.1.2/alembic → factorysemantics_mes-0.2.0/src/fsmes/migrations}/versions/153379d6cf19_merge_cutlery_and_walkthrough_chains.py +0 -0
- {factorysemantics_mes-0.1.2/alembic → factorysemantics_mes-0.2.0/src/fsmes/migrations}/versions/18af853fc5c4_initial_schema.py +0 -0
- {factorysemantics_mes-0.1.2/alembic → factorysemantics_mes-0.2.0/src/fsmes/migrations}/versions/7c1e5a9d2b4f_serial_sequences.py +0 -0
- {factorysemantics_mes-0.1.2/alembic → factorysemantics_mes-0.2.0/src/fsmes/migrations}/versions/9c4d2c836d05_add_user_passwords.py +0 -0
- {factorysemantics_mes-0.1.2/alembic → factorysemantics_mes-0.2.0/src/fsmes/migrations}/versions/a1b2c3d4e5f6_agent_identity.py +0 -0
- {factorysemantics_mes-0.1.2/alembic → factorysemantics_mes-0.2.0/src/fsmes/migrations}/versions/a1c5e83b7602_calendar_and_scheduling.py +0 -0
- {factorysemantics_mes-0.1.2/alembic → factorysemantics_mes-0.2.0/src/fsmes/migrations}/versions/a7c1e93b5f20_roles_as_data.py +0 -0
- {factorysemantics_mes-0.1.2/alembic → factorysemantics_mes-0.2.0/src/fsmes/migrations}/versions/a7c2e5d1b9f0_document_kind_steps_needs_walkthroughs.py +0 -0
- {factorysemantics_mes-0.1.2/alembic → factorysemantics_mes-0.2.0/src/fsmes/migrations}/versions/b2c3d4e5f6a7_outbox_hardening.py +0 -0
- {factorysemantics_mes-0.1.2/alembic → factorysemantics_mes-0.2.0/src/fsmes/migrations}/versions/b3f8d2a41c67_controlled_documents.py +0 -0
- {factorysemantics_mes-0.1.2/alembic → factorysemantics_mes-0.2.0/src/fsmes/migrations}/versions/b7d2e9f4a1c3_unit_inspections.py +0 -0
- {factorysemantics_mes-0.1.2/alembic → factorysemantics_mes-0.2.0/src/fsmes/migrations}/versions/b8f4d27e1a53_serialisation.py +0 -0
- {factorysemantics_mes-0.1.2/alembic → factorysemantics_mes-0.2.0/src/fsmes/migrations}/versions/c2e9b74a3f81_gauges_and_calibration.py +0 -0
- {factorysemantics_mes-0.1.2/alembic → factorysemantics_mes-0.2.0/src/fsmes/migrations}/versions/c3d4e5f6a7b8_triggers.py +0 -0
- {factorysemantics_mes-0.1.2/alembic → factorysemantics_mes-0.2.0/src/fsmes/migrations}/versions/c4e8f1a2d5b6_serial_units_one_index.py +0 -0
- {factorysemantics_mes-0.1.2/alembic → factorysemantics_mes-0.2.0/src/fsmes/migrations}/versions/c9e2a4b71d38_material_at_a_station.py +0 -0
- {factorysemantics_mes-0.1.2/alembic → factorysemantics_mes-0.2.0/src/fsmes/migrations}/versions/d4a1c7e5b902_equipment_cost_center.py +0 -0
- {factorysemantics_mes-0.1.2/alembic → factorysemantics_mes-0.2.0/src/fsmes/migrations}/versions/d4a7f10c8b52_component_may_enter_twice.py +0 -0
- {factorysemantics_mes-0.1.2/alembic → factorysemantics_mes-0.2.0/src/fsmes/migrations}/versions/d4e5f6a7b8c9_recommended_adjustments.py +0 -0
- {factorysemantics_mes-0.1.2/alembic → factorysemantics_mes-0.2.0/src/fsmes/migrations}/versions/e5f6a7b8c9d0_tag_values_latest_index.py +0 -0
- {factorysemantics_mes-0.1.2/alembic → factorysemantics_mes-0.2.0/src/fsmes/migrations}/versions/e6b3c92d4f17_drop_the_old_bom_constraint.py +0 -0
- {factorysemantics_mes-0.1.2/alembic → factorysemantics_mes-0.2.0/src/fsmes/migrations}/versions/e7b3c9d18a45_workorder_work_center.py +0 -0
- {factorysemantics_mes-0.1.2/alembic → factorysemantics_mes-0.2.0/src/fsmes/migrations}/versions/f0a1b2c3d4e5_equipment_states_ended_index.py +0 -0
- {factorysemantics_mes-0.1.2/alembic → factorysemantics_mes-0.2.0/src/fsmes/migrations}/versions/f2a8d31c6b74_routing_durations.py +0 -0
- {factorysemantics_mes-0.1.2/alembic → factorysemantics_mes-0.2.0/src/fsmes/migrations}/versions/f7d1a58e2c94_preventive_maintenance.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/py.typed +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/seed.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/seed_kepsim.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/seed_line.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/services/__init__.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/services/adjustments.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/services/ai_status.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/services/assistant.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/services/audit.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/services/auth.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/services/capabilities.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/services/design_triage.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/services/documents.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/services/drafting.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/services/line.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/services/masterdata.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/services/quality.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/services/retention.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/services/scheduling.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/services/serialization.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/services/spc.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/services/staging.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/services/tags.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/services/triggers.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/services/walkthroughs.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/sim/__init__.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/sim/generate.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/sim/operations.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/sim/rollup.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/sim/score.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/sim/store.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/sim/sweep.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/sim/triage.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/sim/truth.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/adjustments.html +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/adjustments.js +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/admin.css +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/admin.html +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/admin.js +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/analysis.css +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/analysis.html +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/assist-record.js +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/assist.css +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/assist.js +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/coa.css +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/coa.html +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/coa.js +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/demo/kepsim-hour.json +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/design.css +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/design.js +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/gauges.html +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/gauges.js +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/index.html +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/instructions.css +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/instructions.html +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/line/app.js +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/line/feed.js +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/line/flow.js +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/line/parts.js +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/line/robot.js +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/line/scene.js +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/line-page.js +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/line.css +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/line.html +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/line3d.html +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/machine.css +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/machines.html +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/machines.js +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/maintenance.html +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/maintenance.js +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/masterdata.html +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/masterdata.js +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/ops.css +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/ops.html +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/ops.js +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/orders.css +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/orders.html +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/quality.css +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/quality.html +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/schedule.html +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/schedule.js +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/spc.html +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/spc.js +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/station.css +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/station.html +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/station.js +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/tags.html +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/tags.js +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/themes.css +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/themes.js +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/trace.html +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/trace.js +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/triggers.html +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/triggers.js +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/vendor/OrbitControls.js +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/vendor/README.md +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/vendor/three.core.min.js +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/src/fsmes/web/vendor/three.module.min.js +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/tests/test_adjustments.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/tests/test_agent.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/tests/test_agent_batching.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/tests/test_agent_eval.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/tests/test_ai_status.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/tests/test_analysis.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/tests/test_assistant.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/tests/test_capabilities.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/tests/test_coa.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/tests/test_core_oplock.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/tests/test_cutlery.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/tests/test_design.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/tests/test_design_triage.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/tests/test_documents.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/tests/test_equipment_oee.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/tests/test_erp_roundtrip.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/tests/test_hierarchy.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/tests/test_hold.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/tests/test_kepsim.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/tests/test_kernel_common.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/tests/test_line_api.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/tests/test_line_scoping.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/tests/test_maintenance.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/tests/test_mcp_parity.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/tests/test_mcp_product.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/tests/test_megafactory.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/tests/test_onboarding.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/tests/test_packaged_config.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/tests/test_paging.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/tests/test_plant_scale_ui.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/tests/test_plant_serve_only.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/tests/test_quality.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/tests/test_rollup.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/tests/test_routing_depth.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/tests/test_scale.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/tests/test_scheduling_trace.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/tests/test_serial_scale.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/tests/test_spc_gauges.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/tests/test_store.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/tests/test_tag_fabric.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/tests/test_tag_fabric_review.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/tests/test_tags.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/tests/test_themes.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/tests/test_triage.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/tests/test_triggers.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/tests/test_ui_check.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/tests/test_walkthroughs.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/tests/test_washer_story.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/tests/test_web.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/tests/test_wip.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/tests/test_workorders.py +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/tests/ui/baselines/control-room.json +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/tests/ui/baselines/daylight.json +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/tests/ui/baselines/high-contrast.json +0 -0
- {factorysemantics_mes-0.1.2 → factorysemantics_mes-0.2.0}/tests/ui/baselines/night-shift.json +0 -0
- {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
|
-
|
|
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
|
-
|
|
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
|