chore(release): 0.11.9 - #354
Conversation
Signed-off-by: client-software-ci <129794699+client-software-ci@users.noreply.github.com>
|
|
||
|
|
||
| ### Bug Fixes | ||
| * coerce LIST[BOOL] items per RFC 0007 §2.15 (#352) ([`105dff2`](https://github.com/OpenJobDescription/openjd-model-for-python/commit/105dff25abc4dfc6970945d881e119438e04fb6c)) |
There was a problem hiding this comment.
Every entry in this section is duplicated or misattributed, and previous releases do not look like this.
Concretely, in these 8 lines:
- Lines 6-7 are the same entry twice, once with the PR suffix
(#352)and once without. Same for lines 8-9 (#341). - Lines 10-13 are the intermediate commit subjects from inside the squashed
b136693: "Record the template-scope let boundary at the merge, and verify it", "Never lower the template-scope let marker", "Stop merging step-level let into the script". Those describe fixes to code introduced earlier on the same branch. They are not user-visible changes, and several of them cancel each other out. A reader sees "Evaluate step-level let bindings in template scope" and "Stop merging step-level let into the script" as two separate fixes in one release. - Every one of lines 10-13 links to
b136693, the squash commit, so four distinct bullets point at the same hash.b136693also has subject "Evaluate step-level let bindings in template scope", which is why lines 8-9 duplicate it.
The cause is that the parser walked the *-prefixed bullet lines in the squashed commit body as if each were its own commit. Compare the 0.11.8 and 0.11.7 sections just below (lines 16-33): each is one bullet per merged PR, no duplicates, and 0.11.8 uses prose descriptions with a (#NNN) suffix and no hash link at all, so this section is also stylistically inconsistent with the two preceding it.
Suggest collapsing to one bullet per merged PR and dropping the intra-branch commit subjects, keeping only the #352 and #341 entries.
|
|
||
| ### Bug Fixes | ||
| * coerce LIST[BOOL] items per RFC 0007 §2.15 (#352) ([`105dff2`](https://github.com/OpenJobDescription/openjd-model-for-python/commit/105dff25abc4dfc6970945d881e119438e04fb6c)) | ||
| * coerce LIST[BOOL] items per RFC 0007 §2.15 ([`105dff2`](https://github.com/OpenJobDescription/openjd-model-for-python/commit/105dff25abc4dfc6970945d881e119438e04fb6c)) |
There was a problem hiding this comment.
The #352 commit body also declares a behavior change that this one-line entry does not convey:
Behavior change: created-Job LIST[BOOL] values are now canonical
booleans (e.g. ["yes","no"] stores and interpolates as true/false),
matching openjd-rs.
A consumer that reads a created Job's LIST[BOOL] parameter and relied on getting back the author's original spellings will now see true/false. "coerce LIST[BOOL] items per RFC 0007 §2.15" reads as a validation tightening, not as a change to stored values.
Worth expanding this bullet to state the observable change, in the prose style the 0.11.8 section uses (lines 20-24).
Rewrite the generated 0.11.9 block for users of the library. The generator emits one line per commit, so PR #341 rendered as six near-duplicate maintainer-facing bullets and PR #352 rendered twice. Each PR now gets one entry that states the observable behaviour change, the symptom it replaces, and for #341 the migration a consumer has to make. Commit hashes resolved to PR links. Signed-off-by: David Leong <116610336+leongdl@users.noreply.github.com>
|
|
||
| ### Bug Fixes | ||
| * A `LIST[BOOL]` job parameter now holds real booleans in the created job, so a list item accepts every spelling Template Schemas §2.15 allows for a scalar `BOOL`: the case-insensitive strings `true`/`yes`/`on`/`1` and `false`/`no`/`off`/`0`, and the numbers `0` and `1`. A mixed list such as `["yes", 0, true]` previously failed to validate with `List contains incompatible types`, and a uniform list such as `["yes", "no"]` was accepted as a list of strings and then failed only once a boolean operator touched an element. `["yes", "no"]` now interpolates as `true`/`false`. A decoded template is unchanged and still round-trips the spellings its author wrote. (#352) | ||
| * A step's template-scope `let` (Template Schemas §3.6) is resolved once, at job creation, using POSIX path format so a created job does not depend on the host that created it. It is no longer merged into the script's own `let`. The merge left the bindings to be evaluated a second time in the host's format when the session ran, and that second value overwrote the first: on Windows, `startswith(path("/foo/bar"), "/foo")` went from true at job creation to false in the session. This is a breaking change for a consumer that calls `StepTemplate.resolve_syntax_sugar()`: the step's resolved bindings now travel in `create_job_with_symbol_tables(...).step_symbol_tables[step_name]` and must be forwarded to the session that runs the step. A consumer that does not forward them loses step-level bindings silently rather than failing. `openjd-cli` forwards them as of OpenJobDescription/openjd-cli#237. (#341) |
There was a problem hiding this comment.
The failure mode described here is the opposite of what the code documents.
This entry states:
A consumer that does not forward them loses step-level bindings silently rather than failing.
But create_job()'s own docstring (src/openjd/model/_create_job.py:577-583) says the failure is loud, not silent:
So for a template that declares a step-level
letand references it from the step's script, thisJobalone is not enough to run the step — the session has no binding for the name and the action fails withUndefined variable.
These cannot both be right, and the difference matters a lot to a reader deciding how urgently to migrate. "Silently loses bindings" reads as wrong results with no error — the worst case, requiring an audit of every job already created. "Fails with Undefined variable" reads as a hard error you cannot miss — unpleasant but self-announcing, and safe to discover at runtime.
Given the docstring is specific about the exact error string, the docstring is likely the accurate one and this line is the error. Suggest matching it, e.g.:
A consumer that does not forward them will see the step's action fail at session time with
Undefined variablefor the binding name.
If instead there really is a silent-loss path (for example when the session happens to define the same name in another scope), it would be worth naming that condition here rather than describing silence as the general case, since it contradicts the primary public API's documented behaviour.
|
|
||
| ### Bug Fixes | ||
| * A `LIST[BOOL]` job parameter now holds real booleans in the created job, so a list item accepts every spelling Template Schemas §2.15 allows for a scalar `BOOL`: the case-insensitive strings `true`/`yes`/`on`/`1` and `false`/`no`/`off`/`0`, and the numbers `0` and `1`. A mixed list such as `["yes", 0, true]` previously failed to validate with `List contains incompatible types`, and a uniform list such as `["yes", "no"]` was accepted as a list of strings and then failed only once a boolean operator touched an element. `["yes", "no"]` now interpolates as `true`/`false`. A decoded template is unchanged and still round-trips the spellings its author wrote. (#352) | ||
| * A step's template-scope `let` (Template Schemas §3.6) is resolved once, at job creation, using POSIX path format so a created job does not depend on the host that created it. It is no longer merged into the script's own `let`. The merge left the bindings to be evaluated a second time in the host's format when the session ran, and that second value overwrote the first: on Windows, `startswith(path("/foo/bar"), "/foo")` went from true at job creation to false in the session. This is a breaking change for a consumer that calls `StepTemplate.resolve_syntax_sugar()`: the step's resolved bindings now travel in `create_job_with_symbol_tables(...).step_symbol_tables[step_name]` and must be forwarded to the session that runs the step. A consumer that does not forward them loses step-level bindings silently rather than failing. `openjd-cli` forwards them as of OpenJobDescription/openjd-cli#237. (#341) |
There was a problem hiding this comment.
The breaking change is scoped to the wrong audience — it understates who has to migrate.
This is a breaking change for a consumer that calls
StepTemplate.resolve_syntax_sugar()
resolve_syntax_sugar() is a niche entry point. Grepping the package, the only in-tree caller is the job-creation hook itself (v2023_09/_model.py:3576); it is not re-exported as a standalone function, so a consumer reaching it directly is rare. A reader who does not call it will read this line and conclude they are unaffected.
But the project's own docs say the affected API is create_job() — the primary public entry point, used in the README's main example. README.md:213-221:
If any of the job's steps declares a template-scope
letthat the step's script references, then thisJobis not sufficient to run the step [...] Usecreate_job_with_symbol_tablesinstead and forward the step's entry
and create_job()'s docstring at _create_job.py:585-587 says the same. The commit footer on b136693 also frames it as create_job(), not resolve_syntax_sugar():
create_job()no longer returns a Job carrying evaluated step-levelletvalues.
So the population that must migrate is "anyone who calls create_job() and then runs the resulting job, where a step declares a template-scope let its script references" — which includes openjd-cli and, presumably, the Deadline Cloud worker agent. Naming resolve_syntax_sugar() instead points readers away from the check they actually need to perform.
Suggest leading with create_job() and the precondition, e.g.:
Breaking for a caller that runs a job created with
create_job()when a step declares a template-scopeletreferenced from its script: switch tocreate_job_with_symbol_tables()and forwardstep_symbol_tables[step_name]to the session. A caller that only inspects theJob(StepDependencyGraph,StepParameterSpaceIterator,hostRequirements) is unaffected.
The "only inspects the Job is unaffected" carve-out is worth keeping from the docstring — it is what lets most readers stop reading.
| @@ -1,3 +1,11 @@ | |||
| ## 0.11.9 (2026-09-04) | |||
There was a problem hiding this comment.
This hand-written prose will be destroyed the next time a release is cut.
.semantic_release/CHANGELOG.md.j2:1 opens with:
{% for version, release in context.history.released.items() %}The template iterates every released version, not just the new one — so it renders the entire CHANGELOG.md from scratch on each run. Combined with the config in pyproject.toml:210-211:
[tool.semantic_release.changelog]
template_dir = ".semantic_release"there is no mode = "update" and no insertion_flag, so python-semantic-release stays in its default init mode: full regeneration, overwriting the file. The next release (0.11.10) will re-derive the 0.11.9 section from commit.commit.summary and restore exactly the six near-duplicate maintainer-facing bullets this commit set out to remove, discarding both carefully written entries.
So the improvement here is real but has a lifetime of one release. Worth considering one of:
- Set
mode = "update"with aninsertion_flag, so PSR only prepends new sections and leaves prior hand-edited ones alone. This makes manual curation durable and is the smallest config change. - Curate at the commit-message level instead — squash each PR to a single
fix:commit whose summary is the user-facing sentence, so the generator produces the desired output natively. The six bullets exist becauseb136693retained sixfix:subject lines through the squash. - Split the files — keep a hand-maintained
CHANGELOG.mdand point PSR at a generatedCHANGELOG.generated.md.
Without one of these, this PR is worth treating as a one-off patch rather than a fix to the release notes. Option 1 or 2 also resolves the root cause noted in the commit message ("The generator emits one line per commit").
|
|
||
|
|
||
| ### Bug Fixes | ||
| * A `LIST[BOOL]` job parameter now holds real booleans in the created job, so a list item accepts every spelling Template Schemas §2.15 allows for a scalar `BOOL`: the case-insensitive strings `true`/`yes`/`on`/`1` and `false`/`no`/`off`/`0`, and the numbers `0` and `1`. A mixed list such as `["yes", 0, true]` previously failed to validate with `List contains incompatible types`, and a uniform list such as `["yes", "no"]` was accepted as a list of strings and then failed only once a boolean operator touched an element. `["yes", "no"]` now interpolates as `true`/`false`. A decoded template is unchanged and still round-trips the spellings its author wrote. (#352) |
There was a problem hiding this comment.
Two accuracy problems in this entry.
1. "failed to validate" attributes the mixed-list failure to the wrong stage.
A mixed list such as
["yes", 0, true]previously failed to validate withList contains incompatible types
That message does not come from validation. List contains incompatible types is raised by ExprValue([...]) construction in the expression engine — see test/openjd/expr/test_lists.py:822-841, which pins it as a TypeError from list construction, and test_unresolved_eval.py:351. The #352 commit message agrees, saying heterogeneous lists "failed expression evaluation with 'List contains incompatible types'".
The distinction matters because it changes when a template author finds out. "Failed to validate" implies decode/create_job rejected the template up front. In reality it got through creation and blew up later, at interpolation — the same late-failure mode the entry correctly describes for the uniform case two clauses later. As written the entry claims the two cases failed at different stages, when they both failed at the same one.
Suggest: ...previously failed at expression evaluation with ..., which also makes the parallel with the uniform case explicit.
2. The accepted-spellings list omits floats.
and the numbers
0and1
_coerce_bool_value (src/openjd/model/_bool_coercion.py:22-25) also accepts floats:
if isinstance(value, float):
if value in (0.0, 1.0):
return bool(value)
raise ValueError("BOOL value as a float must be 0.0 or 1.0.")Since the sentence is framed as "every spelling ... allows", an author reading it would reasonably conclude [0.0, 1.0] is rejected when it is accepted. Suggest the numbers 0/1 and 0.0/1.0.
0.11.9 (2026-09-04)
Bug Fixes
LIST[BOOL]job parameter now holds real booleans in the created job, so a list item accepts every spelling Template Schemas §2.15 allows for a scalarBOOL: the case-insensitive stringstrue/yes/on/1andfalse/no/off/0, and the numbers0and1. A mixed list such as["yes", 0, true]previously failed to validate withList contains incompatible types, and a uniform list such as["yes", "no"]was accepted as a list of strings and then failed only once a boolean operator touched an element.["yes", "no"]now interpolates astrue/false. A decoded template is unchanged and still round-trips the spellings its author wrote. (fix: coerce LIST[BOOL] items per RFC 0007 §2.15 #352)let(Template Schemas §3.6) is resolved once, at job creation, using POSIX path format so a created job does not depend on the host that created it. It is no longer merged into the script's ownlet. The merge left the bindings to be evaluated a second time in the host's format when the session ran, and that second value overwrote the first: on Windows,startswith(path("/foo/bar"), "/foo")went from true at job creation to false in the session. This is a breaking change for a consumer that callsStepTemplate.resolve_syntax_sugar(): the step's resolved bindings now travel increate_job_with_symbol_tables(...).step_symbol_tables[step_name]and must be forwarded to the session that runs the step. A consumer that does not forward them loses step-level bindings silently rather than failing.openjd-cliforwards them as of fix: Forward the create-time step symbol table to openjd-sessions openjd-cli#237. (fix: Evaluate step-level let bindings in template scope #341)