Skip to content

Re-vendor RuleMonkey 3.9.0 to 3.10.0 - #480

Merged
wshlavacek merged 2 commits into
mainfrom
revendor-rulemonkey-3.10.0
Aug 23, 2026
Merged

Re-vendor RuleMonkey 3.9.0 to 3.10.0#480
wshlavacek merged 2 commits into
mainfrom
revendor-rulemonkey-3.10.0

Conversation

@wshlavacek

Copy link
Copy Markdown
Collaborator

Refreshes the vendored RuleMonkey from 3.9.0 to 3.10.0, for 0.15.0.

Why now

The vendored copy was eleven commits behind. Three of those change what a model
does under method="rm", and one of them can turn a model that runs today into one
that refuses, so this belongs in a release that is already a major bump rather
than in a patch.

What changes for users

TotalRate now warns at load, and is refused for one specific shape. BioNetGen
does not implement TotalRate for network simulations, so there is no BNG2 result
to check such a model against, and NFsim disagrees with RuleMonkey on it. NFsim
expands a rule whose reactant pattern has interchangeable components into one
reaction class per permutation, and under TotalRate every class returns the whole
rate, so the rule runs at the rate times the number of populated permutations.
Upstream measured 1.00x, 2.02x and 2.98x as free sites go from one to three. BNG2
implies a third number again. All three disagree, so RuleMonkey refuses those
rules rather than picking one reading silently. The test is narrow on purpose: a
TotalRate rule is refused only when a reactant pattern touches a component whose
molecule type declares two or more of that name. Everything else warns and runs.

A rate law built on reactant_N() had a propensity of zero, so any rule using one
never fired at all. It is now resolved against the rule asking for it.

A session counted every tracked observable twice.

The rest is either a fix to a shape our corpus does not write, or performance
work with no behavioural component.

The two-repo part, which is the awkward bit

This refresh could not run at all until richardposner/RuleMonkey#78 merged.
RuleMonkey keeps its own copy of bngsim's expression evaluator for standalone
builds, and the EXPRTK_SYNC_FILES guard compares that copy against this tree and
fails closed. The copy was pinned to a bngsim commit predating the mratio work of
issues #451, #453 and #456, so the guard refused with:

RuleMonkey standalone ExprTk/bngsim_expr vendoring has drifted from this
BNGsim tree.

That upstream refresh changes nothing here. Inside a bngsim build CMake links the
host bngsim::expression target and the vendored copy is never compiled, which is
exactly why the drift went unnoticed for so long. It did mean standalone
RuleMonkey was still evaluating mratio with the version that can be silently
wrong, which is the reason it was worth landing upstream.

I added a note recording this ordering to scripts/RULEMONKEY_VENDORING.md, whose
Current Baseline was also stale. It named commit 13e9f636 while VENDOR.json said
1d14160.

One small cleanup

VENDOR.json recorded a previous session's scratch directory as local_checkout.
This refresh was run from /tmp/rulemonkey-vendor-candidate, the path the vendoring
doc prescribes, so that record is now a stable path rather than a machine-specific
one.

Testing

Full Python suite against the new tree, and the targeted suites the vendoring doc
names:

python -m pytest python/tests/

5612 passed, 24 skipped, nothing failed. The count is 9 higher than before
because #478 landed its own tests on main in the meantime.

python -m pytest python/tests/test_rulemonkey.py python/tests/test_timeout.py \
                 python/tests/test_exprtk_vendoring.py

63 passed. The changelog and vendoring lint suites were run separately after the
CHANGELOG.md and RULEMONKEY_VENDORING.md edits, since those came after the full
run: 35 passed.

The wheel smoke that the vendoring doc names as the packaging truth for
RuleMonkeySession is running and I will add its result as a comment.

Verified separately that the vendored tree carries no bngsim_expr directory and
that its CMakeLists still takes the if(TARGET bngsim::expression) handoff, which
is the guardrail against duplicate ExprTkEvaluator symbols.

