Skip to content

feat: add environment mode per phase - #2595

Open
zepfred wants to merge 20 commits into
TimefoldAI:mainfrom
zepfred:feat/environment
Open

feat: add environment mode per phase#2595
zepfred wants to merge 20 commits into
TimefoldAI:mainfrom
zepfred:feat/environment

Conversation

@zepfred

@zepfred zepfred commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

Allows each solver phase (Construction Heuristic, Local Search, Exhaustive Search, Partitioned Search, Custom) to override the solver's environmentMode with a stricter mode of its own via PhaseConfig.withEnvironmentMode(...). This makes it possible to run a suspect phase under FULL_ASSERT (or another stricter mode) for debugging, without paying that performance cost for the whole solving run.

  • A phase's environment mode must be at least as strict as the solver's; it can never be looser.
  • If the solver's mode is NON_REPRODUCIBLE, no phase can override it (every other mode is reproducible, hence stricter).
  • Any number of phases may override the mode, including all of them — the solver's own mode still governs everything outside the phases (SolutionManager, the integrations).
  • If every phase ends up in the same mode, that mode becomes the solver's too, since no phase is left running in the configured one. This spares the solve a second score director factory for a mode nothing runs in.

Both rules are enforced when the SolverFactory is built, so a misconfiguration fails there rather than during solving.

Key changes

  • PhaseConfig: new environmentMode field/getter/setter/withEnvironmentMode(...), added to the @XmlType propOrder, and wired into solver.xsd / benchmark.xsd. Includes a revapi-differences.json ignore entry for the resulting @XmlType.propOrder change. The accessors are @Nullable (null means "run in the solver's mode") and carry javadoc stating the rules above and the cost below.

  • ScoreDirectorFactoryFactoryDelegateScoreDirectorFactory: renamed and reworked. It stays the single entry point that picks the score calculation implementation (easy / incremental / Constraint Streams) and hides the choice from callers. One delegate is still built eagerly for the solver's environment mode. Most delegates merely pass the mode on to the score director they build, so they serve any mode and are reused as they are; only BavetConstraintStreamScoreDirectorFactory builds its constraint network from the mode up front, so for it a separate delegate is built per requested mode and cached. DefaultSolverFactory continues to expose the factory built for the solver's own mode to consumers decoupled from the solving lifecycle (SolverManager, Quarkus DI injecting ConstraintMetaModel).

  • SolverContextManager (new): owns the InnerScoreDirector the solver is working with and swaps it when a phase requires a different environment mode. It compares the phase's mode to the current one at phaseStarted and only builds a replacement when they differ, carrying the working solution, the score calculation count, the SolverScope's view of both directors, and the BestSolutionRecaller's assertion level across the swap. Score directors themselves are not cached — caching lives one level down in the factory, which is the expensive part to build. Also fixes score director closing on the failure path, where outerSolvingEnded never runs.

  • AbstractSolver / DefaultSolver / phase factories: restructured so each phase is built with, and runs under, its own config policy and score director rather than always reusing the solver-level one.

  • Bundled fix — stale ListVariableStateSupply references in list move selectors (ElementDestinationSelector, RandomSubListSelector, ListChangeMoveSelector, ListSwapMoveSelector, KOptListMoveSelector, ListRuinRecreateMoveSelector). These previously cached the supply once at selector construction, which breaks as soon as a phase runs on a different score director. They now acquire it per phase in phaseStarted from the phase's own score director — which owns the supply and allocates it once — and drop it in phaseEnded.

  • Benchmark report: <environmentMode> is valid on phase configs inside benchmark solver configs, so the report can no longer read the solver-level mode and call it the truth. A new EnvironmentModeResolver in core is now the single answer to "which mode does this config actually run in" (validate + a total resolve, plus the per-phase and strictest-mode views), used by both DefaultSolverFactory and the benchmark instead of each deriving its own. The report now warns per solver benchmark on the strictest mode any of its phases runs in, naming the offending phase, and warns when the solver benchmarks in one report do not all resolve to the same mode, since their results are then not comparable.

  • Docs: new "Using different environment modes per phase" section in solver-diagnostics.adoc with a config example, the rules, and the cost note below.

User-visible notes

  • A phase running in a mode other than the solver's gets its own score director. With Constraint Streams that means a second constraint network is built for that mode — built once and reused, but not free.
  • Setting the same stricter mode on every phase makes it the solver's mode, which also slows down SolutionManager operations.
  • The benchmark report's "Environment mode" row can now read PHASE_ASSERT (localSearch: FULL_ASSERT) rather than always a bare enum name, so anything parsing that column downstream needs to cope with the suffix.

Copilot AI left a comment

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.

Pull request overview

This PR introduces per-phase EnvironmentMode overrides so individual solver phases can run with stricter assertion modes (e.g., FULL_ASSERT) without imposing that cost on the entire solve, and it refactors score director factory creation/lifecycle to support per-phase score directors.

Changes:

  • Add environmentMode to PhaseConfig, wire it into XSDs, and document configuration usage.
  • Refactor solver/phase construction so each phase can run under its own environment mode and corresponding score director (via DelegateScoreDirectorFactory).
  • Fix list move selectors to avoid stale ListVariableStateSupply references when score directors are rebuilt, by introducing ListVariableStateSupplyHolder.

Reviewed changes

Copilot reviewed 61 out of 61 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
tools/benchmark/src/main/resources/benchmark.xsd Adds environmentMode element to phase config schema.
docs/src/modules/ROOT/pages/running-timefold-solver/solver-diagnostics.adoc Documents per-phase environment mode overrides with an example.
core/src/test/java/ai/timefold/solver/core/impl/solver/SolverMetricsIT.java Updates latch-await assertions to JUnit assertDoesNotThrow.
core/src/test/java/ai/timefold/solver/core/impl/solver/DefaultSolverTest.java Adds tests covering per-phase environment mode behavior and context restoration.
core/src/test/java/ai/timefold/solver/core/impl/solver/DefaultSolverFactoryTest.java Adds validation tests for environment mode constraints across phases.
core/src/test/java/ai/timefold/solver/core/impl/score/director/stream/ConstraintStreamsBavetScoreDirectorSemanticsTest.java Updates to use DelegateScoreDirectorFactory.
core/src/test/java/ai/timefold/solver/core/impl/score/director/incremental/IncrementalScoreDirectorTest.java Mocks getEnvironmentMode() and adjusts no-op listener methods.
core/src/test/java/ai/timefold/solver/core/impl/score/director/incremental/IncrementalScoreDirectorSemanticsTest.java Updates to use DelegateScoreDirectorFactory.
core/src/test/java/ai/timefold/solver/core/impl/score/director/easy/EasyScoreDirectorSemanticsTest.java Updates to use DelegateScoreDirectorFactory.
core/src/test/java/ai/timefold/solver/core/impl/score/director/DelegateScoreDirectorFactoryTest.java Renames/extends tests for the new delegate factory behavior.
core/src/test/java/ai/timefold/solver/core/impl/neighborhood/NeighborhoodsTest.java Adapts acceptor/phase builder APIs to pass environment mode.
core/src/test/java/ai/timefold/solver/core/impl/localsearch/decider/acceptor/AcceptorFactoryTest.java Updates acceptor factory API usage to include environment mode.
core/src/test/java/ai/timefold/solver/core/impl/heuristic/selector/move/generic/list/RandomSubListSwapMoveSelectorTest.java Ensures selectors receive phaseStarted lifecycle for fresh supplies.
core/src/test/java/ai/timefold/solver/core/impl/heuristic/selector/move/generic/list/RandomSubListChangeMoveSelectorTest.java Ensures selectors receive phaseStarted lifecycle for fresh supplies.
core/src/test/java/ai/timefold/solver/core/impl/heuristic/selector/move/generic/list/RandomListChangeIteratorTest.java Ensures destination selector receives phaseStarted lifecycle.
core/src/test/java/ai/timefold/solver/core/impl/heuristic/selector/move/generic/list/ListSwapMoveSelectorTest.java Ensures selector receives phaseStarted lifecycle for fresh supplies.
core/src/test/java/ai/timefold/solver/core/impl/heuristic/selector/move/generic/list/ListChangeMoveSelectorTest.java Ensures selector receives phaseStarted lifecycle for fresh supplies.
core/src/test/java/ai/timefold/solver/core/impl/heuristic/selector/list/RandomSubListSelectorTest.java Ensures selector receives phaseStarted lifecycle for fresh supplies.
core/src/test/java/ai/timefold/solver/core/impl/heuristic/selector/list/ElementDestinationSelectorTest.java Ensures selector receives phaseStarted lifecycle for fresh supplies.
core/src/test/java/ai/timefold/solver/core/impl/domain/variable/ListVariableStateSupplyHolderTest.java Adds unit test for ListVariableStateSupplyHolder demand/cancel behavior.
core/src/main/resources/solver.xsd Adds environmentMode element to phase config schema.
core/src/main/java/ai/timefold/solver/core/impl/solver/scope/SolverScope.java Routes assertScoreFromScratch through score director instance.
core/src/main/java/ai/timefold/solver/core/impl/solver/recaller/BestSolutionRecallerFactory.java Delegates assertion enabling to BestSolutionRecaller.
core/src/main/java/ai/timefold/solver/core/impl/solver/recaller/BestSolutionRecaller.java Adds enableAssertions(EnvironmentMode) method.
core/src/main/java/ai/timefold/solver/core/impl/solver/DefaultSolverFactory.java Introduces default environment mode, delegate factory, and env-mode validation across phases.
core/src/main/java/ai/timefold/solver/core/impl/solver/DefaultSolver.java Refactors construction to carry default context and delegate factory; logs default env mode.
core/src/main/java/ai/timefold/solver/core/impl/solver/AbstractSolver.java Adds per-phase context swapping to run phases under different environment modes.
core/src/main/java/ai/timefold/solver/core/impl/score/director/ScoreDirectorFactory.java Adds getEnvironmentMode() and adjusts builder generics; removes factory-level assert method.
core/src/main/java/ai/timefold/solver/core/impl/score/director/InnerScoreDirector.java Adds assertScoreFromScratch and a counted increment method.
core/src/main/java/ai/timefold/solver/core/impl/score/director/DelegateScoreDirectorFactory.java Replaces ScoreDirectorFactoryFactory and centralizes score director creation per env mode.
core/src/main/java/ai/timefold/solver/core/impl/score/director/AbstractScoreDirectorFactory.java Implements getEnvironmentMode() and moves score-from-scratch assertion off the factory.
core/src/main/java/ai/timefold/solver/core/impl/score/director/AbstractScoreDirector.java Stores environment mode, adjusts tracking/assert logic, and implements assertScoreFromScratch.
core/src/main/java/ai/timefold/solver/core/impl/phase/Phase.java Adds getEnvironmentMode() to phase API.
core/src/main/java/ai/timefold/solver/core/impl/phase/custom/DefaultCustomPhaseFactory.java Resolves per-phase environment mode and passes it into phase builder.
core/src/main/java/ai/timefold/solver/core/impl/phase/custom/DefaultCustomPhase.java Logs environment mode and threads it through the builder hierarchy.
core/src/main/java/ai/timefold/solver/core/impl/phase/AbstractPossiblyInitializingPhase.java Threads environment mode into initializing phase builder base.
core/src/main/java/ai/timefold/solver/core/impl/phase/AbstractPhaseFactory.java Adds shared resolveEnvironmentMode helper for phase factories.
core/src/main/java/ai/timefold/solver/core/impl/phase/AbstractPhase.java Stores phase environment mode and uses it for assertion enabling.
core/src/main/java/ai/timefold/solver/core/impl/partitionedsearch/DefaultPartitionedSearchPhaseFactory.java Passes resolved environment mode into enterprise partitioned search builder.
core/src/main/java/ai/timefold/solver/core/impl/localsearch/DefaultLocalSearchPhaseFactory.java Propagates environment mode into decider/acceptor construction.
core/src/main/java/ai/timefold/solver/core/impl/localsearch/DefaultLocalSearchPhase.java Logs environment mode and threads it through phase builder.
core/src/main/java/ai/timefold/solver/core/impl/localsearch/decider/acceptor/tabu/AbstractTabuAcceptor.java Enables tabu assertions based on environment mode.
core/src/main/java/ai/timefold/solver/core/impl/localsearch/decider/acceptor/AcceptorFactory.java Adds environment mode parameter and enables assertions accordingly.
core/src/main/java/ai/timefold/solver/core/impl/heuristic/selector/move/generic/RuinRecreateConstructionHeuristicPhaseFactory.java Passes environment mode into decider construction (root mode by default).
core/src/main/java/ai/timefold/solver/core/impl/heuristic/selector/move/generic/RuinRecreateConstructionHeuristicPhaseBuilder.java Threads environment mode into builder construction/copying.
core/src/main/java/ai/timefold/solver/core/impl/heuristic/selector/move/generic/list/ruin/ListRuinRecreateMoveSelector.java Switches to ListVariableStateSupplyHolder to avoid stale supply across phase swaps.
core/src/main/java/ai/timefold/solver/core/impl/heuristic/selector/move/generic/list/ListSwapMoveSelector.java Switches to ListVariableStateSupplyHolder and phase lifecycle hooks.
core/src/main/java/ai/timefold/solver/core/impl/heuristic/selector/move/generic/list/ListChangeMoveSelector.java Switches to ListVariableStateSupplyHolder and phase lifecycle hooks.
core/src/main/java/ai/timefold/solver/core/impl/heuristic/selector/move/generic/list/kopt/KOptListMoveSelector.java Switches to ListVariableStateSupplyHolder and phase lifecycle hooks.
core/src/main/java/ai/timefold/solver/core/impl/heuristic/selector/list/RandomSubListSelector.java Switches to ListVariableStateSupplyHolder and phase lifecycle hooks.
core/src/main/java/ai/timefold/solver/core/impl/heuristic/selector/list/ElementDestinationSelector.java Switches to ListVariableStateSupplyHolder and phase lifecycle hooks.
core/src/main/java/ai/timefold/solver/core/impl/heuristic/HeuristicConfigPolicy.java Renames/adjusts copying methods used by phase/child-thread policy creation.
core/src/main/java/ai/timefold/solver/core/impl/exhaustivesearch/DefaultExhaustiveSearchPhaseFactory.java Resolves per-phase environment mode and propagates it into decider and phase builder.
core/src/main/java/ai/timefold/solver/core/impl/exhaustivesearch/DefaultExhaustiveSearchPhase.java Logs environment mode and threads it through phase builder.
core/src/main/java/ai/timefold/solver/core/impl/exhaustivesearch/decider/AbstractExhaustiveSearchDecider.java Enables decider assertions based on environment mode.
core/src/main/java/ai/timefold/solver/core/impl/domain/variable/ListVariableStateSupplyHolder.java Introduces helper to demand/cancel list state supply per phase start/end.
core/src/main/java/ai/timefold/solver/core/impl/constructionheuristic/DefaultConstructionHeuristicPhaseFactory.java Resolves per-phase environment mode and propagates it into decider and phase builder.
core/src/main/java/ai/timefold/solver/core/impl/constructionheuristic/DefaultConstructionHeuristicPhase.java Logs environment mode and threads it through phase builder.
core/src/main/java/ai/timefold/solver/core/enterprise/TimefoldSolverEnterpriseService.java Extends enterprise partitioned search API to accept environment mode.
core/src/main/java/ai/timefold/solver/core/config/phase/PhaseConfig.java Adds per-phase environmentMode config with JAXB/XSD support and inheritance.
core/src/build/revapi-differences.json Ignores the JAXB @XmlType.propOrder change for PhaseConfig.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread core/src/main/java/ai/timefold/solver/core/impl/solver/AbstractSolver.java Outdated

Copilot AI left a comment

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.

Pull request overview

Copilot reviewed 61 out of 61 changed files in this pull request and generated 1 comment.

Copilot AI left a comment

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.

Pull request overview

Copilot reviewed 61 out of 61 changed files in this pull request and generated no new comments.

Suppressed comments (5)

core/src/test/java/ai/timefold/solver/core/impl/solver/SolverMetricsIT.java:228

  • Using JUnit's assertDoesNotThrow violates the repository test convention requiring AssertJ assertions (see CONSTITUTION.md), so switch this to AssertJ and remove the JUnit import.
    core/src/test/java/ai/timefold/solver/core/impl/solver/SolverMetricsIT.java:291
  • Using JUnit's assertDoesNotThrow violates the repository test convention requiring AssertJ assertions (see CONSTITUTION.md), so switch this to AssertJ and remove the JUnit import.
    core/src/test/java/ai/timefold/solver/core/impl/solver/SolverMetricsIT.java:440
  • Using JUnit's assertDoesNotThrow violates the repository test convention requiring AssertJ assertions (see CONSTITUTION.md), so switch this to AssertJ and remove the JUnit import.
    core/src/main/java/ai/timefold/solver/core/impl/solver/AbstractSolver.java:133
  • AbstractSolver.preparePhase() always builds a new ScoreDirectorFactory/ScoreDirector when switching into a non-default environment mode, which contradicts the PR description of lazily reusing factories per distinct mode and may add avoidable overhead when phases switch modes repeatedly.
    core/src/test/java/ai/timefold/solver/core/impl/solver/SolverMetricsIT.java:138
  • Using JUnit's assertDoesNotThrow violates the repository test convention requiring AssertJ assertions (see CONSTITUTION.md), so switch this to AssertJ and remove the JUnit import.

This issue also appears in the following locations of the same file:

  • line 228
  • line 291
  • line 440

Copilot AI review requested due to automatic review settings August 19, 2026 19:18

Copilot AI left a comment

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.

Pull request overview

Copilot reviewed 84 out of 84 changed files in this pull request and generated 5 comments.

Suppressed comments (3)

core/src/test/java/ai/timefold/solver/core/impl/solver/SolverMetricsIT.java:228

  • CONSTITUTION.md forbids JUnit assertions in tests, so replace this assertDoesNotThrow call with an AssertJ equivalent.
    core/src/test/java/ai/timefold/solver/core/impl/solver/SolverMetricsIT.java:291
  • CONSTITUTION.md forbids JUnit assertions in tests, so replace this assertDoesNotThrow call with an AssertJ equivalent.
    core/src/test/java/ai/timefold/solver/core/impl/solver/SolverMetricsIT.java:440
  • CONSTITUTION.md forbids JUnit assertions in tests, so replace this assertDoesNotThrow call with an AssertJ equivalent.

Comment thread core/src/test/java/ai/timefold/solver/core/impl/solver/SolverMetricsIT.java Outdated
Comment thread core/src/test/java/ai/timefold/solver/core/impl/solver/SolverMetricsIT.java Outdated
Comment thread core/src/test/java/ai/timefold/solver/core/impl/solver/DefaultSolverTest.java Outdated
Copilot AI review requested due to automatic review settings August 26, 2026 15:31

Copilot AI left a comment

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.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

@zepfred

zepfred commented Aug 26, 2026

Copy link
Copy Markdown
Contributor Author

Here are the benchmark warnings for the following configuration:

<plannerBenchmark xmlns="https://timefold.ai/xsd/benchmark" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                  xsi:schemaLocation="https://timefold.ai/xsd/benchmark https://timefold.ai/xsd/benchmark/benchmark.xsd">
    <parallelBenchmarkCount>18</parallelBenchmarkCount>
    <inheritedSolverBenchmark>
        <solver>
            <termination>
                <secondsSpentLimit>10</secondsSpentLimit>
            </termination>
        </solver>
        <problemBenchmarks>
            <problemStatisticType>BEST_SCORE</problemStatisticType>
        </problemBenchmarks>
    </inheritedSolverBenchmark>
    <solverBenchmark>
        <name>Solver1</name>
        <solver>
            <constructionHeuristic/>
            <localSearch/>
        </solver>
    </solverBenchmark>
    <solverBenchmark>
        <name>Solver2</name>
        <solver>
            <constructionHeuristic/>
            <localSearch>
                <environmentMode>FULL_ASSERT</environmentMode>
            </localSearch>
        </solver>
    </solverBenchmark>
</plannerBenchmark>
image

@triceo triceo left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

  • The changes to the benchmarker should go away; benchmarker should fail fast when this is detected. (Considering how tiny benchmarker test coverage is, we should not be touching it unless we absolutely have to.
  • The Delegate factory is IMO overly complex, and overused.
  • The SolverContextManager is poorly designed; its resource management is leaking to the rest of the solver.
  • The global env mode should not be decided by the phases.
  • Plus usual smaller comments.

@@ -302,35 +303,62 @@ public List<String> getWarningList() {
List<String> warningList = new ArrayList<>();
String javaVmName = System.getProperty("java.vm.name");
if (javaVmName != null && javaVmName.contains("Client VM")) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Client VMs have not existed for probably a decade now. This can be completely removed.

import org.jspecify.annotations.Nullable;

@NullMarked
public abstract class GenericListMoveSelector<Solution_> extends GenericMoveSelector<Solution_> {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Abstract classed, by convention, start by Abstract.
It appears we broke that convention already with the parent, fix that too.

Comment on lines +117 to +118
// Constraint Stream factory requires a new factory if the environment changes
this.requireNewFactoryOnDifferentEnvironment = config.getConstraintProviderClass() != null;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

This is very brittle. You are making the assumption that only CS will ever need this, and when something in the other score directors changes, this immediately introduces a silent bug which nobody notices.

IMO it is safer for this to always be true, and therefore it doesn't need to exist at all.

Comment on lines +42 to +50
* <p>
* Since a solver phase may override the solver's environment mode,
* {@link #createScoreDirectorBuilder(EnvironmentMode)} may be called with a different mode than the default one.
* Most delegates only pass the environment mode on to the score director they build,
* so they can serve any mode and are reused as they are.
* The exception is {@link BavetConstraintStreamScoreDirectorFactory},
* which builds its constraint network from the environment mode up front;
* for it, a separate delegate is built for the requested mode,
* then cached and shared like the default one, as building it is expensive.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

See comment below. IMO this should not be the case.

assertCorrectDirectorFactory(config);
this.solutionDescriptor = solutionDescriptor;
this.globalEnvironmentMode = environmentMode;
this.metricsRequiringConstraintMatchList = metricsRequiringConstraintMatchList;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

The class should not be dealing with this. That is the delegate's problem.
Everything but the environment mode is the delegate's problem.


A phase's environment mode must be at least as strict as the solver's environment mode; it can never be less strict.
Any number of phases can override it, including all of them:
the solver's environment mode still applies outside the phases.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Suggested change
the solver's environment mode still applies outside the phases.
the solver's global environment mode still applies outside these phases.

A phase's environment mode must be at least as strict as the solver's environment mode; it can never be less strict.
Any number of phases can override it, including all of them:
the solver's environment mode still applies outside the phases.
If the solver's environment mode is `<<environmentModeNonReproducible,NON_REPRODUCIBLE>>`, no phase can override it,

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Suggested change
If the solver's environment mode is `<<environmentModeNonReproducible,NON_REPRODUCIBLE>>`, no phase can override it,
If the solver's global environment mode is `<<environmentModeNonReproducible,NON_REPRODUCIBLE>>`, no phase can override it,

Comment on lines +230 to +231
If every phase ends up in the same environment mode, that mode becomes the solver's environment mode too,
since no phase is left running in the configured one.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

IMO wrong and unexpected, as explained above.

Comment on lines +241 to +246
[NOTE]
====
The solver's environment mode also applies outside the phases,
including to xref:using-timefold-solver/modeling-planning-problems.adoc[`SolutionManager`] operations,
so a stricter solver-level mode makes those slower as well.
====

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

What does this mean? How is SolutionManager affected by solver config phases?

Comment on lines +233 to +239
[NOTE]
====
A phase that runs in a different environment mode than the solver gets its own score director.
With the xref:constraints-and-score/score-calculation.adoc#constraintStreams[Constraint Streams] API,
that means a second constraint network is built for that mode.
It is built once and reused, but it is not free: prefer overriding the phases you actually want to inspect.
====

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Suggested change
[NOTE]
====
A phase that runs in a different environment mode than the solver gets its own score director.
With the xref:constraints-and-score/score-calculation.adoc#constraintStreams[Constraint Streams] API,
that means a second constraint network is built for that mode.
It is built once and reused, but it is not free: prefer overriding the phases you actually want to inspect.
====
NOTE: A phase that runs in a different environment mode than the solver gets its own score director.
With the xref:constraints-and-score/score-calculation.adoc#constraintStreams[Constraint Streams] API,
that means a second constraint network is built for that mode.
It is built once and reused, but it is not free: prefer overriding the phases you actually want to inspect.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants