feat: add A (AND-junction) and F-system safety instructions#3
Merged
Czarnak merged 2 commits intoJul 20, 2026
Merged
Conversation
…ESTOP1, SFDOOR, FDBACK) Real-world V21 F-programs (fail-safe FBs) hit two gaps in the catalog: - "A" (the AND-junction, FBD's counterpart to the already-supported "O" OR-junction) was entirely missing, so any AND fan-in folded to Unhandled. - The four common F-system safety boxes (ACK_GL, ESTOP1, SFDOOR, FDBACK) were not catalogued, so calls to them folded to Unhandled even though they are boxes like any other system FB (en/eno, optionally instanced). While adding these, found and fixed a related bug: per-pin negation (`<Negated Name="inN"/>` on the junction/box Part itself, distinct from a negated Contact feeding it) was silently dropped for AND/OR junctions and for BOX inputs generally — only Contact/Coil negation was ever applied. Fixed for both categories, plus a regression test for the pre-existing OR-junction gap. Verified against a real V21 safety FB (F_FBD, ~20 networks mixing all of the above): 14 "unknown instruction"/negation-related warnings before the fix, 0 after, with the decoded SCL cross-checked network-by-network against the raw FlgNet XML by hand. No production project data is included here — only synthetic, license-clean test fixtures following the existing test_fold.py pattern (model.* built directly, no XML). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…pins PR Czarnak#3 review found that per-pin negation was still silently dropped in four spots: A/O junction NAND/NOR (Negated out), flip-flop set/reset pins, box en pins, and box output pins read as sub-expressions. Each now wraps the result in Not instead of dropping the inversion, closing the exact "authoritative-looking but wrong" failure mode this decoder is built to avoid. Also corrects the ESTOP1 catalog entry, which listed placeholder in1/in2 pins never observed on that block. Pin list confirmed against a real ESTOP1 v1.6 export: en/E_STOP/ACK_NEC/ACK/TIME_DEL in, Q/Q_DELAY/ACK_REQ/DIAG/eno out. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EsNpUYoWRowQLtXCo1DuZX
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Ran the decoder against a real V21 fail-safe FB (F_FBD, ~20 networks) and hit two catalog gaps:
A(AND-junction) was entirely missing.O(OR-junction) is supported, but its FBD counterpartAfolded toUnhandled— this turned out to be the majority of the warnings (9 of 14), not the F-instructions themselves.ACK_GL,ESTOP1,SFDOOR,FDBACK) were uncatalogued, so calls to them folded toUnhandledeven though they're boxes like any other system FB (en/eno, optionally instanced) — no special-casing needed once catalogued.While wiring these up, found and fixed a related bug: per-pin negation on junction/box Parts was silently dropped.
<Negated Name="inN"/>directly on anA/Ojunction (distinct from a negatedContactfeeding it) — and the equivalent on a BOX's input pins (e.g.FDBACK'sON/QBAD_FIO, which are commonly wired negated) — was never applied. OnlyContact/Coilnegation was handled before. Fixed for bothCategory.AND_JUNCTION/OR_JUNCTION(via a shared_junction_brancheshelper) andCategory.BOXinputs, plus a regression test covering the pre-existingOgap.Verification
A→A(negated)→Srflip-flop chain, and anFDBACKbox with two negated inputs) wire-by-wire against the rawFlgNetXML — decoded SCL matches exactly, including which operand the negation lands on.ruff check .clean;pytest --cov222 passed (3 pre-existing, unrelated Windows-symlink-privilege skips), coverage 90.6% (gate: 80%).model.*objects built directly, following the existingtest_fold.pypattern (no XML fixtures, so no fixture-licensing concerns per CONTRIBUTING.md).Test plan
ruff check .pytest -q --cov=simaticml_decoder --cov-report=term-missing --cov-fail-under=80Co-Authored-By: Claude Sonnet 5 noreply@anthropic.com