Not included

RuleWorld/nfsim#92 is still open, so the NFsim carry queue is untouched and #428
stays open as its tracker.

The vendored copy was eleven commits behind. Three of those change what a model
does under method="rm", and one can turn a model that runs today into one that
refuses, so this belongs in a release that is already a major bump.

TotalRate now warns at load and is refused for one shape. BioNetGen does not
implement TotalRate for network simulations, so there is no BNG2 result to check
such a model against, and NFsim disagrees with RuleMonkey on it. NFsim expands a
rule whose reactant pattern has interchangeable components into one reaction
class per permutation, and under TotalRate every class returns the whole rate, so
the rule runs at the rate times the number of populated permutations. Upstream
measured 1.00x, 2.02x and 2.98x as free sites go from one to three, and BNG2
implies a third number again. All three disagree, so RuleMonkey refuses those
rules rather than picking a reading silently. The test is narrow on purpose. A
TotalRate rule is refused only when a reactant pattern touches a component whose
molecule type declares two or more of that name. Everything else warns and runs.

A rate law built on reactant_N() had a propensity of zero, so any rule using one
never fired. It is now resolved against the rule asking for it.

A session counted every tracked observable twice.

The rest is either a fix to a shape our corpus does not write or performance work
with no behavioural component.

This refresh could not run until richardposner/RuleMonkey#78 merged. RuleMonkey
keeps its own copy of the bngsim expression evaluator for standalone builds, and
the EXPRTK_SYNC_FILES guard compares that copy against this tree and fails
closed. It was pinned to a bngsim commit predating the mratio work of issues
#451, #453 and #456. That upstream refresh changes nothing here, because inside a
bngsim build CMake links the host bngsim::expression target and the vendored copy
is never compiled. That is also why the drift went unnoticed. The ordering is now
recorded in scripts/RULEMONKEY_VENDORING.md, whose baseline was stale as well: it
named commit 13e9f636 while VENDOR.json said 1d14160.

VENDOR.json had recorded a previous session's scratch directory as
local_checkout. This refresh ran from /tmp/rulemonkey-vendor-candidate, the path
the vendoring doc prescribes, so that record is a stable path now.

Full Python suite: 5612 passed, 24 skipped.
scripts/local_ci.py writes scripts/_reports/ and a
scripts/local_ci_report-<platform>-<pytag>.md next to itself. Neither has ever
been committed and neither should be, since both are machine specific. They were
not ignored either, so running the wheel smoke that RULEMONKEY_VENDORING.md asks
for leaves two untracked paths sitting in git status, one of them a directory.

Found by running that step for this pull request.
@wshlavacek

Copy link
Copy Markdown
Collaborator Author

Wheel smoke result, the packaging check RULEMONKEY_VENDORING.md asks for:

uv run python scripts/local_ci.py wheel --python 3.12

build stamp            PASS pybind11=3.1.0 commit=baf5b4aea271
capabilities           PASS features={'nfsim': True, 'rulemonkey': True, ...}
.net+ODE               PASS shape=(11,2)
SBML+ODE               PASS shape=(11,3)
NFsim session          PASS
RuleMonkey session     PASS
Antimony               PASS shape=(11,1)

ALL PASS

RuleMonkey session PASS is the line that matters here, since it exercises the
packaged RuleMonkeySession flow rather than the editable build. The build stamp
confirms it built this branch.

I also added a second commit while running that step. scripts/local_ci.py writes
scripts/_reports/ and a scripts/local_ci_report--.md next to
itself, and neither was ignored, so the documented validation step leaves two
untracked paths in git status. Neither has ever been committed. They are now
ignored.

@wshlavacek
wshlavacek merged commit 67da6f3 into main Aug 23, 2026
5 checks passed
@wshlavacek
wshlavacek deleted the revendor-rulemonkey-3.10.0 branch August 23, 2026 17:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant