This release adds snapshot-based diagnosis and guided recovery to pyrung. Given a faulted machine's tag dump (like from a Click PLC 'Read Data from PLC', why() traces the cause and how() finds the shortest path to your target state, sub-second, even through a full PackML state machine.
Combined with always()/never() (formerly prove()), the toolchain now covers the full diagnostic loop: what's wrong → how do I fix it → prove it can't happen again.
Highlights
plc.why(*tags)— backward reachability from a frozen snapshot. Scan history not neededplc.how(condition)— minimum input-change path via waypoint-decomposed BFS with heuristic domain seeding - nerd talk for 'you don't need to annotate your Tags with min/max/choices= to use how.how(StateCurrent == EXECUTE)on the `packml_bench.py' model runs sub-second.always()/never()— replacesprove(), with free-input factoring andsplit_atdecomposition- Agent workspace —
ladder_to_pyrung_project()emits CLAUDE.md, skills, and test scaffold - 3 breaking changes (prove→always, DAP reload→autoReload, 1-indexed rungs in print() outputs)
- 14 prover/validator soundness fixes
See CHANGELOG.md for the full list.
Test plan
-
make test— 4067 passed -
make lint— clean -
make docs-build— strict, no warnings -
make test-soundness— prover agreement checks -
make test-fuzz— fuzzer suite - Tag v0.10.0 after merge