Repository navigation
Keep LaunchSpineCompiler up to date and its output deterministic - #335
Conversation
The renderer settings were written in a `doFirst` action of every `LaunchSpineCompiler`, after Gradle had fingerprinted the settings directory. A fresh daemon then saw the file as added and reran the task, a cache hit skipped the action, and a changed DSL value left the task up-to-date with stale settings. A new `writeValidationSettings` task writes the file. It takes the DSL value as its input and the file as its only output, runs after `clean`, and every `LaunchSpineCompiler` depends on it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Two runs of the Validation compiler over the same protos produced different sources, so `LaunchSpineCompiler` outputs and everything compiled from them changed on every rerun. `mangled()` now derives its suffix from the SHA-256 digest of the identifier instead of a random string. The suffix keeps its length and alphabet. Callers must pass identifiers unique within the target class, since equal identifiers now yield equal names. The option generators and `SetOnceRenderer` sort the views they query by the order of declaration, because the views come in hash order that changes between JVM runs. The `(choice)` generator takes the order of the groups from the declaring message type, as the group in the view carries no fields. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Follow the `XIgTest` naming of integration tests from the testing guideline. The other `*ITest` suites are to be reviewed separately. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Refresh the `RequiredGenerator` snippets embedded in the developer docs, and ask new built-in generators to sort the views they select. Describe the output of `WriteValidationSettings` without relying on what the CoreJvm Compiler declares. Wrap the long lines of the proto fixture and the task log. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
There was a problem hiding this comment.
🟢 Approved
No blocking issues remain in the settings-task wiring, deterministic generation, or regression coverage.
No open issues 🎉
What changed in this PR
Improves incremental builds in the Validation compiler by writing settings before input fingerprinting and making generated Java sources deterministic.
Changes:
- Adds a dedicated settings-writing task with explicit inputs, output, and compiler dependencies.
- Replaces random name suffixes with deterministic hashes and orders generated constraints by declaration.
- Adds regression coverage and updates documentation and version metadata.
| File | Description |
|---|---|
version.gradle.kts |
Bumps version to .466. |
tests/validating/src/testFixtures/proto/spine/test/tools/validate/declaration_order.proto |
Adds declaration-order fixtures. |
tests/validating/src/test/kotlin/io/spine/test/options/DeclarationOrderIgTest.kt |
Tests constraint ordering. |
java/src/test/kotlin/io/spine/tools/validation/java/generate/JavaIdentifiersSpec.kt |
Tests deterministic identifiers. |
java/src/main/kotlin/io/spine/tools/validation/java/setonce/SetOnceRenderer.kt |
Orders set-once field processing. |
java/src/main/kotlin/io/spine/tools/validation/java/generate/OptionGenerator.kt |
Documents stable output ordering. |
java/src/main/kotlin/io/spine/tools/validation/java/generate/option/ValidateGenerator.kt |
Orders validate fields. |
java/src/main/kotlin/io/spine/tools/validation/java/generate/option/RequiredGenerator.kt |
Orders required fields. |
java/src/main/kotlin/io/spine/tools/validation/java/generate/option/PatternGenerator.kt |
Orders pattern fields. |
java/src/main/kotlin/io/spine/tools/validation/java/generate/option/GoesGenerator.kt |
Orders goes fields. |
java/src/main/kotlin/io/spine/tools/validation/java/generate/option/DistinctGenerator.kt |
Orders distinct fields. |
java/src/main/kotlin/io/spine/tools/validation/java/generate/option/ChoiceGenerator.kt |
Orders choices using message declarations. |
java/src/main/kotlin/io/spine/tools/validation/java/generate/option/bound/RangeGenerator.kt |
Orders range fields. |
java/src/main/kotlin/io/spine/tools/validation/java/generate/option/bound/MinGenerator.kt |
Orders minimum-bound fields. |
java/src/main/kotlin/io/spine/tools/validation/java/generate/option/bound/MaxGenerator.kt |
Orders maximum-bound fields. |
java/src/main/kotlin/io/spine/tools/validation/java/generate/JavaIdentifiers.kt |
Derives deterministic name suffixes. |
gradle-plugin/src/test/kotlin/io/spine/tools/validation/gradle/WriteValidationSettingsSpec.kt |
Tests settings serialization and replacement. |
gradle-plugin/src/test/kotlin/io/spine/tools/validation/gradle/ValidationGradlePluginSpec.kt |
Tests task wiring and input/output declarations. |
gradle-plugin/src/main/kotlin/io/spine/tools/validation/gradle/WriteValidationSettings.kt |
Adds the settings-writing task. |
gradle-plugin/src/main/kotlin/io/spine/tools/validation/gradle/ValidationGradlePlugin.kt |
Makes compiler tasks depend on settings preparation. |
docs/dependencies/pom.xml |
Updates reported project version. |
docs/dependencies/dependencies.md |
Refreshes dependency reports. |
docs/content/docs/validation/developer/java-code-generation.md |
Refreshes the generator example. |
docs/content/docs/validation/developer/build-and-release.md |
Updates the version example. |
docs/content/docs/validation/developer/adding-a-built-in-option.md |
Documents deterministic view ordering. |
.agents/tasks/up-to-date-compiler-tasks.md |
Records the implementation plan and verification log. |
Review effort: Balanced
`publish.yml` became a thin caller of the reusable `publishing.yml` from `config`, so the embedded "Publish artifacts to Maven" step no longer exists and `:docs:checkSamples` fails. Embed the trigger and the job instead, leaving out the `uses:` line whose commit changes on every `./config/pull`, and describe what the reusable workflow does. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
There was a problem hiding this comment.
Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.
An organization owner can choose the repository organization as the billing source for reviews requested by members with a paid Copilot license. Learn about Copilot code review billing. Review the Copilot code review billing settings.
Keep `Compiler.fallbackVersion` at `2.0.0-SNAPSHOT.074`. The pull resets it to the `.069` that `config` carries, while this repository builds with `.074`. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Introduce `FieldView`, the common interface of the views of fields with a validation option, and `Iterable<FieldView>.sortedByDeclaration()`. The field views implement the interface via `(is)`; `BoundedFieldView` extends it. Generators and `SetOnceRenderer` now call the extension instead of repeating the sorting lambda. Group the tests of `mangled()` in a nested class of `JavaIdentifiersSpec` and name the suite after the file. Refresh the embedded `RequiredGenerator` snippets and point the built-in option guide at the extension. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Make "CodeMatters Open-Source" the default copyright profile of the project and apply its notice to the source files changed on this branch. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #335 +/- ##
============================================
+ Coverage 92.63% 93.57% +0.94%
- Complexity 363 367 +4
============================================
Files 84 86 +2
Lines 2090 2117 +27
Branches 157 159 +2
============================================
+ Hits 1936 1981 +45
+ Misses 110 92 -18
Partials 44 44 🚀 New features to boost your workflow:
|
Summary
Follow-up to SpineEventEngine/compiler#94 ("Stop the integration-test build from
recompiling the root modules"). Two changes to keep
LaunchSpineCompilerfromrerunning when nothing it depends on has changed:
Write the Validation settings before
LaunchSpineCompilerruns.The
JavaValidationRenderersettings file was written in adoFirstaction of everyLaunchSpineCompiler, i.e. after Gradle had fingerprinted the settings directory.As a result:
FROM-CACHE) skipped the action, so the settings never reached thecache key;
cleanleft the taskUP-TO-DATEwith stale settings.A new
writeValidationSettingstask now writes the file. Its input is the DSL value,its only output is the file, it runs after
clean, and everyLaunchSpineCompilerdepends on it.
Generate the same Java code from build to build. Two runs of the Validation
compiler over the same protos produced different sources:
mangled()appended random suffixes. It now derives the suffix from the SHA-256digest of the identifier, with the same length and alphabet as before.
SetOnceRendereriterated the queried views in hash order,which changes between JVM runs. They now sort the views with the new
sortedByDeclaration()extension. It is declared onFieldView, a new interface incontextthat the field views implement via(is);BoundedFieldViewnow extendsit.
ChoiceGeneratortakes the order of the groups from the declaring message type,because its view holds a
oneofgroup, not a field, and that group carries no fields.mangled()is public. Equal identifiers now yield equal names, so a customOptionGeneratormust pass identifiers that are unique within the target class.The KDoc states this rule. All built-in callers already comply. Custom generators that
select field views can sort them with
sortedByDeclaration().The branch also:
config. It bringsbuildSrc,AGENTS.md,init-submodules,and
publish.ymlup to date.Compiler.fallbackVersionstays at2.0.0-SNAPSHOT.074: the pull resets it to the.069thatconfigcarries, whilethis repository builds with
.074.default profile, and the source files changed on this branch carry its notice.
publish.ymlis now a thin caller of the reusablepublishing.ymlfromconfig. The "Publish artifacts to Maven" step embedded inbuild-and-release.mdno longer existed, which failed the "Match embedded and originalcode" check. The page now embeds the trigger and the job, leaving out the
uses:line,whose commit changes on every
./config/pull.Commits
2.0.0-SNAPSHOT.466LaunchSpineCompilerruns: theWriteValidationSettingstask and itsProjectBuilderspecs..466.mangled(), viewssorted by declaration order,
JavaIdentifiersSpec, and theDeclarationOrderIgTestintegration test.
DeclarationOrderITesttoDeclarationOrderIgTest: follows theXIgTestnaming from the testing guideline.
RequiredGeneratorsnippets embeddedin the developer docs, and added a step to the built-in option guide asking generators
to sort the views they select.
publish.ymlin the release docs: the docs fix described above../config/pull): theconfigpull,keeping the Compiler pin at
.074.sortedByDeclaration():FieldViewand the extension, usedby the generators and
SetOnceRenderer.JavaIdentifiersSpecnow groups themangled()tests in a nested class, and the docs point at the extension.notices on the changed files.
Verification
./gradlew clean build dokkaGeneratepasses on the final tree.tests/*modules that have protos(
--rerun) and randiff -rontests/*/generated. 0 files differ. With thejava/src/mainchanges reverted, 52 files differ between two runs.DeclarationOrderIgTest((required),(min),(choice)) fails on the old code andpasses on the new code.
.466plugin, published toMaven Local, stays
UP-TO-DATEacross--no-daemonruns, reruns when the DSL valuechanges, and works after
clean. On.465, the second run reruns with"…JavaValidationRenderer.pb.json has been added".
:docs:checkSamplescouldn't run locally, because theembed-codebinary is x86-64only. I regenerated the embedded snippets from the source, using the
start/endranges of their
<embed-code>tags. I then checked every embed underdocs/contentagainst the sources with a script that mimics
embed-code. The script doesn't supportfragment=embeds; those embeddocs/_examples, which this PR doesn't touch.Not in this PR
UP-TO-DATEregression test. TheProjectBuilderspecspin the task wiring, the
@Inputand@OutputFiledeclarations,mustRunAfter(clean)and the settings file path. The TestKit check (
--no-watch-fs, a DSL change, thenclean) belongs in CoreJvm Compiler's follow-up. That follow-up also makes its settingswriter declare exact output files and pick up DSL changes, and needs this version
published first.
*ITestsuites undertests/to follow theXIgTestconvention. That's separate work.
The plan and log for this work are in
.agents/tasks/up-to-date-compiler-tasks.md.🤖 Generated with Claude Code