Index: drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/curriculumcourse/domain/Lecture.java
===================================================================
--- drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/curriculumcourse/domain/Lecture.java	(revision 85075744012386e75d3c3a32fea66e75e1c28d2d)
+++ drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/curriculumcourse/domain/Lecture.java	(revision )
@@ -141,7 +141,7 @@
 
     @Override
     public String toString() {
-        return course + "-" + lectureIndexInCourse + " @ " + period + " + " + room;
+        return id + "(" + course + "-" + lectureIndexInCourse + " @ " + period + " + " + room + ")";
     }
 
 }
Index: drools-planner/drools-planner-examples/src/test/resources/org/drools/planner/examples/curriculumcourse/solver/curriculumCourseScoreRules_jbrules2809.drl
===================================================================
--- drools-planner/drools-planner-examples/src/test/resources/org/drools/planner/examples/curriculumcourse/solver/curriculumCourseScoreRules_jbrules2809.drl	(revision )
+++ drools-planner/drools-planner-examples/src/test/resources/org/drools/planner/examples/curriculumcourse/solver/curriculumCourseScoreRules_jbrules2809.drl	(revision )
@@ -0,0 +1,71 @@
+/*
+ * 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.curriculumcourse.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.curriculumcourse.domain.Course;
+import org.drools.planner.examples.curriculumcourse.domain.Curriculum;
+import org.drools.planner.examples.curriculumcourse.domain.CurriculumCourseSchedule;
+import org.drools.planner.examples.curriculumcourse.domain.Day;
+import org.drools.planner.examples.curriculumcourse.domain.Lecture;
+import org.drools.planner.examples.curriculumcourse.domain.Period;
+import org.drools.planner.examples.curriculumcourse.domain.Room;
+import org.drools.planner.examples.curriculumcourse.domain.Teacher;
+import org.drools.planner.examples.curriculumcourse.domain.Timeslot;
+import org.drools.planner.examples.curriculumcourse.domain.UnavailablePeriodConstraint;
+
+global HardAndSoftConstraintScoreCalculator scoreCalculator;
+
+// ############################################################################
+// Soft constraints
+// ############################################################################
+
+// RoomStability: All lectures of a course should be given in the same room.
+// Each distinct room used for the lectures of a course, but the first, counts as 1 point of penalty.
+rule "roomStability"
+    when
+        $course : Course()
+        $roomCount : Number(intValue > 1) from accumulate(
+            $room : Room()
+            and exists Lecture(course == $course, room == $room),
+            count($room)
+        )
+    then
+        insertLogical(new IntConstraintOccurrence("roomStability", ConstraintType.NEGATIVE_SOFT,
+                ($roomCount.intValue() - 1),
+                $course));
+end
+
+// ############################################################################
+// Calculate score
+// ############################################################################
+
+// 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/curriculumcourse/Jbrules2809Part3Test.java
===================================================================
--- drools-planner/drools-planner-examples/src/test/java/org/drools/planner/examples/curriculumcourse/Jbrules2809Part3Test.java	(revision )
+++ drools-planner/drools-planner-examples/src/test/java/org/drools/planner/examples/curriculumcourse/Jbrules2809Part3Test.java	(revision )
@@ -0,0 +1,179 @@
+/*
+ * 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.curriculumcourse;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.Iterator;
+import java.util.Map;
+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.curriculumcourse.domain.CurriculumCourseSchedule;
+import org.drools.planner.examples.curriculumcourse.domain.Lecture;
+import org.drools.planner.examples.curriculumcourse.domain.Period;
+import org.drools.planner.examples.curriculumcourse.persistence.CurriculumCourseDaoImpl;
+import org.drools.runtime.rule.FactHandle;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * @author Geoffrey De Smet
+ */
+public class Jbrules2809Part3Test extends LoggingTest {
+
+    private static final String DRL_FILE = "/org/drools/planner/examples/curriculumcourse/solver/curriculumCourseScoreRules_jbrules2809.drl";
+    private static final String DATA_FILE = "/org/drools/planner/examples/curriculumcourse/data/testComp01_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);
+
+        CurriculumCourseSchedule curriculumCourseSchedule = (CurriculumCourseSchedule) new CurriculumCourseDaoImpl().readSolution(getClass().getResourceAsStream(
+                DATA_FILE));
+        for (Object fact : curriculumCourseSchedule.getFacts()) {
+            workingMemory.insert(fact);
+        }
+
+        Score score;
+        workingMemory.fireAllRules();
+        score = workingScoreCalculator.calculateScore();
+
+        Lecture lec143 = findLectureById(curriculumCourseSchedule, 143L);
+        FactHandle lec143Handle = workingMemory.getFactHandle(lec143);
+
+        // Do no real difference
+        workingMemory.update(lec143Handle, lec143);
+
+        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(curriculumCourseSchedule, 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 Lecture findLectureById(CurriculumCourseSchedule curriculumCourseSchedule, long id) {
+        for (Lecture lecture : curriculumCourseSchedule.getLectureList()) {
+            if (lecture.getId() == id) {
+                return lecture;
+            }
+        }
+        throw new IllegalArgumentException("Invalid id (" + id + ")");
+    }
+
+    /**
+     * @param presumedScore never null
+     */
+    public void assertWorkingScore(CurriculumCourseSchedule curriculumCourseSchedule, Score presumedScore) {
+        StatefulSession tmpWorkingMemory = ruleBase.newStatefulSession();
+        ScoreCalculator tmpScoreCalculator = workingScoreCalculator.clone();
+        tmpWorkingMemory.setGlobal("scoreCalculator", tmpScoreCalculator);
+        for (Object fact : curriculumCourseSchedule.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();
+            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);
+        }
+        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/curriculumcourse/data/testComp01_jbrules2809.xml
===================================================================
--- drools-planner/drools-planner-examples/src/test/resources/org/drools/planner/examples/curriculumcourse/data/testComp01_jbrules2809.xml	(revision )
+++ drools-planner/drools-planner-examples/src/test/resources/org/drools/planner/examples/curriculumcourse/data/testComp01_jbrules2809.xml	(revision )
@@ -0,0 +1,36 @@
+<CurriculumCourseSchedule id="1">
+  <teacherList id="2"/>
+  <curriculumList id="27"/>
+  <courseList id="42">
+    <Course id="91">
+      <id>24</id>
+      <code>c0067</code>
+    </Course>
+  </courseList>
+  <dayList id="103"/>
+  <timeslotList id="109"/>
+  <periodList id="116"/>
+  <roomList id="147">
+    <Room id="151">
+      <id>3</id>
+      <code>F</code>
+    </Room>
+    <Room id="153">
+      <id>5</id>
+      <code>S</code>
+    </Room>
+  </roomList>
+  <unavailablePeriodConstraintList id="154"/>
+  <lectureList id="208">
+    <Lecture id="348">
+      <id>139</id>
+      <course reference="91"/>
+      <room reference="153"/>
+    </Lecture>
+    <Lecture id="352">
+      <id>143</id>
+      <course reference="91"/>
+      <room reference="151"/>
+    </Lecture>
+  </lectureList>
+</CurriculumCourseSchedule>
