Skip to content

chore(release): 0.11.9 - #354

Merged
leongdl merged 2 commits into
mainlinefrom
bump/0.11.9
Sep 4, 2026
Merged

chore(release): 0.11.9#354
leongdl merged 2 commits into
mainlinefrom
bump/0.11.9

Conversation

@client-software-ci

@client-software-ci client-software-ci commented Sep 4, 2026

Copy link
Copy Markdown
Collaborator

0.11.9 (2026-09-04)

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. (fix: coerce LIST[BOOL] items per RFC 0007 §2.15 #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 fix: Forward the create-time step symbol table to openjd-sessions openjd-cli#237. (fix: Evaluate step-level let bindings in template scope #341)

Signed-off-by: client-software-ci <129794699+client-software-ci@users.noreply.github.com>
AlexTranAmz
AlexTranAmz previously approved these changes Sep 4, 2026
Comment thread CHANGELOG.md
Comment thread CHANGELOG.md Outdated


### Bug Fixes
* coerce LIST[BOOL] items per RFC 0007 §2.15 (#352) ([`105dff2`](https://github.com/OpenJobDescription/openjd-model-for-python/commit/105dff25abc4dfc6970945d881e119438e04fb6c))

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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. b136693 also 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.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NA.

Comment thread CHANGELOG.md Outdated

### 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))

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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>
@leongdl
leongdl enabled auto-merge (squash) September 4, 2026 03:42
Comment thread CHANGELOG.md

### 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)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 let and references it from the step's script, this Job alone is not enough to run the step — the session has no binding for the name and the action fails with Undefined 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 variable for 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.

@leongdl
leongdl disabled auto-merge September 4, 2026 03:45
Comment thread CHANGELOG.md

### 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)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 let that the step's script references, then this Job is not sufficient to run the step [...] Use create_job_with_symbol_tables instead 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-level let values.

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-scope let referenced from its script: switch to create_job_with_symbol_tables() and forward step_symbol_tables[step_name] to the session. A caller that only inspects the Job (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.

@leongdl
leongdl merged commit 2726bbc into mainline Sep 4, 2026
31 checks passed
@leongdl
leongdl deleted the bump/0.11.9 branch September 4, 2026 03:45
Comment thread CHANGELOG.md
@@ -1,3 +1,11 @@
## 0.11.9 (2026-09-04)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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:

  1. Set mode = "update" with an insertion_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.
  2. 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 because b136693 retained six fix: subject lines through the squash.
  3. Split the files — keep a hand-maintained CHANGELOG.md and point PSR at a generated CHANGELOG.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").

Comment thread CHANGELOG.md


### 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)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 with List 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 0 and 1

_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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants