Skip to content

feat!: Implement FEATURE_BUNDLE_1 RFC 0004#258

Merged
mwiebe merged 1 commit intoOpenJobDescription:mainlinefrom
mwiebe:implement-rfc-0004
Feb 2, 2026
Merged

feat!: Implement FEATURE_BUNDLE_1 RFC 0004#258
mwiebe merged 1 commit intoOpenJobDescription:mainlinefrom
mwiebe:implement-rfc-0004

Conversation

@mwiebe
Copy link
Contributor

@mwiebe mwiebe commented Jan 30, 2026

What was the problem/requirement? (What/Why)

RFC 0004 was accepted 1/9, and needs implementation in openjd-model, openjd-sessions, etc.

What was the solution? (How)

Implement the extension in the model parsing. For the syntax sugar, this also includes a new method on the StepTemplate that de-sugars it into the syntax without the sugar.

What is the impact of this change?

Progress towards this extension being available for use.

How was this change tested?

This change introduces unit tests for the extension.

I used the following prompt for LLM evaluation of this code change against RFC 0004 in openjd-specifications:

You are a helpful RFC conformance reviewer. Another agent has
implemented RFC 0004, along with tests, in the most recent commit. Your
job is to carefully inspect the RFC, the RFC-specific details in the
OpenJD spec, and look at all the code changes to evaluate compliance.
Produce a report on the quality of the implementation. How well does it
conform? Give each relevant section/subsection of the spec a score. Also
look at the unit tests and evaluate that it is covering all edge cases
of the spec. Write your report to the file CONFORMANCE_REPORT.md.

All code also reviewed by hand.

Was this change documented?

Extension documented in openjd-specifications, this change adds comments/docstrings as appropriate.

Is this a breaking change?

Yes, in a subtle way with some fields that can now be FormatString instead of just int.

BREAKING CHANGE: The types of some model class fields are extended from
Optional[int] to Optional[int | FormatString], so downstream code
that relies on those types can fail type checking.

Does this change impact security?

No.


By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.

@mwiebe mwiebe requested a review from a team as a code owner January 30, 2026 19:18
@leongdl leongdl self-assigned this Jan 30, 2026
jericht
jericht previously approved these changes Jan 30, 2026
JobName = Annotated[
str,
StringConstraints(min_length=1, max_length=128, strict=True, pattern=_standard_string_regex),
StringConstraints(min_length=1, max_length=512, strict=True, pattern=_standard_string_regex),

Choose a reason for hiding this comment

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

Have you kept this as a buffer cz of comment in the code above?

# Max length is validated after resolution in Job model, not here
# because the template name can contain format strings

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The bounds that we put in the type annotations always apply when validating/parsing an input with pydantic, so the upper limit has to be the maximum of upper limits supported. Later, it is dynamically checked against the extension-specific limit.

if v is None:
return v
context = cast(Optional[ModelParsingContext], info.context)
max_len = 256 if context and "FEATURE_BUNDLE_1" in context.extensions else 64

Choose a reason for hiding this comment

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

nit: maybe using constants for the constraints would be better here so its easy to update

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think when you apply LLM code prompting, this convention that was true before may be reversed now - with the values directly here there are fewer indirections that are necessary to cross-validate against the written spec, for example.

Choose a reason for hiding this comment

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

Ah well this is subjective I would rather teach the LLMs to follow the convention to keep the code clean :)) but non-blocking nonetheless, approved!

@classmethod
def _validate_environment_name(cls, v: str, info: ValidationInfo) -> str:
context = cast(Optional[ModelParsingContext], info.context)
max_len = 512 if context and "FEATURE_BUNDLE_1" in context.extensions else 64

Choose a reason for hiding this comment

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

nit: Same as above, maybe using constants would be better here

@mwiebe mwiebe force-pushed the implement-rfc-0004 branch from 4db2be9 to 76aef33 Compare January 30, 2026 21:49
I used the following prompt for LLM evaluation of this code change
against RFC 0004 in openjd-specifications:

> You are a helpful RFC conformance reviewer. Another agent has
> implemented RFC 0004, along with tests, in the most recent commit. Your
> job is to carefully inspect the RFC, the RFC-specific details in the
> OpenJD spec, and look at all the code changes to evaluate compliance.
> Produce a report on the quality of the implementation. How well does it
> conform? Give each relevant section/subsection of the spec a score. Also
> look at the unit tests and evaluate that it is covering all edge cases
> of the spec. Write your report to the file CONFORMANCE_REPORT.md.

All code also reviewed by hand.

BREAKING CHANGE: The types of some model class fields are extended from
    Optional[int] to Optional[int | FormatString], so downstream code
    that relies on those types can fail type checking.

Signed-off-by: Mark <399551+mwiebe@users.noreply.github.com>
@mwiebe mwiebe force-pushed the implement-rfc-0004 branch from 76aef33 to 8449d03 Compare January 30, 2026 22:16
@mwiebe mwiebe changed the title feat: Implement FEATURE_BUNDLE_1 RFC 0004 feat!: Implement FEATURE_BUNDLE_1 RFC 0004 Jan 30, 2026
@sonarqubecloud
Copy link

Quality Gate Failed Quality Gate failed

Failed conditions
3.9% Duplication on New Code (required ≤ 3%)
C Reliability Rating on New Code (required ≥ A)

See analysis details on SonarQube Cloud

Catch issues before they fail your Quality Gate with our IDE extension SonarQube for IDE


SUPPORTED_NAME = "SUPPORTED_NAME"
ANOTHER_SUPPORTED_NAME = "ANOTHER_SUPPORTED_NAME"
FEATURE_BUNDLE_1 = "FEATURE_BUNDLE_1"
Copy link
Contributor

Choose a reason for hiding this comment

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

should these two enums be changed? Docstring indicates otherwise

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good call, that was in there because of a different change that was fixed later.

Default: False
data (FormatString): The text data to write to the file.
endOfLine (Optional[EndOfLine]): Line ending style. Requires FEATURE_BUNDLE_1 extension.
Default: AUTO
Copy link
Contributor

Choose a reason for hiding this comment

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

do we need to describe AUTO? Is it based on operating system Windows vs. Posix? Or extension type? I don't see it listed in the RFC

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah, it's worthwhile describing that here. It's specified in https://github.com/OpenJobDescription/openjd-specifications/wiki/2023-09-Template-Schemas#61-embeddedfiletext

You're right that it's not in https://github.com/OpenJobDescription/openjd-specifications/blob/mainline/rfcs/0004-enhanced-limits-and-capabilities.md. It was, and then we noted how clunky it was to include the block diffs in the RFC and shifted them out into the PR itself. But in doing so, we never added descriptions of those changes back into the RFC. I'm inclined to leave it as is and proceed with what we have in the spec, and watch for this phenomenon in future RFCs.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'll merge this now, and then fix up your two comments in a trivial follow-up

) -> Optional[JobParameterDefinitionList]:
if v is not None:
# EnvironmentTemplate always has max 50 parameters (no extension increases this)
if len(v) > 50:
Copy link

Choose a reason for hiding this comment

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

Super nit - do we put constants like this somewhere ? Could be useful as an exported param?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The source of truth for that is here: https://github.com/OpenJobDescription/openjd-specifications/wiki/2023-09-Template-Schemas#12-environment-template

The conformance review prompt that I showed in the PR description did note this value and that it matched the spec in the report it produced. I also think the conformance suite in OpenJobDescription/openjd-specifications#103 is a good place documenting it. These feel sufficient to me, so I'd rather not add another version of these constants in another separate place.

if v is not None:
# Validate max length based on extension
context = cast(Optional[ModelParsingContext], info.context)
max_len = 200 if context and "FEATURE_BUNDLE_1" in context.extensions else 50
Copy link

Choose a reason for hiding this comment

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

The customer will be happy!

@mwiebe mwiebe merged commit 86f79ee into OpenJobDescription:mainline Feb 2, 2026
24 of 25 checks passed
@mwiebe mwiebe deleted the implement-rfc-0004 branch February 2, 2026 18:23
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.

5 participants