simaudit 0.1.0a1__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 (45) hide show
  1. simaudit-0.1.0a1/CHANGELOG.md +15 -0
  2. simaudit-0.1.0a1/CITATION.cff +37 -0
  3. simaudit-0.1.0a1/LICENSE +21 -0
  4. simaudit-0.1.0a1/MANIFEST.in +6 -0
  5. simaudit-0.1.0a1/PKG-INFO +230 -0
  6. simaudit-0.1.0a1/README.md +194 -0
  7. simaudit-0.1.0a1/THIRD_PARTY.md +32 -0
  8. simaudit-0.1.0a1/VALIDATION.md +118 -0
  9. simaudit-0.1.0a1/docs/ADAPTERS.md +70 -0
  10. simaudit-0.1.0a1/docs/REPORTS.md +32 -0
  11. simaudit-0.1.0a1/docs/REQUIREMENTS.md +112 -0
  12. simaudit-0.1.0a1/examples/cartpole-probes.json +1 -0
  13. simaudit-0.1.0a1/examples/custom_simulator.py +24 -0
  14. simaudit-0.1.0a1/examples/probes.json +1 -0
  15. simaudit-0.1.0a1/pyproject.toml +53 -0
  16. simaudit-0.1.0a1/references.bib +17 -0
  17. simaudit-0.1.0a1/setup.cfg +4 -0
  18. simaudit-0.1.0a1/src/simaudit/__init__.py +9 -0
  19. simaudit-0.1.0a1/src/simaudit/__main__.py +2 -0
  20. simaudit-0.1.0a1/src/simaudit/adapters/__init__.py +3 -0
  21. simaudit-0.1.0a1/src/simaudit/adapters/base.py +68 -0
  22. simaudit-0.1.0a1/src/simaudit/adapters/cartpole.py +66 -0
  23. simaudit-0.1.0a1/src/simaudit/adapters/mujoco.py +108 -0
  24. simaudit-0.1.0a1/src/simaudit/checks.py +220 -0
  25. simaudit-0.1.0a1/src/simaudit/cli.py +53 -0
  26. simaudit-0.1.0a1/src/simaudit/pytest_plugin.py +43 -0
  27. simaudit-0.1.0a1/src/simaudit/release.py +107 -0
  28. simaudit-0.1.0a1/src/simaudit/report.py +151 -0
  29. simaudit-0.1.0a1/src/simaudit/worker.py +15 -0
  30. simaudit-0.1.0a1/src/simaudit.egg-info/PKG-INFO +230 -0
  31. simaudit-0.1.0a1/src/simaudit.egg-info/SOURCES.txt +43 -0
  32. simaudit-0.1.0a1/src/simaudit.egg-info/dependency_links.txt +1 -0
  33. simaudit-0.1.0a1/src/simaudit.egg-info/entry_points.txt +5 -0
  34. simaudit-0.1.0a1/src/simaudit.egg-info/requires.txt +16 -0
  35. simaudit-0.1.0a1/src/simaudit.egg-info/top_level.txt +1 -0
  36. simaudit-0.1.0a1/tests/test_checks.py +200 -0
  37. simaudit-0.1.0a1/tests/test_mujoco.py +22 -0
  38. simaudit-0.1.0a1/tests/test_plugin.py +24 -0
  39. simaudit-0.1.0a1/validation/PROTOCOL.md +29 -0
  40. simaudit-0.1.0a1/validation/known_cases.py +43 -0
  41. simaudit-0.1.0a1/validation/make_receipt.py +17 -0
  42. simaudit-0.1.0a1/validation/run_controls.py +51 -0
  43. simaudit-0.1.0a1/validation/run_known_cases.py +43 -0
  44. simaudit-0.1.0a1/validation/run_release_cases.py +19 -0
  45. simaudit-0.1.0a1/validation/verify_receipt.py +19 -0
