chore: make constraint metadata more flexible#2234
Conversation
There was a problem hiding this comment.
Pull request overview
Introduces the new ConstraintDescription-based metadata model for constraints (IDs + extensible user-defined metadata), updates internal usages (benchmarks, Quarkus/Jackson integrations, metrics tags, tests), and adds a migration recipe plus documentation to support upgrading from earlier APIs.
Changes:
- Replace string-based constraint name/group/description APIs with
ConstraintDescriptionand rename “constraint name” to “constraint ID”. - Update metrics/tagging, serializers, benchmark reporting, and tests to use
ConstraintRef.id()and constraint IDs. - Add an OpenRewrite migration recipe (and docs) to help migrate removed/renamed constraint metadata APIs.
Reviewed changes
Copilot reviewed 68 out of 68 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
| tools/migration/src/test/java/ai/timefold/solver/migration/v2/ConstraintDescriptionMigrationRecipeTest.java | Adds recipe tests for the new constraint metadata migration behavior. |
| tools/migration/src/main/java/ai/timefold/solver/migration/v2/ConstraintDescriptionMigrationRecipe.java | New OpenRewrite recipe to migrate removed/renamed constraint metadata APIs. |
| tools/migration/src/main/java/ai/timefold/solver/migration/ToLatestRecipe.java | Wires the new migration recipe into the “to latest” upgrade chain. |
| tools/benchmark/src/test/java/ai/timefold/solver/benchmark/impl/statistic/subsingle/constraintmatchtotalstepscore/ConstraintMatchTotalStepScoreSubSingleStatisticTest.java | Updates benchmark statistic tests to use constraint IDs. |
| tools/benchmark/src/test/java/ai/timefold/solver/benchmark/impl/statistic/subsingle/constraintmatchtotalbestscore/ConstraintMatchTotalBestScoreSubSingleStatisticTest.java | Updates benchmark statistic tests to use constraint IDs. |
| tools/benchmark/src/main/java/ai/timefold/solver/benchmark/impl/statistic/subsingle/constraintmatchtotalstepscore/ConstraintMatchTotalStepScoreSubSingleStatistic.java | Updates chart series labels to use constraint IDs. |
| tools/benchmark/src/main/java/ai/timefold/solver/benchmark/impl/statistic/subsingle/constraintmatchtotalstepscore/ConstraintMatchTotalStepScoreStatisticPoint.java | Updates CSV output to use constraint IDs. |
| tools/benchmark/src/main/java/ai/timefold/solver/benchmark/impl/statistic/subsingle/constraintmatchtotalbestscore/ConstraintMatchTotalBestScoreSubSingleStatistic.java | Updates chart series labels to use constraint IDs. |
| tools/benchmark/src/main/java/ai/timefold/solver/benchmark/impl/statistic/subsingle/constraintmatchtotalbestscore/ConstraintMatchTotalBestScoreStatisticPoint.java | Updates CSV output to use constraint IDs. |
| tools/benchmark/src/main/java/ai/timefold/solver/benchmark/impl/statistic/StatisticRegistry.java | Renames Micrometer tag from constraint.name to constraint.id and adapts extraction logic. |
| quarkus-integration/quarkus/runtime/src/main/java/ai/timefold/solver/quarkus/devui/TimefoldDevUIPropertiesRPCService.java | Exposes constraint IDs (not names) in Dev UI constraints endpoint. |
| quarkus-integration/quarkus-jackson/runtime/src/main/java/ai/timefold/solver/quarkus/jackson/score/constraint/ConstraintRefJacksonSerializer.java | Serializes ConstraintRef using id(). |
| quarkus-integration/quarkus-jackson/runtime/src/main/java/ai/timefold/solver/quarkus/jackson/domain/solution/ConstraintWeightOverridesSerializer.java | Serializes weight overrides keyed by constraint IDs. |
| quarkus-integration/quarkus-jackson/runtime/src/main/java/ai/timefold/solver/quarkus/jackson/domain/solution/AbstractConstraintWeightOverridesDeserializer.java | Deserializes weight overrides into ID-keyed map. |
| persistence/jackson/src/main/java/ai/timefold/solver/jackson/api/score/constraint/ConstraintRefJacksonSerializer.java | Serializes ConstraintRef using id(). |
| persistence/jackson/src/main/java/ai/timefold/solver/jackson/api/domain/solution/ConstraintWeightOverridesSerializer.java | Serializes weight overrides keyed by constraint IDs. |
| persistence/jackson/src/main/java/ai/timefold/solver/jackson/api/domain/solution/AbstractConstraintWeightOverridesDeserializer.java | Deserializes weight overrides into ID-keyed map. |
| docs/src/modules/ROOT/pages/using-timefold-solver/running-the-solver.adoc | Updates Micrometer tag documentation to constraint.id. |
| docs/src/modules/ROOT/pages/upgrading-timefold-solver/upgrade-from-v1.adoc | Documents upgrade path for constraint ID/description/group API changes. |
| docs/src/modules/ROOT/pages/constraints-and-score/score-calculation.adoc | Adds ConstraintDescription metadata model documentation and “constraint anatomy” section updates. |
| docs/src/modules/ROOT/pages/constraints-and-score/constraint-configuration.adoc | Clarifies that ConstraintWeightOverrides keys must match constraint IDs. |
| core/src/test/java/ai/timefold/solver/core/testconstraint/TestConstraint.java | Updates test constraint construction to use DefaultConstraintDescription instead of group/description strings. |
| core/src/test/java/ai/timefold/solver/core/impl/score/stream/common/uni/UniConstraintBuilderTest.java | Updates builder tests for new constraint construction signature. |
| core/src/test/java/ai/timefold/solver/core/impl/score/stream/common/uni/AbstractUniConstraintStreamTest.java | Replaces test constraint name usage with constraint ID. |
| core/src/test/java/ai/timefold/solver/core/impl/score/stream/common/uni/AbstractUniConstraintStreamPrecomputeTest.java | Replaces test constraint name usage with constraint ID. |
| core/src/test/java/ai/timefold/solver/core/impl/score/stream/common/tri/TriConstraintBuilderTest.java | Updates builder tests for new constraint construction signature. |
| core/src/test/java/ai/timefold/solver/core/impl/score/stream/common/tri/AbstractTriConstraintStreamTest.java | Replaces test constraint name usage with constraint ID. |
| core/src/test/java/ai/timefold/solver/core/impl/score/stream/common/tri/AbstractTriConstraintStreamPrecomputeTest.java | Replaces test constraint name usage with constraint ID. |
| core/src/test/java/ai/timefold/solver/core/impl/score/stream/common/quad/QuadConstraintBuilderTest.java | Updates builder tests for new constraint construction signature. |
| core/src/test/java/ai/timefold/solver/core/impl/score/stream/common/quad/AbstractQuadConstraintStreamTest.java | Replaces test constraint name usage with constraint ID. |
| core/src/test/java/ai/timefold/solver/core/impl/score/stream/common/quad/AbstractQuadConstraintStreamPrecomputeTest.java | Replaces test constraint name usage with constraint ID. |
| core/src/test/java/ai/timefold/solver/core/impl/score/stream/common/bi/BiConstraintBuilderTest.java | Updates builder tests for new constraint construction signature. |
| core/src/test/java/ai/timefold/solver/core/impl/score/stream/common/bi/AbstractBiConstraintStreamTest.java | Replaces test constraint name usage with constraint ID. |
| core/src/test/java/ai/timefold/solver/core/impl/score/stream/common/bi/AbstractBiConstraintStreamPrecomputeTest.java | Replaces test constraint name usage with constraint ID. |
| core/src/test/java/ai/timefold/solver/core/impl/score/stream/common/AbstractConstraintTest.java | Removes constraint group validation tests (constraint groups removed). |
| core/src/test/java/ai/timefold/solver/core/impl/score/stream/common/AbstractConstraintStreamTest.java | Renames shared test constants from “name” to “id” and updates match helpers. |
| core/src/test/java/ai/timefold/solver/core/impl/score/stream/common/AbstractAdvancedGroupByConstraintStreamTest.java | Updates test constraints to use constraint IDs. |
| core/src/test/java/ai/timefold/solver/core/impl/score/stream/bavet/BavetRegressionTest.java | Updates regression tests to use constraint IDs. |
| core/src/test/java/ai/timefold/solver/core/impl/score/stream/bavet/BavetAdvancedGroupByConstraintStreamTest.java | Updates Bavet group-by tests to use constraint IDs. |
| core/src/test/java/ai/timefold/solver/core/impl/score/stream/AbstractConstraintBuilderTest.java | Refactors sanitization tests to validate constraint IDs via asConstraint(id). |
| core/src/test/java/ai/timefold/solver/core/impl/score/director/stream/DefaultConstraintMetaModelTest.java | Removes group-related meta model assertions and updates test constraints accordingly. |
| core/src/test/java/ai/timefold/solver/core/impl/domain/solution/ConstraintWeightOverridesTest.java | Renames API usage from known constraint names to known constraint IDs. |
| core/src/main/java/ai/timefold/solver/core/impl/score/stream/test/AbstractSingleConstraintAssertion.java | Updates assertion messages to use constraint IDs. |
| core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/DefaultConstraintDescription.java | Adds default ConstraintDescription implementation used by asConstraint(String). |
| core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/ConstraintConstructor.java | Updates constraint construction functional interface to accept ConstraintDescription. |
| core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/AbstractConstraintBuilder.java | Changes terminal builder API to asConstraint(ConstraintDescription). |
| core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/AbstractConstraint.java | Stores ConstraintDescription, derives ConstraintRef from description.id(), and removes constraint group handling. |
| core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/uni/BavetAbstractUniConstraintStream.java | Updates constraint build pipeline to pass ConstraintDescription. |
| core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/tri/BavetAbstractTriConstraintStream.java | Updates constraint build pipeline to pass ConstraintDescription. |
| core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/quad/BavetAbstractQuadConstraintStream.java | Updates constraint build pipeline to pass ConstraintDescription. |
| core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/bi/BavetAbstractBiConstraintStream.java | Updates constraint build pipeline to pass ConstraintDescription. |
| core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/BavetConstraint.java | Updates constraint implementation constructor to accept ConstraintDescription. |
| core/src/main/java/ai/timefold/solver/core/impl/score/director/stream/DefaultConstraintMetaModel.java | Removes group indexing and simplifies meta model to map by ConstraintRef. |
| core/src/main/java/ai/timefold/solver/core/impl/score/director/InnerScoreDirector.java | Updates Javadoc to refer to constraint IDs. |
| core/src/main/java/ai/timefold/solver/core/impl/score/constraint/ConstraintMatch.java | Uses constraint IDs in toString(). |
| core/src/main/java/ai/timefold/solver/core/impl/localsearch/DefaultLocalSearchPhase.java | Updates Micrometer tags to use constraint.id. |
| core/src/main/java/ai/timefold/solver/core/impl/domain/solution/descriptor/ConstraintWeightSupplier.java | Validates overrides against constraint IDs and queries weights by ID. |
| core/src/main/java/ai/timefold/solver/core/impl/domain/solution/DefaultConstraintWeightOverrides.java | Renames API to getKnownConstraintIds() and uses ID-based lookup. |
| core/src/main/java/ai/timefold/solver/core/impl/bavet/visual/NodeGraph.java | Displays constraint IDs in DOT metadata output. |
| core/src/main/java/ai/timefold/solver/core/impl/bavet/common/BavetAbstractConstraintStream.java | Builds constraints from ConstraintDescription rather than separate name/group/description strings. |
| core/src/main/java/ai/timefold/solver/core/api/score/stream/ConstraintRef.java | Renames record component to id and sanitizes ID via sanitize("id", ...). |
| core/src/main/java/ai/timefold/solver/core/api/score/stream/ConstraintMetaModel.java | Removes group APIs and adds shorthand getConstraint(String id). |
| core/src/main/java/ai/timefold/solver/core/api/score/stream/ConstraintDescription.java | Introduces user-extensible constraint metadata interface with immutable ID contract. |
| core/src/main/java/ai/timefold/solver/core/api/score/stream/ConstraintBuilder.java | Replaces asConstraintDescribed(...) with asConstraint(String) and asConstraint(ConstraintDescription). |
| core/src/main/java/ai/timefold/solver/core/api/score/stream/Constraint.java | Removes group APIs and changes getDescription() return type to ConstraintDescription. |
| core/src/main/java/ai/timefold/solver/core/api/score/analysis/ScoreAnalysis.java | Renames constraint analysis lookup parameter to constraintId. |
| core/src/main/java/ai/timefold/solver/core/api/score/analysis/ConstraintAnalysis.java | Replaces constraintName() with default constraintId() based on constraintRef().id(). |
| core/src/main/java/ai/timefold/solver/core/api/domain/solution/ConstraintWeightOverrides.java | Renames APIs to ID-based naming and adds overload for ConstraintRef. |
zepfred
left a comment
There was a problem hiding this comment.
The new code improved the cohesion, and the class ConstraintDescription is an good solution. However, I don't understand why the class lacks description information. In my opinion, both ID and description should be the key information regarding the constraints.
|
The goal of this PR is for the solver to only expose what the solver needs - and the solver only needs Description will not be on the interface, because there is no need for us to provide any. |
|



Enterprise counterpart:
https://github.com/TimefoldAI/timefold-solver-enterprise/pull/517