chore(deps): Bump openjd-* Rust crates to the 0.6.0 release - #349
Merged
leongdl merged 6 commits intoSep 3, 2026
Merged
Conversation
Move the bindings crate onto the openjd-rs release published by OpenJobDescription/openjd-rs#357: openjd-expr 0.5.0 -> 0.6.0 (breaking) openjd-model 0.5.4 -> 0.6.0 (breaking) openjd-sessions 0.5.4 -> 0.5.5 The breaking part of both minor bumps is openjd-rs#354, "Keep the decimal places of a floatstring range element", the Rust counterpart of OpenJobDescription#345 on this side. `TaskParameter::Float` now carries `Vec<Float64>` rather than `Vec<f64>`, because a `<floatstring>` range element has to keep the scale it was written with: '02.50' renders `2.50`, not `2.5` (Template Schemas §7.5). That reaches Python through `TaskParameterValue`, which renders the preserved spelling verbatim, so the per-task value a command line receives now matches the pure-Python reference. `FloatTaskParameter.range` stays `list[float]` -- it is the numeric introspection view of the resolved definition -- so the conversion takes `Float64::value()` there. openjd-model 0.6.0 also carries openjd-rs#355 (two chunking parity gaps) and openjd-rs#358 (the 512-character cap on a let binding identifier), and openjd-sessions 0.5.5 carries openjd-rs#361 (persist a resolved symbol table supplied by argument). Verified: cargo build --all-targets, cargo clippy --all-targets -D warnings, cargo test and cargo test --doc all pass. The Python suite is 5546 passed with 5 failures that are all gap markers this release closes; they are addressed in the following commit. Signed-off-by: David Leong <116610336+leongdl@users.noreply.github.com>
openjd-rs#355 closed both divergences that
`test/openjd/model_v1/test_known_gaps.py` recorded as strict xfails, so with
`xfail_strict = true` they now fail as xpasses. That file's own rule is to
promote a resolved gap to its proper home rather than drop the marker in place,
so both move to `test_step_param_space_iter.py` beside the rest of
`TestChunksTaskCountOverride`.
- A CONTIGUOUS chunked space supports random access. `it[0]`, `it[1]` and
`it[-1]` answer, indexing observes `chunks_task_count_override`, and one
past the end is still an IndexError. This replaces
`test_a_contiguous_space_refuses_indexing_with_or_without_the_override`,
which asserted the refusal and named this exact swap as its counterpart.
- `chunks_parameter_name` and `chunks_default_task_count` report for any
chunked space, not only an adaptive one, which is what v0 has always done.
Added `test_an_adaptive_space_still_refuses_indexing` as the negative control
and the remaining limitation: an adaptive space has no knowable count, so
`len()` raises ValueError and every index is out of range, while iteration
still yields. Measured, along with everything asserted above, against
openjd-model 0.6.0 before the assertions were written.
Both promoted assertions are falsifiable by the version alone: they were strict
xfails passing on mainline at openjd-model 0.5.4, so they failed there, and the
CI run on 007f212 reports them xpassing at 0.6.0.
`specs/python-model-interface.md` claimed both limitations and pointed at the
xfails by name; it now states the random access that works and the one adaptive
limitation that remains. The `Optional[str]`/`Optional[int]` signatures are
unchanged -- both getters still answer None for a space that is not chunked.
Verified: 5551 passed, 24 skipped, 3 xfailed with the 94% coverage gate
enforced; ruff, black and mypy clean.
`test_known_gaps.py` is now down to one test, which is a passing regression
test rather than a gap. Left where it is rather than widen this change.
Signed-off-by: David Leong <116610336+leongdl@users.noreply.github.com>
`scripts/check_third_party_licenses.sh` fails on a Cargo.lock change alone, and the three crate bumps are exactly what the diff contains: openjd-expr 0.5.0 -> 0.6.0, openjd-model 0.5.4 -> 0.6.0, openjd-sessions 0.5.4 -> 0.5.5. No other line moves, and no transitive dependency changed. Regenerating it needed a portability fix first. `sed -i 's/\r//'` on the EOL normalization line is GNU-only: BSD sed reads the next argument as the backup suffix, so on macOS the script died with `sed: 1: "/var/folders/...": invalid command code f` before writing anything. Rewriting through a temp file behaves identically on both. The failure was not specific to this change -- the script could not be run on macOS at all -- and CI regenerates with the same script, so the committed file and the check stay in agreement. Verified: `scripts/check_third_party_licenses.sh --update` then `scripts/check_third_party_licenses.sh` reports the file up to date, with cargo-about 0.9.2, the version CI installs. Signed-off-by: David Leong <116610336+leongdl@users.noreply.github.com>
leongdl
enabled auto-merge (squash)
September 3, 2026 02:56
`StepParameterSpace(taskParameterDefinitions={"F": {"type": "FLOAT", "range":
["1.50"]}})` rendered the task parameter value `1.5`, while the same element
decoded from a template rendered `1.50`. Review on OpenJobDescription#349 found it; measured, 5 of
6 elements disagreed between the two routes: '1.50'->1.5, '1e3'->1000.0,
'5.'->5.0, '.5'->0.5, '02.50'->2.5.
`task_param_def_from_dict` read every element through `v.str()` and re-emitted
the float variant as a JSON *number*. `Float64` reads a JSON number as a bare
value and a JSON string as a preserved spelling, so the number form threw the
decimal places away -- the thing openjd-rs#354 added `Float64` to carry.
The template makes this distinction with the `<float> | <floatstring>` union, so
the binding now makes it the same way: an element that arrives as a Python `str`
is forwarded as a JSON string, anything else keeps the numeric path. `v.str()`
collapsed the two, which is why the fix is a branch rather than a cast.
Deliberately not widened:
- A Python `float` must not acquire a spelling from `str()`. Measured, both
routes already agree on 1.5, 1000.0 and 0.5, and forwarding '1000.0' as
text would have been a new divergence in the other direction.
- An unparseable element still fails, in `Float64`'s deserializer rather than
here, exactly as it did when this re-emitted a number.
- `FloatTaskParameter.range` stays `list[float]`. It is the numeric
introspection view, so '2.50' still reports 2.5 there while rendering 2.50.
Two of them can compare equal by `.range` and render differently; the spec
now says so rather than the API changing shape.
- A redundant leading zero is still not stripped here. That is a `create_job`
normalization (openjd-model `create_job/ranges.rs`), not part of reading a
resolved value, and constructing the Rust `TaskParameter` directly behaves
the same way -- `Float64`'s deserializer trims whitespace and unsigns zero
but does not strip. So '02.50' given straight to the resolved type keeps its
zero. Pinned by name.
`TestFloatRangeSpellingIsPreserved` covers it: 10 string spellings, 3 float
negative controls, agreement with the template path, the leading-zero
divergence, and the rejection path. Mutation-checked by flipping the new branch
back to the numeric path, which fails 10 of the 16. The two survivors are
labelled in the test as not pinning the fix: '2.5' renders the same either way,
and ' 2.50 ' already took the string path because Rust's f64 parse rejects the
spaces.
Separately measured against openjd-rs#354 itself: all 26 input/expected pairs
from that PR's own assertions render identically through both this repo's
implementations, v0 and v1 -- including '-0.0'->0.0, '0e5', '-0.0E+2'->0.0E+2,
'1e-400', a 403-character 0.000...1, '5.' and '.5'.
Verified: 5567 passed, 24 skipped, 3 xfailed with the 94% coverage gate
enforced; cargo clippy --all-targets -D warnings, cargo fmt --check, cargo test,
ruff, black and mypy all clean.
Signed-off-by: David Leong <116610336+leongdl@users.noreply.github.com>
Four findings from review on OpenJobDescription#349, all against bfa28bc. `__getitem__` now rejects an adaptive space explicitly. Review pointed out that it resolved a negative index against `self.len` — the count `__len__` refuses to report for an adaptive space, on the grounds that it is not knowable — and that `it[-1]` therefore declined only because `get` happened to decline downstream. Confirmed by reading it: `self.len` is captured unconditionally at construction and `__getitem__` had no adaptive check. Since 0.6.0 just extended `get` to contiguous chunked spaces, a later extension to adaptive would have made `it[-1]` answer against a count `len()` still withholds. The guard makes the documented behaviour the enforced one and lets the message name the reason. The message is now the pure-Python reference's, verbatim. The type stays `IndexError` rather than moving to v0's bare `LookupError`: `IndexError` is a `LookupError` subclass, so a caller catching either type is served by both implementations, while changing the type would break anyone catching `IndexError`. Full type parity is a breaking change and is not smuggled into a dependency bump. The spec now records the divergence, which review noted the rewritten text had made read as though the area were at parity. `test_indexing_observes_the_override` had a docstring the previous commit falsified: it said random access needs a non-sequential space and that a contiguous chunked space is always sequential, then pointed at "the test below" — which is now the test proving both clauses wrong. Replaced with the reason the NONCONTIGUOUS choice actually still holds, which review identified correctly: it renders a single-task chunk as a bare `1` where CONTIGUOUS renders `1-1`, and that is what the assertions depend on. `scripts/check_third_party_licenses.sh` no longer creates a second temp file. The `$generated.eol` sibling the previous commit introduced was not registered with the `trap`, so it leaked if the script died between the redirect and the `mv`. Folding `sed` into the redirect that already builds `$generated` drops the file, the `mv` and the portability caveat at once. Review suggested `tr -d`; kept `sed 's/\r//'` because `tr -d` also deletes a CR that is not a line ending, and the point here is EOL normalization. The script still reports the file up to date, so the output is byte-identical. Verified: 5567 passed, 24 skipped, 3 xfailed with the 94% coverage gate; cargo clippy --all-targets -D warnings, cargo fmt, ruff, black, mypy clean; scripts/check_third_party_licenses.sh reports up to date. Removing the new guard fails `test_an_adaptive_space_still_refuses_indexing` and nothing else, from a green baseline of 18 in that class. Signed-off-by: David Leong <116610336+leongdl@users.noreply.github.com>
AlexTranAmz
previously approved these changes
Sep 3, 2026
openjd-model 0.6.0 carries openjd-rs#358, which enforces Template Schemas §3.6.1's 512-character cap on a `let` binding's `<UserIdentifier>`; before it a 513-character name was accepted. The v0 side has covered this since OpenJobDescription#348, in `test/openjd/model_v0/v2023_09/test_let_bindings.py`. The v1 path had nothing, so the bump brought the enforcement with no test on this side to hold it. Measured through `decode_job_template` on both implementations before writing the assertions. 512 characters is accepted and 513 rejected, identically, with `EXPR` alone and with `EXPR` plus `FEATURE_BUNDLE_1`. The accept at 512 with `EXPR` alone is the case worth having. The cap is flat, not §7.1's `<Identifier>` cap of 64 rising to 512 under `FEATURE_BUNDLE_1`, so a fix built on the wrong constant would reject a template the spec permits. A 65-character control covers the same ground from the other side: over the §7.1 cap, under §3.6.1's, and accepted. The two implementations' messages differ in wording, so the assertion is on the error path and the phrase `exceeds 512 characters`, not on the whole string. Verified: 5572 passed, 24 skipped, 3 xfailed with the 94% coverage gate; ruff, black and mypy clean. Signed-off-by: David Leong <116610336+leongdl@users.noreply.github.com>
mwiebe
approved these changes
Sep 3, 2026
seant-aws
approved these changes
Sep 3, 2026
AlexTranAmz
approved these changes
Sep 3, 2026
Merged
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.
Moves the bindings crate onto the openjd-rs release published by OpenJobDescription/openjd-rs#357.
openjd-expropenjd-modelopenjd-sessionsWhat the breaking part is
Both minor bumps are breaking because of openjd-rs#354, "Keep the decimal places of a floatstring range element" — the Rust counterpart of #345 on this side.
TaskParameter::Floatnow carriesVec<Float64>rather thanVec<f64>, because a<floatstring>range element has to keep the scale it was written with:'02.50'renders2.50, not2.5(Template Schemas §7.5).That reaches Python through
TaskParameterValue, which renders the preserved spelling verbatim, so the per-task value a command line receives fromopenjd.model._v1now matches the pure-Python reference.openjd-model0.6.0 also carries openjd-rs#355 (two chunking parity gaps) and openjd-rs#358 (the 512-character cap on a let binding identifier).openjd-sessions0.5.5 carries openjd-rs#361 (persist a resolved symbol table supplied by argument).Parity with openjd-rs#354
Every input/expected pair in that PR's own assertions — its
value.rsunit tests, theranges.rsleading-zero tests, andtest_step_param_space_iter.rs— was run through both implementations this repo ships. 26/26 agree, v0 and v1, including-0.0→0.0,-0.00→0.00,0e5,00e5→0e5,-0.0E+2→0.0E+2,0.0000001,1e-400, a 403-character0.000…1," 2.50 "→2.50,5.→5.and.5→.5.Every fix in the release, and how it was verified
The release's claimed changes were reconciled against a source diff of the old and new crates, so an unlisted change could not hide.
openjd-exprtouched onlyvalue.rs;openjd-modeltouchedranges.rs,job/mod.rs,step_param_space.rsandtemplate/validate_v2023_09/format_strings.rs;openjd-sessionstouched onlysession.rs. Every one maps to a listed fix — nothing unclaimed.decode_job_template+create_job+StepParameterSpaceIterator, all 26 input/expected pairs from that PR's own assertionsStepParameterSpaceIteratorindexing andchunks_*gettersletidentifierdecode_job_templateon both implementationsEXPRalone and withFEATURE_BUNDLE_1; no test existed on the v1 side, so one was addedopenjd-rs#361 is an
openjd-sessionschange, and this repo has no sessions tests:test/holdsexpr,model_v0andmodel_v1only, and the Python wrapper plus its suite live in openjd-sessions-for-python. What is confirmed here is that the binding reaches the fixed path —rust-bindings/src/sessions/session.rs:494forwards the argument assession.enter_environment(&env, resolved.as_ref(), Some(&env_id), env_ref), which is exactly theresolved_symtabargument route the fix made equivalent to the field. The fix is internal to the crate, so it needs no binding change. End-to-end coverage of a wrap environment'sParam.*reaching its RFC 0008 hooks belongs to the sibling repo and is not verified by this PR.Changes beyond the version pins
FloatTaskParameterconversion.Float64::value()where the binding wants a number.FloatTaskParameter.rangestayslist[float]— it is the numeric introspection view, not the render path.A FLOAT range element built from Python keeps its spelling (review finding).
StepParameterSpace(taskParameterDefinitions={"F": {"type": "FLOAT", "range": ["1.50"]}})rendered1.5where the template rendered1.50; measured, 5 of 6 elements disagreed. The cause was re-emitting the element as a JSON number, whichFloat64reads as a bare value. A Pythonstris now forwarded as a JSON string, reproducing the template's own<float> | <floatstring>distinction. Not made unconditional: a Pythonfloatmust not acquire a spelling fromstr(), and both routes already agree on1.5,1000.0and0.5.The adaptive indexing refusal is enforced, not incidental (review finding).
__getitem__resolved a negative index againstself.len, the count__len__withholds for an adaptive space, soit[-1]declined only becausegetdeclined downstream. It now rejects an adaptive space up front, with the pure-Python reference's message so "unknown count" is distinguishable from "past the end". The type staysIndexErrorrather than moving to v0's bareLookupError;IndexErroris aLookupError, so callers catching either are served by both implementations, and changing the type would breakexcept IndexError. The divergence is recorded in the spec.Two chunking gaps close, so tests move. openjd-rs#355 resolved both divergences
test_known_gaps.pyrecorded asstrictxfails, whichxfail_strictreports as failures. Following that file's own rule, both were promoted totest_step_param_space_iter.py:CONTIGUOUSchunked space now supports random access, observingchunks_task_count_override, with one past the end still anIndexError. Replacestest_a_contiguous_space_refuses_indexing_with_or_without_the_override, which asserted the refusal and named this swap as its counterpart.chunks_parameter_nameandchunks_default_task_countnow report for any chunked space, not only an adaptive one, which is what v0 has always done.Nothing here is a chunking regression — every assertion moved toward the v0 reference.
THIRD-PARTY-LICENSES.txtregenerated; the diff is exactly the three crate versions, no transitive dependency moved. That needed a portability fix inscripts/check_third_party_licenses.sh:sed -i 's/\r//'is GNU-only and killed the script on macOS before it wrote anything.sednow folds into the redirect that already builds the file, which also removes a temp file that was not registered with thetrap(review finding).Verification
ruff,black --check,mypyclean.cargo build --all-targets,cargo clippy --all-targets -- -D warnings,cargo fmt --check,cargo test,cargo test --docall pass.scripts/check_third_party_licenses.shreports the file up to date, cargo-about 0.9.2, the version CI installs.test_an_adaptive_space_still_refuses_indexingand nothing else.Not verified locally: Windows and Linux. Everything above was run on macOS; CI covers the other two legs. One Windows leg failed earlier on
test_pwsh_string_simple_roundtrip, a pre-existing PowerShell-startupsubprocess.TimeoutExpiredunrelated to this change.