@@ -0,0 +1,15 @@
1
+ # Changelog
2
+
3
+ ## 0.1.0a1 - 2026-11-14
4
+
5
+ First public alpha.
6
+
7
+ - Checks: parameter-assignment consistency, integrator-order convergence,
8
+ release comparison across interpreters, and observation consistency.
9
+ - Six explicit statuses (PASS, FAIL, ABSTAIN, SKIPPED, PARTIAL, BLOWUP) and
10
+ strict JSON reports with stated limitations.
11
+ - CLI, pytest fixture, Gymnasium CartPole/Reacher adapters, MuJoCo order adapter.
12
+ - Fixed before publication: `compare_releases` exposed the caller's whole
13
+ site-packages to its worker interpreters when pip-installed; workers now see
14
+ only the simaudit package.
15
+ - Validation includes MuJoCo 3.16.0, 3.17.0 and 4.0.1 (see VALIDATION.md).
@@ -0,0 +1,37 @@
1
+ cff-version: 1.2.0
2
+ message: "Please cite the two method papers below when using simaudit. Paper authorship is recorded separately from software authorship."
3
+ title: "simaudit: scoped diagnostics for simulators"
4
+ type: software
5
+ version: 0.1.0a1
6
+ date-released: 2026-11-14
7
+ repository-code: "https://github.com/TesfayZ/simaudit"
8
+ keywords:
9
+ - reinforcement learning
10
+ - simulator validation
11
+ - MuJoCo
12
+ - Gymnasium
13
+ - numerical verification
14
+ abstract: "Scoped, reproducible diagnostics for user-supplied simulators: parameter-assignment consistency, integrator-order convergence, release comparison and observation consistency, with explicit statements of what was not assessed."
15
+ license: MIT
16
+ authors:
17
+ - family-names: Gebrekidan
18
+ given-names: Tesfay Zemuy
19
+ references:
20
+ - type: article
21
+ title: "Diagnosing Model and Discretisation Errors in Reinforcement Learning Simulators Using Invariants"
22
+ authors:
23
+ - family-names: Gebrekidan
24
+ given-names: Tesfay Zemuy
25
+ year: 2026
26
+ doi: 10.5281/zenodo.24114609
27
+ url: "https://zenodo.org/records/24114609"
28
+ - type: article
29
+ title: "Diagnosing Faults in Reinforcement Learning Simulators with Canonical Polynomial Invariants"
30
+ authors:
31
+ - family-names: Gebrekidan
32
+ given-names: Tesfay Zemuy
33
+ - family-names: Gebrerufael
34
+ given-names: Hadush Hailu
35
+ year: 2026
36
+ doi: 10.48550/arXiv.2609.13194
37
+ url: "https://arxiv.org/abs/2609.13194v2"
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Tesfay Zemuy Gebrekidan
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,6 @@
1
+ include LICENSE CITATION.cff references.bib THIRD_PARTY.md VALIDATION.md CHANGELOG.md
2
+ recursive-include docs *.md
3
+ recursive-include examples *.py *.json
4
+ recursive-include validation *.py *.md
5
+ recursive-include tests *.py
6
+ prune evidence
@@ -0,0 +1,230 @@
1
+ Metadata-Version: 2.4
2
+ Name: simaudit
3
+ Version: 0.1.0a1
4
+ Summary: Scoped, reproducible diagnostics for user-supplied simulators
5
+ Author: Tesfay Zemuy Gebrekidan
6
+ License-Expression: MIT
7
+ Project-URL: Repository, https://github.com/TesfayZ/simaudit
8
+ Project-URL: Issues, https://github.com/TesfayZ/simaudit/issues
9
+ Project-URL: Documentation, https://github.com/TesfayZ/simaudit#readme
10
+ Keywords: reinforcement-learning,simulator,verification,mujoco,gymnasium,testing
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: Intended Audience :: Science/Research
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3.11
15
+ Classifier: Programming Language :: Python :: 3.12
16
+ Classifier: Programming Language :: Python :: 3.13
17
+ Classifier: Programming Language :: Python :: 3.14
18
+ Classifier: Topic :: Scientific/Engineering
19
+ Classifier: Framework :: Pytest
20
+ Requires-Python: >=3.11
21
+ Description-Content-Type: text/markdown
22
+ License-File: LICENSE
23
+ Requires-Dist: numpy>=1.24
24
+ Provides-Extra: gymnasium
25
+ Requires-Dist: gymnasium>=1.0; extra == "gymnasium"
26
+ Provides-Extra: mujoco
27
+ Requires-Dist: mujoco>=3.2; extra == "mujoco"
28
+ Requires-Dist: gymnasium>=1.0; extra == "mujoco"
29
+ Provides-Extra: pytest
30
+ Requires-Dist: pytest>=8; extra == "pytest"
31
+ Provides-Extra: dev
32
+ Requires-Dist: pytest>=8; extra == "dev"
33
+ Requires-Dist: build>=1; extra == "dev"
34
+ Requires-Dist: gymnasium>=1.0; extra == "dev"
35
+ Dynamic: license-file
36
+
37
+ # simaudit
38
+
39
+ Installable diagnostics for **your own simulator**, with explicit limits on what
40
+ was assessed. Supply a small Python adapter; NumPy is the only core dependency.
41
+ Gymnasium and MuJoCo are optional examples. Version **0.1.0a1** is an alpha,
42
+ not a generally calibrated simulator-certification service.
43
+
44
+ ## Install
45
+
46
+ ```bash
47
+ # Pre-release: pip skips alpha versions unless you ask for them.
48
+ python -m pip install --pre simaudit
49
+ # Optional adapters and pytest integration:
50
+ python -m pip install --pre 'simaudit[gymnasium,mujoco,pytest]'
51
+ # Or from a source checkout:
52
+ python -m pip install .
53
+ ```
54
+
55
+ Python 3.11 or newer (CI matrix 3.11-3.14; local validation on 3.14.6 and 3.12.3). Nothing downloads, runs experiments, or imports an optional
56
+ simulator on package import. For development: `python -m pip install '.[dev]'`.
57
+
58
+ ## Test your own simulator
59
+
60
+ ```python
61
+ import numpy as np
62
+ from simaudit import Adapter, Feature, Report, check_order
63
+
64
+ # Wrap your simulator so each call restores every dependency of its next step.
65
+ def step(state, action, dt):
66
+ return state + dt * (state + action)
67
+
68
+ def native_reference(state, action, dt):
69
+ return np.asarray([(1 + dt) * state[0] + dt * action])
70
+
71
+ adapter = Adapter(
72
+ name="my simulator", step_fn=step, native_step_fn=native_reference,
73
+ features=[Feature("dynamics", "tested", "Smooth scalar ODE, no hidden state", True)],
74
+ smooth=True, declared_order=1, dt=0.2,
75
+ )
76
+ result = check_order(adapter, [[0.5], [1.0], [1.5]], [0, 0, 0])
77
+ report = Report([result])
78
+ print(report.summary())
79
+ report.write("audit.json")
80
+ ```
81
+
82
+ The native reference should call the original simulator without the adapter
83
+ transformation being tested. A user-provided reference and inventory are trusted
84
+ inputs, not automatically verified specifications. See [the adapter guide](docs/ADAPTERS.md)
85
+ for mutable simulators, noise, arbitrary state metrics, assignment factories,
86
+ observation maps and capability requirements.
87
+
88
+ The CLI loads a trusted local `module:function` returning an adapter. From this
89
+ directory, run the included NumPy-only example:
90
+
91
+ ```bash
92
+ PYTHONPATH=examples simaudit order --factory custom_simulator:factory \
93
+ --probes examples/probes.json --strict --json audit.json
94
+ ```
95
+
96
+ Python factories execute code with your Python process's privileges. Probe files
97
+ contain only `states` and matching `actions`. The same interface works with your
98
+ own importable adapter module. `python -m simaudit` is equivalent to `simaudit`.
99
+
100
+ ## Four independent checks
101
+
102
+ | Check | Python API | Needs | What it reports |
103
+ |---|---|---|---|
104
+ | Parameter assignment | `check_assignment` | Replay, native reference, assignment factory | Baseline/direct/fresh comparison; no-op, stale, consistent or unresolved |
105
+ | Numerical order | `check_order` | Replay, native reference, timestep, declared order, smoothness, distance | Stable refinement slopes, below-declaration order, or inability to diagnose |
106
+ | Release/variant comparison | `compare_releases` | Factory and two supplied Python interpreters | First-step differences on identical inputs; later differences recorded separately |
107
+ | Observation consistency | `check_observation` | Replay, native reference, observed and reference observation maps | Differences above the precision/noise floor |
108
+
109
+ The package doesn't implement the papers' energy-fingerprint classifier,
110
+ algebraic localisation, parameter identification or automatic equation diagnosis.
111
+ A numerical-order pass cannot establish that equations are correct.
112
+
113
+ ## Results and limitations
114
+
115
+ Every result contains **PASS, FAIL, ABSTAIN, SKIPPED, PARTIAL or BLOWUP**, a reason,
116
+ scope, limitations, mandatory feature coverage, modifications, versions and raw
117
+ probe measurements. Limitations and untested features are printed beside results.
118
+
119
+ - Float32 or a declared noise floor blocks a healthy consistency verdict in
120
+ checks A, B and D. A and D can still flag discrepancies above their floors.
121
+ - Missing capabilities return `SKIPPED`; unsupported smoothness/features give
122
+ `PARTIAL`; unresolved or unstable slopes give `ABSTAIN`.
123
+ - Nonfinite trajectories or detected engine resets give `BLOWUP`.
124
+ - A failed adapter replay/native-step self-test blocks downstream diagnosis.
125
+ - `PASS` covers the supplied probes under the declared conditions only. A wrong
126
+ reference, shared implementation error or unreported hidden state can escape it.
127
+
128
+ By default `FAIL` exits 1; other nonpasses print a warning and exit 0. `--strict`
129
+ exits 1 on **any** nonpass. Configuration errors exit 2. Empty reports are never
130
+ all-clear. [Report contract](docs/REPORTS.md).
131
+
132
+ ## Optional adapters and releases
133
+
134
+ ```bash
135
+ simaudit assignment --factory simaudit.adapters.cartpole:cartpole \
136
+ --probes examples/cartpole-probes.json --parameter masscart --value 2 --json cartpole.json
137
+ ```
138
+
139
+ This deliberately detects the paper's assignment discrepancy and exits 1. The
140
+ fresh CartPole reference explicitly rebuilds dependent constants; it does not
141
+ assert that Gymnasium promises arbitrary attribute mutation.
142
+
143
+ `mujoco_xml(xml)` supplies native replay for smooth autonomous rigid models and
144
+ rejects unsupported features. `reacher()` supplies a cache-consistency comparison
145
+ against the shipped observation map after `mj_forward`. Both live in
146
+ `simaudit.adapters.mujoco`; imports are lazy. Custom adapters are not subject to
147
+ these built-in models' limitations but must declare their own.
148
+
149
+ For a release pair, create two separate environments yourself, with NumPy and
150
+ the simulator versions you want, then supply their Python paths:
151
+
152
+ ```bash
153
+ simaudit release --factory simaudit.adapters.cartpole:cartpole \
154
+ --probes examples/cartpole-probes.json --python-a /path/a/bin/python \
155
+ --python-b /path/b/bin/python --strict --json releases.json
156
+ ```
157
+
158
+ The worker runs the current package source in each interpreter. The package does
159
+ not install or upgrade either environment. Your custom factory module must also
160
+ be importable there. Missing versions remain untested. A changed first step means
161
+ compatibility changed, not necessarily that either release is wrong.
162
+
163
+ ## pytest and verification
164
+
165
+ Install the `pytest` extra to use the auto-discovered `simaudit_check` fixture:
166
+
167
+ ```python
168
+ def test_simulator(simaudit_check):
169
+ simaudit_check(check_order(adapter, [[1.0]], [0]))
170
+ ```
171
+
172
+ `FAIL` fails the test; other nonpasses skip with their original status and full
173
+ reason. `pytest --simaudit-strict --simaudit-json results.json` fails the session
174
+ on any nonpass and preserves the separate audit counts. Reporting is serial;
175
+ pytest-xdist aggregation is not supported.
176
+
177
+ Run software tests with `python -m pytest`. Build with
178
+ `python -m build`. See [validation results](VALIDATION.md),
179
+ [prospective paper-case protocol](validation/PROTOCOL.md), and
180
+ [requirements and acceptance criteria](docs/REQUIREMENTS.md). These are small package tests
181
+ and selected reproductions, not a general false-alarm guarantee.
182
+
183
+ ## Cite the two method papers
184
+
185
+ 1. **Tesfay Zemuy Gebrekidan** (2026). *Diagnosing Model and Discretisation Errors
186
+ in Reinforcement Learning Simulators Using Invariants*.
187
+ [Zenodo](https://zenodo.org/records/24114609).
188
+ 2. **Tesfay Zemuy Gebrekidan and Hadush Hailu Gebrerufael** (2026).
189
+ *Diagnosing Faults in Reinforcement Learning Simulators with Canonical
190
+ Polynomial Invariants*. [arXiv:2609.13194v2](https://arxiv.org/abs/2609.13194v2).
191
+
192
+ [CITATION.cff](CITATION.cff), [BibTeX](references.bib), and
193
+ [reuse and licence notices](THIRD_PARTY.md) preserve the attribution. MIT licensed.
194
+
195
+ ## What it has found so far
196
+
197
+ From [VALIDATION.md](VALIDATION.md); each row is scoped to the supplied probes.
198
+
199
+ | Case | Result |
200
+ |---|---|
201
+ | Gymnasium CartPole `masscart`/`masspole`/`length` assignment | FAIL (no-op / stale / partly stale) vs a freshly constructed reference; `gravity` PASS |
202
+ | MuJoCo 3.16.0 and 3.17.0, RK4 heavy top on a ball joint | FAIL: 23/24 probes below declared order 4 (1/24 ABSTAIN), median slope 1.96 |
203
+ | MuJoCo **4.0.1**, same model and probes | PASS 24/24, median slope 3.92 |
204
+ | Same model with three hinges (control) | PASS in every tested engine |
205
+ | Reacher post-step observation vs refreshed map | FAIL, largest discrepancy 2.4e-6 (3.16.0, 3.17.0 and 4.0.1) |
206
+
207
+ MuJoCo 4.0.0 itself was not installed or tested; no result is inferred for it.
208
+
209
+ ## Roadmap
210
+
211
+ Not implemented in 0.1.0a1, and not claimed anywhere in this package:
212
+
213
+ - **0.2:** energy-refinement fingerprint (model-versus-discretisation label), a
214
+ decision table combining checks, and a one-parameter fit, each only with its
215
+ negative-control suite passing.
216
+ - **0.3:** algebraic invariant screening behind an optional extra.
217
+ - Other classic-control assignment adapters, vector environments, and shipped
218
+ Ant/Humanoid with contacts and actuation.
219
+
220
+ ## Documentation
221
+
222
+ | File | Purpose |
223
+ |---|---|
224
+ | [docs/ADAPTERS.md](docs/ADAPTERS.md) | Writing an adapter and declaring its features |
225
+ | [docs/REPORTS.md](docs/REPORTS.md) | Report schema, statuses and JSON round trip |
226
+ | [docs/REQUIREMENTS.md](docs/REQUIREMENTS.md) | Acceptance criteria recorded before validation |
227
+ | [VALIDATION.md](VALIDATION.md) | What was actually run, and the limits of those runs |
228
+ | [validation/PROTOCOL.md](validation/PROTOCOL.md) | Paper-case protocol and scripts |
229
+ | [evidence/README.md](evidence/README.md) | Archived result files and the hash receipt |
230
+ | [CHANGELOG.md](CHANGELOG.md) | Release history |
@@ -0,0 +1,194 @@
1
+ # simaudit
2
+
3
+ Installable diagnostics for **your own simulator**, with explicit limits on what
4
+ was assessed. Supply a small Python adapter; NumPy is the only core dependency.
5
+ Gymnasium and MuJoCo are optional examples. Version **0.1.0a1** is an alpha,
6
+ not a generally calibrated simulator-certification service.
7
+
8
+ ## Install
9
+
10
+ ```bash
11
+ # Pre-release: pip skips alpha versions unless you ask for them.
12
+ python -m pip install --pre simaudit
13
+ # Optional adapters and pytest integration:
14
+ python -m pip install --pre 'simaudit[gymnasium,mujoco,pytest]'
15
+ # Or from a source checkout:
16
+ python -m pip install .
17
+ ```
18
+
19
+ Python 3.11 or newer (CI matrix 3.11-3.14; local validation on 3.14.6 and 3.12.3). Nothing downloads, runs experiments, or imports an optional
20
+ simulator on package import. For development: `python -m pip install '.[dev]'`.
21
+
22
+ ## Test your own simulator
23
+
24
+ ```python
25
+ import numpy as np
26
+ from simaudit import Adapter, Feature, Report, check_order
27
+
28
+ # Wrap your simulator so each call restores every dependency of its next step.
29
+ def step(state, action, dt):
30
+ return state + dt * (state + action)
31
+
32
+ def native_reference(state, action, dt):
33
+ return np.asarray([(1 + dt) * state[0] + dt * action])
34
+
35
+ adapter = Adapter(
36
+ name="my simulator", step_fn=step, native_step_fn=native_reference,
37
+ features=[Feature("dynamics", "tested", "Smooth scalar ODE, no hidden state", True)],
38
+ smooth=True, declared_order=1, dt=0.2,
39
+ )
40
+ result = check_order(adapter, [[0.5], [1.0], [1.5]], [0, 0, 0])
41
+ report = Report([result])
42
+ print(report.summary())
43
+ report.write("audit.json")
44
+ ```
45
+
46
+ The native reference should call the original simulator without the adapter
47
+ transformation being tested. A user-provided reference and inventory are trusted
48
+ inputs, not automatically verified specifications. See [the adapter guide](docs/ADAPTERS.md)
49
+ for mutable simulators, noise, arbitrary state metrics, assignment factories,
50
+ observation maps and capability requirements.
51
+
52
+ The CLI loads a trusted local `module:function` returning an adapter. From this
53
+ directory, run the included NumPy-only example:
54
+
55
+ ```bash
56
+ PYTHONPATH=examples simaudit order --factory custom_simulator:factory \
57
+ --probes examples/probes.json --strict --json audit.json
58
+ ```
59
+
60
+ Python factories execute code with your Python process's privileges. Probe files
61
+ contain only `states` and matching `actions`. The same interface works with your
62
+ own importable adapter module. `python -m simaudit` is equivalent to `simaudit`.
63
+
64
+ ## Four independent checks
65
+
66
+ | Check | Python API | Needs | What it reports |
67
+ |---|---|---|---|
68
+ | Parameter assignment | `check_assignment` | Replay, native reference, assignment factory | Baseline/direct/fresh comparison; no-op, stale, consistent or unresolved |
69
+ | Numerical order | `check_order` | Replay, native reference, timestep, declared order, smoothness, distance | Stable refinement slopes, below-declaration order, or inability to diagnose |
70
+ | Release/variant comparison | `compare_releases` | Factory and two supplied Python interpreters | First-step differences on identical inputs; later differences recorded separately |
71
+ | Observation consistency | `check_observation` | Replay, native reference, observed and reference observation maps | Differences above the precision/noise floor |
72
+
73
+ The package doesn't implement the papers' energy-fingerprint classifier,
74
+ algebraic localisation, parameter identification or automatic equation diagnosis.
75
+ A numerical-order pass cannot establish that equations are correct.
76
+
77
+ ## Results and limitations
78
+
79
+ Every result contains **PASS, FAIL, ABSTAIN, SKIPPED, PARTIAL or BLOWUP**, a reason,
80
+ scope, limitations, mandatory feature coverage, modifications, versions and raw
81
+ probe measurements. Limitations and untested features are printed beside results.
82
+
83
+ - Float32 or a declared noise floor blocks a healthy consistency verdict in
84
+ checks A, B and D. A and D can still flag discrepancies above their floors.
85
+ - Missing capabilities return `SKIPPED`; unsupported smoothness/features give
86
+ `PARTIAL`; unresolved or unstable slopes give `ABSTAIN`.
87
+ - Nonfinite trajectories or detected engine resets give `BLOWUP`.
88
+ - A failed adapter replay/native-step self-test blocks downstream diagnosis.
89
+ - `PASS` covers the supplied probes under the declared conditions only. A wrong
90
+ reference, shared implementation error or unreported hidden state can escape it.
91
+
92
+ By default `FAIL` exits 1; other nonpasses print a warning and exit 0. `--strict`
93
+ exits 1 on **any** nonpass. Configuration errors exit 2. Empty reports are never
94
+ all-clear. [Report contract](docs/REPORTS.md).
95
+
96
+ ## Optional adapters and releases
97
+
98
+ ```bash
99
+ simaudit assignment --factory simaudit.adapters.cartpole:cartpole \
100
+ --probes examples/cartpole-probes.json --parameter masscart --value 2 --json cartpole.json
101
+ ```
102
+
103
+ This deliberately detects the paper's assignment discrepancy and exits 1. The
104
+ fresh CartPole reference explicitly rebuilds dependent constants; it does not
105
+ assert that Gymnasium promises arbitrary attribute mutation.
106
+
107
+ `mujoco_xml(xml)` supplies native replay for smooth autonomous rigid models and
108
+ rejects unsupported features. `reacher()` supplies a cache-consistency comparison
109
+ against the shipped observation map after `mj_forward`. Both live in
110
+ `simaudit.adapters.mujoco`; imports are lazy. Custom adapters are not subject to
111
+ these built-in models' limitations but must declare their own.
112
+
113
+ For a release pair, create two separate environments yourself, with NumPy and
114
+ the simulator versions you want, then supply their Python paths:
115
+
116
+ ```bash
117
+ simaudit release --factory simaudit.adapters.cartpole:cartpole \
118
+ --probes examples/cartpole-probes.json --python-a /path/a/bin/python \
119
+ --python-b /path/b/bin/python --strict --json releases.json
120
+ ```
121
+
122
+ The worker runs the current package source in each interpreter. The package does
123
+ not install or upgrade either environment. Your custom factory module must also
124
+ be importable there. Missing versions remain untested. A changed first step means
125
+ compatibility changed, not necessarily that either release is wrong.
126
+
127
+ ## pytest and verification
128
+
129
+ Install the `pytest` extra to use the auto-discovered `simaudit_check` fixture:
130
+
131
+ ```python
132
+ def test_simulator(simaudit_check):
133
+ simaudit_check(check_order(adapter, [[1.0]], [0]))
134
+ ```
135
+
136
+ `FAIL` fails the test; other nonpasses skip with their original status and full
137
+ reason. `pytest --simaudit-strict --simaudit-json results.json` fails the session
138
+ on any nonpass and preserves the separate audit counts. Reporting is serial;
139
+ pytest-xdist aggregation is not supported.
140
+
141
+ Run software tests with `python -m pytest`. Build with
142
+ `python -m build`. See [validation results](VALIDATION.md),
143
+ [prospective paper-case protocol](validation/PROTOCOL.md), and
144
+ [requirements and acceptance criteria](docs/REQUIREMENTS.md). These are small package tests
145
+ and selected reproductions, not a general false-alarm guarantee.
146
+
147
+ ## Cite the two method papers
148
+
149
+ 1. **Tesfay Zemuy Gebrekidan** (2026). *Diagnosing Model and Discretisation Errors
150
+ in Reinforcement Learning Simulators Using Invariants*.
151
+ [Zenodo](https://zenodo.org/records/24114609).
152
+ 2. **Tesfay Zemuy Gebrekidan and Hadush Hailu Gebrerufael** (2026).
153
+ *Diagnosing Faults in Reinforcement Learning Simulators with Canonical
154
+ Polynomial Invariants*. [arXiv:2609.13194v2](https://arxiv.org/abs/2609.13194v2).
155
+
156
+ [CITATION.cff](CITATION.cff), [BibTeX](references.bib), and
157
+ [reuse and licence notices](THIRD_PARTY.md) preserve the attribution. MIT licensed.
158
+
159
+ ## What it has found so far
160
+
161
+ From [VALIDATION.md](VALIDATION.md); each row is scoped to the supplied probes.
162
+
163
+ | Case | Result |
164
+ |---|---|
165
+ | Gymnasium CartPole `masscart`/`masspole`/`length` assignment | FAIL (no-op / stale / partly stale) vs a freshly constructed reference; `gravity` PASS |
166
+ | MuJoCo 3.16.0 and 3.17.0, RK4 heavy top on a ball joint | FAIL: 23/24 probes below declared order 4 (1/24 ABSTAIN), median slope 1.96 |
167
+ | MuJoCo **4.0.1**, same model and probes | PASS 24/24, median slope 3.92 |
168
+ | Same model with three hinges (control) | PASS in every tested engine |
169
+ | Reacher post-step observation vs refreshed map | FAIL, largest discrepancy 2.4e-6 (3.16.0, 3.17.0 and 4.0.1) |
170
+
171
+ MuJoCo 4.0.0 itself was not installed or tested; no result is inferred for it.
172
+
173
+ ## Roadmap
174
+
175
+ Not implemented in 0.1.0a1, and not claimed anywhere in this package:
176
+
177
+ - **0.2:** energy-refinement fingerprint (model-versus-discretisation label), a
178
+ decision table combining checks, and a one-parameter fit, each only with its
179
+ negative-control suite passing.
180
+ - **0.3:** algebraic invariant screening behind an optional extra.
181
+ - Other classic-control assignment adapters, vector environments, and shipped
182
+ Ant/Humanoid with contacts and actuation.
183
+
184
+ ## Documentation
185
+
186
+ | File | Purpose |
187
+ |---|---|
188
+ | [docs/ADAPTERS.md](docs/ADAPTERS.md) | Writing an adapter and declaring its features |
189
+ | [docs/REPORTS.md](docs/REPORTS.md) | Report schema, statuses and JSON round trip |
190
+ | [docs/REQUIREMENTS.md](docs/REQUIREMENTS.md) | Acceptance criteria recorded before validation |
191
+ | [VALIDATION.md](VALIDATION.md) | What was actually run, and the limits of those runs |
192
+ | [validation/PROTOCOL.md](validation/PROTOCOL.md) | Paper-case protocol and scripts |
193
+ | [evidence/README.md](evidence/README.md) | Archived result files and the hash receipt |
194
+ | [CHANGELOG.md](CHANGELOG.md) | Release history |
@@ -0,0 +1,32 @@
1
+ # Method provenance and reuse
2
+
3
+ The package uses two source papers, with their full authorship preserved:
4
+
5
+ 1. **Tesfay Zemuy Gebrekidan.** *Diagnosing Model and Discretisation Errors in
6
+ Reinforcement Learning Simulators Using Invariants* (2026).
7
+ [Zenodo record](https://zenodo.org/records/24114609).
8
+ Source repository: [`dafd`](https://github.com/TesfayZ/dafd). Assignment consistency, refinement diagnostics,
9
+ native integrator controls and precision/coverage limitations inform this package.
10
+ 2. **Tesfay Zemuy Gebrekidan and Hadush Hailu Gebrerufael.** *Diagnosing Faults in
11
+ Reinforcement Learning Simulators with Canonical Polynomial Invariants* (2026).
12
+ [arXiv:2609.13194v2](https://arxiv.org/abs/2609.13194v2).
13
+ Source repository: [`algebraicRLtest`](https://github.com/TesfayZ/algebraicRLtest). Paired release comparisons, positive
14
+ controls and observation consistency inform this package. Its algebraic
15
+ screening/localisation method is not implemented in this alpha.
16
+
17
+ Both source repositories have MIT licences, copyright 2026 Tesfay Zemuy Gebrekidan.
18
+ That software licence notice does not replace the papers' scholarly authorship.
19
+ The MIT notice is retained in LICENSE. `validation/known_cases.py` adapts the
20
+ minimal heavy-top geometry from `dafd/benchmark_quaternion_mechanism.py`; its
21
+ collision masks are explicitly changed for the conservative test. The small
22
+ checks are new adapter-based implementations of the documented methods. No
23
+ research runner, paper prose, dataset, model or complete source module is vendored.
24
+ Source file hashes inspected during development appear in evidence/reuse_sources.json.
25
+
26
+ Runtime dependencies are imported, not bundled: NumPy (BSD-3-Clause), Gymnasium
27
+ (MIT, optional), MuJoCo (Apache-2.0, optional), pytest (MIT, optional). A stable
28
+ release still needs a full resolved dependency licence inventory, including
29
+ transitive dependencies. This list does not claim that audit has been completed.
30
+
31
+ Official interfaces consulted: [MuJoCo API](https://mujoco.readthedocs.io/en/stable/APIreference/APIfunctions.html)
32
+ and [pytest plugin documentation](https://docs.pytest.org/en/stable/how-to/writing_plugins.html).
@@ -0,0 +1,118 @@
1
+ # Validation of 0.1.0a1
2
+
3
+ Local measurements, 11 November 2026. Protocols were written before package
4
+ measurements: docs/REQUIREMENTS.md (software controls) and validation/PROTOCOL.md
5
+ (paper cases). Full results are in evidence/*.json. These are new package runs,
6
+ not imports of the papers' result tables and not an independent scientific
7
+ replication of their complete studies.
8
+
9
+ ## Paper cases
10
+
11
+ Both installed combinations were exercised: **Gymnasium 1.4.0 / MuJoCo 3.16.0**
12
+ and **Gymnasium 1.3.0 / MuJoCo 3.17.0**, under Python 3.14.6.
13
+
14
+ | Case | Result in both combinations | Scope |
15
+ |---|---|---|
16
+ | CartPole masscart x2 | FAIL: no-op relative to fresh reference | 100 supplied starts, alternate actions |
17
+ | CartPole masspole x2 | FAIL: stale constants | Same 100 starts |
18
+ | CartPole length x2 | FAIL: partly stale update | Mechanism annotation comes from adapter source inspection |
19
+ | CartPole gravity x2 | PASS: consistent | 100 starts, no observed discrepancies |
20
+ | RK4 heavy top, ball joint | FAIL: 23/24 probes below declared order; 1/24 ABSTAIN | Median fine-pair slope 1.95918; conservative geometry, h=.05 |
21
+ | RK4 heavy top, three hinges | PASS: 24/24 probes | Median fine-pair slope 3.86154; healthy geometry control |
22
+ | Reacher post-step observation | FAIL: discrepancy from refreshed map | 24 starts; largest discrepancy 2.39071e-6 |
23
+
24
+ No 4.0.0 engine was installed or tested. No result is inferred for it, for other
25
+ release versions, or for shipped Ant/Humanoid with contacts and actuation.
26
+
27
+ ### Addendum, 14 November 2026: MuJoCo 4.0.1
28
+
29
+ The same protocol and seed were run unchanged with Gymnasium 1.4.0 / MuJoCo 4.0.1
30
+ under Python 3.12.3 (evidence/paper_cases_mj401.json). CartPole results are
31
+ identical. The heavy-top **ball-joint case now PASSes on 24/24 probes** (median
32
+ fine-pair slope 3.915; it was FAIL with 1.959 on 3.16.0), and the hinge control
33
+ still passes (3.862). The Reacher observation check still FAILs (largest
34
+ discrepancy 2.39071e-6). This is a measurement on the conservative heavy-top
35
+ model only; it does not establish where the change occurred between 3.17.0 and
36
+ 4.0.1, and 4.0.0 remains untested.
37
+
38
+ ### Addendum: release-worker isolation bug (fixed before first publication)
39
+
40
+ When simaudit was pip-installed, `compare_releases` put the caller's whole
41
+ site-packages directory on the workers' PYTHONPATH, which could make both workers
42
+ import the caller's NumPy/simulator instead of each interpreter's own versions.
43
+ The validation runs above used a source tree, where only the package directory
44
+ was exposed, so they were not affected. Workers now receive a temporary directory
45
+ containing only the simaudit package, with a regression test. The Acrobot release
46
+ controls were not rerun after this change.
47
+ The Reacher reference shares the observation formula and only checks its cache
48
+ consistency. CartPole's fresh reference rebuilds constants under an explicitly
49
+ supplied parameter contract; direct attribute mutation need not be an upstream
50
+ supported API. A FAIL here is scoped to that comparison.
51
+
52
+ The two runs reuse the same probe design and are not 48 independent starts for
53
+ an engine-wide population claim. The ball-joint abstention is retained. No
54
+ threshold was relaxed to remove it.
55
+
56
+ ## Release comparison and controls from the joint paper
57
+
58
+ Using isolated workers, Gymnasium 1.3.0 versus 1.4.0 Acrobot agreed exactly on
59
+ all recorded first steps. On the same 1.3.0 version, the book-versus-nips control
60
+ was detected (maximum first-step difference 0.00147277) and the mass2=1.3 control
61
+ was detected (0.0609411). Each used 24 paired starts, 5 recorded steps, and the
62
+ first-step threshold 1e-13. This validates detection, not the joint paper's
63
+ algebraic screening, constraint localisation or parameter attribution, which
64
+ are deferred features. The full historical 350-pair matrix was not rerun.
65
+
66
+ ## General-purpose software controls
67
+
68
+ Euler and RK4 scalar ODE controls each had 0 failures and 0 abstentions across
69
+ 100 starts. The two-sided 95% Wilson false-alarm interval per control is
70
+ approximately [0, 0.0370]. This is conditional on those chosen scalar controls,
71
+ not calibration across arbitrary simulators. Float32 order and observation
72
+ controls abstain; declared-noise order controls abstain. Float64 observation
73
+ controls pass. Tests also cover missing capabilities, bad restoration, wrong
74
+ native references, nonfinite trajectories, unknown features, unlogged assignment
75
+ modifications, schema rejection, CLI, subprocess comparison and pytest statuses.
76
+
77
+ Implementation testing exposed two issues which were corrected before final
78
+ measurements: independent float32 arithmetic needed a dtype-aware replay
79
+ comparison floor, and returned mutable buffers needed copying. The frozen
80
+ scientific diagnostic thresholds were not changed. A zero-torque constant-speed
81
+ hinge test was corrected to use a gravity-loaded axis; exact flow correctly
82
+ abstains because there is no truncation error to estimate.
83
+
84
+ ## Packaging and software test result
85
+
86
+ The final suite has 34 passing tests (33 at the 11 November receipt, plus the isolation regression test; 34 pass on Python 3.12.3 with MuJoCo 4.0.1), including the optional MuJoCo tests. A wheel
87
+ and source distribution were built. The wheel was installed without network
88
+ access into a new virtual environment using existing system dependencies, and its
89
+ CLI ran a copied custom-simulator example from /tmp, outside the source tree.
90
+ The installed package imported without loading Gymnasium or MuJoCo, and pytest
91
+ discovered its plugin entry point. This is package isolation, not a clean-room
92
+ reinstallation of all third-party dependencies.
93
+
94
+ Run `python validation/verify_receipt.py` from the repository to check retained
95
+ hashes. The repository receipt is excluded from distributions to avoid a
96
+ self-referential archive hash.
97
+
98
+ ## Reproduce
99
+
100
+ From this package directory, after installing the package:
101
+
102
+ ```bash
103
+ python -m pytest
104
+ python -m build
105
+ PYTHONPATH=validation python validation/run_controls.py \
106
+ --report /tmp/package_controls.json --summary /tmp/false_alarm_controls.json
107
+ PYTHONPATH=src:validation /path/to/simulator/python validation/run_known_cases.py /tmp/paper_cases.json
108
+ PYTHONPATH=src:validation python validation/run_release_cases.py \
109
+ --python-a /path/to/version-a/python --python-b /path/to/version-b/python \
110
+ --out /tmp/release_controls.json
111
+ ```
112
+
113
+ `evidence/validation_receipt.json` records final execution checks and hashes.
114
+ A GitHub Actions workflow is included (.github/workflows/tests.yml); hosted CI had
115
+ not been run when this receipt was written. Stable publication still requires
116
+ external usability tests, a larger held-out control set, a complete dependency
117
+ licence inventory and additional version coverage. The name `simaudit` was
118
+ unregistered on PyPI on 14 November 2026.