Index: drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/nurserostering/domain/Assignment.java
===================================================================
--- drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/nurserostering/domain/Assignment.java	(revision 38ab6e0cd0201306de8eb6775db1044d6d86228e)
+++ drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/nurserostering/domain/Assignment.java	(revision )
@@ -125,7 +125,7 @@
     }
 
     public boolean isWeekend() {
-        WeekendDefinition weekendDefinition = employee.getContract().getWeekendDefinition();
+        WeekendDefinition weekendDefinition = WeekendDefinition.SATURDAY_SUNDAY;
         DayOfWeek dayOfWeek = shift.getShiftDate().getDayOfWeek();
         return weekendDefinition.isWeekend(dayOfWeek);
     }
Index: drools-planner/drools-planner-examples/src/test/resources/org/drools/planner/examples/nurserostering/solver/nurseRosteringScoreRules_jbrules2809.drl
===================================================================
--- drools-planner/drools-planner-examples/src/test/resources/org/drools/planner/examples/nurserostering/solver/nurseRosteringScoreRules_jbrules2809.drl	(revision )
+++ drools-planner/drools-planner-examples/src/test/resources/org/drools/planner/examples/nurserostering/solver/nurseRosteringScoreRules_jbrules2809.drl	(revision )
@@ -0,0 +1,167 @@
+/*
+ * Copyright 2010 JBoss Inc
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.drools.planner.examples.nurserostering.solver;
+    dialect "java"
+
+import org.drools.planner.core.score.calculator.HardAndSoftConstraintScoreCalculator;
+import org.drools.planner.core.score.constraint.IntConstraintOccurrence;
+import org.drools.planner.core.score.constraint.ConstraintType;
+
+import org.drools.planner.examples.nurserostering.domain.DayOfWeek;
+import org.drools.planner.examples.nurserostering.domain.Employee;
+import org.drools.planner.examples.nurserostering.domain.Assignment;
+import org.drools.planner.examples.nurserostering.domain.FreeBefore2DaysWithAWorkDayPattern;
+import org.drools.planner.examples.nurserostering.domain.NurseRoster;
+import org.drools.planner.examples.nurserostering.domain.Pattern;
+import org.drools.planner.examples.nurserostering.domain.RosterInfo;
+import org.drools.planner.examples.nurserostering.domain.Shift;
+import org.drools.planner.examples.nurserostering.domain.ShiftDate;
+import org.drools.planner.examples.nurserostering.domain.ShiftType;
+import org.drools.planner.examples.nurserostering.domain.ShiftType2DaysPattern;
+import org.drools.planner.examples.nurserostering.domain.ShiftType3DaysPattern;
+import org.drools.planner.examples.nurserostering.domain.ShiftTypeSkillRequirement;
+import org.drools.planner.examples.nurserostering.domain.Skill;
+import org.drools.planner.examples.nurserostering.domain.SkillProficiency;
+import org.drools.planner.examples.nurserostering.domain.WeekendDefinition;
+import org.drools.planner.examples.nurserostering.domain.WorkBeforeFreeSequencePattern;
+import org.drools.planner.examples.nurserostering.domain.contract.Contract;
+import org.drools.planner.examples.nurserostering.domain.contract.BooleanContractLine;
+import org.drools.planner.examples.nurserostering.domain.contract.ContractLine;
+import org.drools.planner.examples.nurserostering.domain.contract.ContractLineType;
+import org.drools.planner.examples.nurserostering.domain.contract.MinMaxContractLine;
+import org.drools.planner.examples.nurserostering.domain.contract.PatternContractLine;
+import org.drools.planner.examples.nurserostering.domain.request.DayOffRequest;
+import org.drools.planner.examples.nurserostering.domain.request.DayOnRequest;
+import org.drools.planner.examples.nurserostering.domain.request.ShiftOffRequest;
+import org.drools.planner.examples.nurserostering.domain.request.ShiftOnRequest;
+import org.drools.planner.examples.nurserostering.domain.solver.EmployeeAssignmentTotal;
+import org.drools.planner.examples.nurserostering.domain.solver.EmployeeConsecutiveAssignmentEnd;
+import org.drools.planner.examples.nurserostering.domain.solver.EmployeeConsecutiveAssignmentStart;
+import org.drools.planner.examples.nurserostering.domain.solver.EmployeeConsecutiveWeekendAssignmentEnd;
+import org.drools.planner.examples.nurserostering.domain.solver.EmployeeConsecutiveWeekendAssignmentStart;
+import org.drools.planner.examples.nurserostering.domain.solver.EmployeeFreeSequence;
+import org.drools.planner.examples.nurserostering.domain.solver.EmployeeWeekendSequence;
+import org.drools.planner.examples.nurserostering.domain.solver.EmployeeWorkSequence;
+
+global HardAndSoftConstraintScoreCalculator scoreCalculator;
+
+// ############################################################################
+// Soft constraints
+// ############################################################################
+
+
+rule "insertEmployeeConsecutiveWeekendAssignmentStart"
+        salience 2 // Do these rules first (optional, for performance)
+    when
+        Assignment(
+            weekend == true,
+            $employee : employee,
+            $weekendSundayIndex : weekendSundayIndex
+        )
+        // The first working weekend has no working weekend before it
+        not Assignment(
+            weekend == true,
+            employee == $employee,
+            weekendSundayIndex == ($weekendSundayIndex - 7)
+        )
+    then
+        insertLogical(new EmployeeConsecutiveWeekendAssignmentStart($employee, $weekendSundayIndex));
+end
+rule "insertEmployeeConsecutiveWeekendAssignmentEnd"
+        salience 2 // Do these rules first (optional, for performance)
+    when
+        Assignment(
+            weekend == true,
+            $employee : employee,
+            $weekendSundayIndex : weekendSundayIndex
+        )
+        // The last working weekend has no working weekend after it
+        not Assignment(
+            weekend == true,
+            employee == $employee,
+            weekendSundayIndex == ($weekendSundayIndex + 7)
+        )
+    then
+        insertLogical(new EmployeeConsecutiveWeekendAssignmentEnd($employee, $weekendSundayIndex));
+end
+
+rule "insertEmployeeWeekendSequence"
+        salience 1 // Do these rules first (optional, for performance)
+    when
+        EmployeeConsecutiveWeekendAssignmentStart(
+            $employee : employee,
+            $firstSundayIndex : sundayIndex
+        )
+
+        EmployeeConsecutiveWeekendAssignmentEnd(
+            employee == $employee,
+            sundayIndex >= $firstSundayIndex,
+            $lastSundayIndex : sundayIndex
+        )
+
+        // There are no free weekends between the first and last weekend
+        not EmployeeConsecutiveWeekendAssignmentEnd(
+            employee == $employee,
+            sundayIndex >= $firstSundayIndex && < $lastSundayIndex
+        )
+    then
+        insertLogical(new EmployeeWeekendSequence($employee, $firstSundayIndex, $lastSundayIndex));
+end
+
+// Minimum number of consecutive working weekends
+rule "minimumConsecutiveWorkingWeekends"
+    when
+        $employee : Employee($contract : contract)
+
+        $employeeWeekendSequence : EmployeeWeekendSequence(
+            employee == $employee,
+            weekendLength < 2,
+            $weekendLength : weekendLength
+        )
+    then
+        insertLogical(new IntConstraintOccurrence("minimumConsecutiveWorkingWeekends", ConstraintType.NEGATIVE_SOFT,
+                (2 - $weekendLength),
+                $employeeWeekendSequence));
+end
+
+// ############################################################################
+// Calculate score
+// ############################################################################
+
+// Accumulate hard constraints
+rule "hardConstraintsBroken"
+        salience -1 // Do the other rules first (optional, for performance)
+    when
+        $hardTotal : Number() from accumulate(
+            IntConstraintOccurrence(constraintType == ConstraintType.NEGATIVE_HARD, $weight : weight),
+            sum($weight) // Vote for http://jira.jboss.com/jira/browse/JBRULES-1075
+        )
+    then
+        scoreCalculator.setHardConstraintsBroken($hardTotal.intValue());
+end
+
+// Accumulate soft constraints
+rule "softConstraintsBroken"
+        salience -1 // Do the other rules first (optional, for performance)
+    when
+        $softTotal : Number() from accumulate(
+            IntConstraintOccurrence(constraintType == ConstraintType.NEGATIVE_SOFT, $weight : weight),
+            sum($weight) // Vote for http://jira.jboss.com/jira/browse/JBRULES-1075
+        )
+    then
+        scoreCalculator.setSoftConstraintsBroken($softTotal.intValue());
+end
Index: drools-planner/drools-planner-examples/src/test/java/org/drools/planner/examples/nurserostering/Jbrules2809Part4Test.java
===================================================================
--- drools-planner/drools-planner-examples/src/test/java/org/drools/planner/examples/nurserostering/Jbrules2809Part4Test.java	(revision )
+++ drools-planner/drools-planner-examples/src/test/java/org/drools/planner/examples/nurserostering/Jbrules2809Part4Test.java	(revision )
@@ -0,0 +1,195 @@
+/*
+ * Copyright 2011 JBoss Inc
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.drools.planner.examples.nurserostering;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeMap;
+
+import org.apache.commons.io.IOUtils;
+import org.drools.ClassObjectFilter;
+import org.drools.RuleBase;
+import org.drools.RuleBaseConfiguration;
+import org.drools.RuleBaseFactory;
+import org.drools.StatefulSession;
+import org.drools.WorkingMemory;
+import org.drools.compiler.DroolsParserException;
+import org.drools.compiler.PackageBuilder;
+import org.drools.planner.core.score.Score;
+import org.drools.planner.core.score.calculator.DefaultHardAndSoftConstraintScoreCalculator;
+import org.drools.planner.core.score.calculator.HardAndSoftConstraintScoreCalculator;
+import org.drools.planner.core.score.calculator.ScoreCalculator;
+import org.drools.planner.core.score.constraint.ConstraintOccurrence;
+import org.drools.planner.core.score.constraint.IntConstraintOccurrence;
+import org.drools.planner.examples.common.app.LoggingTest;
+import org.drools.planner.examples.nurserostering.domain.Assignment;
+import org.drools.planner.examples.nurserostering.domain.Employee;
+import org.drools.planner.examples.nurserostering.domain.NurseRoster;
+import org.drools.planner.examples.nurserostering.persistence.NurseRosteringDaoImpl;
+import org.drools.runtime.rule.FactHandle;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * @author Geoffrey De Smet
+ */
+public class Jbrules2809Part4Test extends LoggingTest {
+
+    private static final String DRL_FILE = "/org/drools/planner/examples/nurserostering/solver/nurseRosteringScoreRules_jbrules2809.drl";
+    private static final String DATA_FILE = "/org/drools/planner/examples/nurserostering/data/testMedium_late01_jbrules2809.xml";
+    
+    protected final transient Logger logger = LoggerFactory.getLogger(getClass());
+
+    protected RuleBase ruleBase;
+    protected HardAndSoftConstraintScoreCalculator workingScoreCalculator;
+    protected WorkingMemory workingMemory;
+
+    @Test
+    public void solveComp01_JBRULES2809() {
+        ruleBase = buildRuleBase();
+        workingMemory = ruleBase.newStatefulSession();
+
+        workingScoreCalculator = new DefaultHardAndSoftConstraintScoreCalculator();
+        workingMemory.setGlobal("scoreCalculator", workingScoreCalculator);
+
+        NurseRoster nurseRoster = (NurseRoster) new NurseRosteringDaoImpl().readSolution(getClass().getResourceAsStream(
+                DATA_FILE));
+        for (Object fact : nurseRoster.getFacts()) {
+            workingMemory.insert(fact);
+        }
+
+        Score score;
+        workingMemory.fireAllRules();
+        score = workingScoreCalculator.calculateScore();
+
+        // Recreate move 2010-01-03(Sun)_E->26(26) => 8(8)
+
+        Assignment as29 = findAssignmentById(nurseRoster, 29L);
+        FactHandle as29Handle = workingMemory.getFactHandle(as29);
+        Employee emp8 = findEmployeeById(nurseRoster, 8L);
+
+        as29.setEmployee(emp8);
+        workingMemory.update(as29Handle, as29);
+
+        workingMemory.fireAllRules();
+        score = workingScoreCalculator.calculateScore();
+
+        // This constraint occurrence should have been retracted, but isn't:
+        // ConstraintOccurrence (curriculumCompactness/NEGATIVE_SOFT:[97(course_26{null}-0 @ 2-4 + null), curriculum_11]=2)
+        assertWorkingScore(nurseRoster, score);
+    }
+
+    private RuleBase buildRuleBase() {
+        PackageBuilder packageBuilder = new PackageBuilder();
+        InputStream scoreDrlIn = getClass().getResourceAsStream(DRL_FILE);
+        try {
+            packageBuilder.addPackageFromDrl(new InputStreamReader(scoreDrlIn, "utf-8"));
+        } catch (DroolsParserException e) {
+            throw new IllegalArgumentException("scoreDrl could not be loaded.", e);
+        } catch (IOException e) {
+            throw new IllegalArgumentException("scoreDrl could not be loaded.", e);
+        } finally {
+            IOUtils.closeQuietly(scoreDrlIn);
+        }
+        RuleBaseConfiguration ruleBaseConfiguration = new RuleBaseConfiguration();
+        RuleBase ruleBase = RuleBaseFactory.newRuleBase(ruleBaseConfiguration);
+        if (packageBuilder.hasErrors()) {
+            throw new IllegalStateException("There are errors in the scoreDrl:"
+                    + packageBuilder.getErrors().toString());
+        }
+        ruleBase.addPackage(packageBuilder.getPackage());
+        return ruleBase;
+    }
+
+    private Assignment findAssignmentById(NurseRoster nurseRoster, long id) {
+        for (Assignment assignment : nurseRoster.getAssignmentList()) {
+            if (assignment.getId() == id) {
+                return assignment;
+            }
+        }
+        throw new IllegalArgumentException("Invalid id (" + id + ")");
+    }
+
+    private Employee findEmployeeById(NurseRoster nurseRoster, long id) {
+        for (Employee employee : nurseRoster.getEmployeeList()) {
+            if (employee.getId() == id) {
+                return employee;
+            }
+        }
+        throw new IllegalArgumentException("Invalid id (" + id + ")");
+    }
+
+    /**
+     * @param presumedScore never null
+     */
+    public void assertWorkingScore(NurseRoster nurseRoster, Score presumedScore) {
+        StatefulSession tmpWorkingMemory = ruleBase.newStatefulSession();
+        ScoreCalculator tmpScoreCalculator = workingScoreCalculator.clone();
+        tmpWorkingMemory.setGlobal("scoreCalculator", tmpScoreCalculator);
+        for (Object fact : nurseRoster.getFacts()) {
+            tmpWorkingMemory.insert(fact);
+        }
+        tmpWorkingMemory.fireAllRules();
+        Score realScore = tmpScoreCalculator.calculateScore();
+        tmpWorkingMemory.dispose();
+        if (!presumedScore.equals(realScore)) {
+            throw new IllegalStateException(
+                    "The presumedScore (" + presumedScore + ") is corrupted because it is not the realScore  ("
+                            + realScore + ").\n"
+                            + "Presumed workingMemory:\n" + buildConstraintOccurrenceSummary(workingMemory)
+                            + "Real workingMemory:\n" + buildConstraintOccurrenceSummary(tmpWorkingMemory));
+        }
+    }
+
+    /**
+     * TODO Refactor this with the ConstraintOccurrenceTotal class: https://jira.jboss.org/jira/browse/JBRULES-2510
+     * @param summaryWorkingMemory sometimes null
+     * @return never null
+     */
+    public String buildConstraintOccurrenceSummary(WorkingMemory summaryWorkingMemory) {
+        logger.trace("Building ConstraintOccurrence summary");
+        if (summaryWorkingMemory == null) {
+            return "  The workingMemory is null.";
+        }
+        Map<String, Number> scoreTotalMap = new TreeMap<String, Number>();
+        Iterator<ConstraintOccurrence> it = (Iterator<ConstraintOccurrence>) summaryWorkingMemory.iterateObjects(
+                new ClassObjectFilter(ConstraintOccurrence.class));
+        while (it.hasNext()) {
+            ConstraintOccurrence occurrence = it.next();
+System.out.println("occurrence :" + occurrence);
+            logger.trace("Adding ConstraintOccurrence ({})", occurrence);
+            Number scoreTotalNumber = scoreTotalMap.get(occurrence.getRuleId());
+                int scoreTotal = scoreTotalNumber == null ? 0 : (Integer) scoreTotalNumber;
+                scoreTotal += ((IntConstraintOccurrence) occurrence).getWeight();
+                scoreTotalMap.put(occurrence.getRuleId(), scoreTotal);
+        }
+System.out.println("===");
+        StringBuilder summary = new StringBuilder();
+        for (Map.Entry<String, Number> scoreTotalEntry : scoreTotalMap.entrySet()) {
+            summary.append("  Score rule (").append(scoreTotalEntry.getKey()).append(") has score total (")
+                    .append(scoreTotalEntry.getValue()).append(").\n");
+        }
+        return summary.toString();
+    }
+
+}
Index: drools-planner/drools-planner-examples/src/test/resources/org/drools/planner/examples/nurserostering/data/testMedium_late01_jbrules2809.xml
===================================================================
--- drools-planner/drools-planner-examples/src/test/resources/org/drools/planner/examples/nurserostering/data/testMedium_late01_jbrules2809.xml	(revision )
+++ drools-planner/drools-planner-examples/src/test/resources/org/drools/planner/examples/nurserostering/data/testMedium_late01_jbrules2809.xml	(revision )
@@ -0,0 +1,70 @@
+<NurseRoster id="1">
+  <id>0</id>
+  <code>medium_late01</code>
+  <skillList id="2"/>
+  <shiftTypeList id="4"/>
+  <shiftTypeSkillRequirementList id="9"/>
+  <patternList id="14"/>
+  <contractList id="22"/>
+  <contractLineList id="63"/>
+  <patternContractLineList id="64"/>
+  <employeeList id="93">
+    <Employee id="102">
+      <id>8</id>
+      <code>8</code>
+      <name>8</name>
+    </Employee>
+    <Employee id="120">
+      <id>26</id>
+      <code>26</code>
+      <name>26</name>
+    </Employee>
+  </employeeList>
+  <skillProficiencyList id="124"/>
+  <shiftDateList id="155">
+    <ShiftDate id="168">
+      <id>2</id>
+      <dayIndex>2</dayIndex>
+      <dayOfWeek>SUNDAY</dayOfWeek>
+      <shiftList id="169">
+        <Shift id="170">
+          <id>8</id>
+          <shiftDate reference="168"/>
+          <index>8</index>
+        </Shift>
+      </shiftList>
+    </ShiftDate>
+    <ShiftDate id="204">
+      <id>8</id>
+      <dayIndex>8</dayIndex>
+      <dayOfWeek>SATURDAY</dayOfWeek>
+      <shiftList id="205">
+        <Shift id="209">
+          <id>35</id>
+          <shiftDate reference="204"/>
+          <index>35</index>
+        </Shift>
+      </shiftList>
+    </ShiftDate>
+  </shiftDateList>
+  <shiftList id="324">
+    <Shift reference="170"/>
+    <Shift reference="209"/>
+  </shiftList>
+  <dayOffRequestList id="325"/>
+  <dayOnRequestList id="416"/>
+  <shiftOffRequestList id="417"/>
+  <shiftOnRequestList reference="416"/>
+  <assignmentList id="718">
+    <Assignment id="748"><!-- the one we're changing -->
+      <id>29</id>
+      <shift reference="170"/>
+      <employee reference="120"/><!-- employee 26 -->
+    </Assignment>
+    <Assignment id="850">
+      <id>131</id>
+      <shift reference="209"/>
+      <employee reference="120"/><!-- employee 26 -->
+    </Assignment>
+  </assignmentList>
+</NurseRoster>
