Thank you for your interest in contributing to SimaticML Decoder. This document covers development setup, code organization, submission guidelines, and the fixture policy.
pip install -e ".[dev]"This installs the package in editable mode along with lint, test, coverage, build, and validation tools.
Before opening a pull request, run these two commands locally and ensure both pass:
ruff check .
pytest -q --cov=simaticml_decoder --cov-report=term-missing --cov-fail-under=80ruff check .— Lints and checks code style (100 character line length)pytest --cov=...— Runs all tests and enforces 80% code coverage
The 80% coverage floor is enforced both in CI and locally in pyproject.toml ([tool.coverage.report] fail_under = 80), so it is not a CI-only gate. Coverage must pass on your machine before you push.
src/simaticml_decoder/windows_handles.py is intentionally omitted from coverage reporting. It contains Windows-only ctypes and NTAPI glue code that is only called from input_policy.py behind a _use_windows_native_discovery() guard. On Linux CI it never executes and would drag aggregate coverage below the 80% floor for platform-specific reasons unrelated to any regression. It has its own platform-gated test suite (tests/test_windows_handles.py, skipif'd to run only on Windows) that verifies it directly.
The decoder consists of three cleanly separated, independently testable phases:
parse.py— XML parser and validationmodel.py— Faithful syntactic mirror of the parsed XML
fold.py— Folding logic: series→AND,O→OR, fan-out, negation, latchesir.py— Intermediate representation: boolean trees and assignments
emit.py— Code generation: IR to SCL text and JSON sidecar
instructions.py— Part catalog (data, not logic)operand.py— Access → display string conversionscl_reconstruct.py— SCL network reconstruction from tokenised ASTinput_policy.py— Untrusted-input boundary enforcement
project.py— Top-level project coordinatorproject_discovery.py— Handle-anchored, symlink-rejecting file discoveryproject_xml.py— XML classification and resource loadingproject_model.py— Block and UDT model contractsproject_index.py— Cross-project reference resolutionproject_emit.py— Project manifest generation
cli.py— Command-line interface
Follow Conventional Commits format:
<type>: <description>
<optional body>
feat:— New featurefix:— Bug fixdocs:— Documentation changestest:— Test additions or changesrefactor:— Code refactoring (no feature or bug-fix change)chore:— Dependency or tooling updatesperf:— Performance improvementsci:— CI/CD workflow changes
feat: add explicit project index command
fix: handle manifest-write failures and invalid --library-root input cleanly
docs: define V21 project input contract
test: cover UDT-reference resolution in project index
ci: enforce supported-format coverage gate
Any new test fixture, golden output file, or diagnostic example must meet these criteria:
- Clear license — The source must have a declared license (MIT, Apache-2.0, BSD, etc.) or explicit permission for redistribution.
- Sanitized and redistributable — Remove or redact any proprietary, sensitive, or identifying information.
- CI regression test — A non-skipping test must exercise the fixture and validate the output against golden or expected values.
Until all three conditions are met, a format is not claimed as "validated". We do not use unlicensed fixtures as a template for adding more.
The repository currently includes temporary compatibility probes from felipebojorquem/sorting-cell-s7-1200, which has no declared license. These probes are used only for local decoder evaluation; they are not a distributable fixture corpus and do not validate feature support. A replacement corpus from a suitably licensed, redaction-reviewed project is pending.
Before submitting a pull request:
- Code is lint-clean —
ruff check .passes - Tests pass and coverage is sufficient —
pytest --cov=...passes with 80%+ coverage - Commit messages follow convention — Conventional Commits format (
feat:,fix:, etc.) - Documentation is updated — If you changed CLI flags, behavior, or interfaces, update
README.mdor relevant docs - Fixtures are licensed — If you added test data, it has a clear license and redistribution rights
- No hardcoded secrets — No API keys, passwords, or internal URLs in code or tests
By contributing to this project, you agree that your contributions will be licensed under the same MIT License as the project (see LICENSE).
For questions, open a GitHub issue. For security concerns, see SECURITY.md.