Index: protocol/src/main/java/geniusweb/protocol/session/SessionResult.java
===================================================================
--- protocol/src/main/java/geniusweb/protocol/session/SessionResult.java	(revision 20)
+++ protocol/src/main/java/geniusweb/protocol/session/SessionResult.java	(revision 20)
@@ -0,0 +1,151 @@
+package geniusweb.protocol.session;
+
+import java.util.Collections;
+import java.util.List;
+
+import com.fasterxml.jackson.annotation.JsonAutoDetect;
+import com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility;
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonTypeInfo;
+
+import geniusweb.issuevalue.Bid;
+import geniusweb.references.PartyWithProfile;
+
+/**
+ * All results collected from running a session. Normally this does not contain
+ * all the details, only the final outcome and other global notes.
+ */
+@JsonAutoDetect(fieldVisibility = Visibility.ANY, getterVisibility = Visibility.NONE, setterVisibility = Visibility.NONE)
+public class SessionResult {
+	private final List<PartyWithProfile> participants;
+	private final Bid agreement;
+	private final List<Double> penalties;
+
+	// add more type info so that jackson can deserialize the actual class
+	@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.WRAPPER_OBJECT)
+	private final Throwable error;
+
+	/**
+	 * 
+	 * @param participants the list oof {@link PartyWithProfile}, in the proper
+	 *                     order (this is relevant for the protocol etc). Should
+	 *                     never be null. Some of them may have entered later of
+	 *                     left early. This list should contain them all.
+	 * @param agreement    the final agreement {@link Bid} of the session. Null
+	 *                     if no agreement was reached.
+	 * @param penalties    the penalties in [0,1] for each participant, same
+	 *                     order as the participants list.
+	 * @param error        a fatal error that terminated the session. Non-fatal
+	 *                     errors (warnings) are not to be reported. Null if no
+	 *                     fatal error occured (session ended following the
+	 *                     protocol). Normally, a fatal error results in no
+	 *                     agreement but there might be protocols that allow a
+	 *                     session to end with an error but stick with a already
+	 *                     reached agreement as well.
+	 */
+	@JsonCreator
+	public SessionResult(
+			@JsonProperty("participants") List<PartyWithProfile> participants,
+			@JsonProperty("agreement") Bid agreement,
+			@JsonProperty("penalties") List<Double> penalties,
+			@JsonProperty("error") Throwable error) {
+		this.participants = participants;
+		this.agreement = agreement;
+		this.penalties = penalties;
+		this.error = error;
+	}
+
+	/**
+	 * 
+	 * @return the list oof {@link PartyWithProfile}, in the proper order (this
+	 *         is relevant for the protocol etc). Should never be null. Some of
+	 *         them may have entered later of left early. This list should
+	 *         contain them all.
+	 */
+	public List<PartyWithProfile> getParticipants() {
+		return Collections.unmodifiableList(participants);
+	}
+
+	/**
+	 * 8return the final agreement {@link Bid} of the session. Null if no
+	 * agreement was reached.
+	 */
+	public Bid getAgreement() {
+		return agreement;
+	};
+
+	/**
+	 * 
+	 * @return list of penalties, in same order as {@link #getParticipants()}.
+	 */
+	public List<Double> getPenalties() {
+		return Collections.unmodifiableList(penalties);
+	}
+
+	/**
+	 * 
+	 * @return a fatal error that terminated the session. Non-fatal errors
+	 *         (warnings) are not to be reported. Null if no fatal error occured
+	 *         (session ended following the protocol). Normally, a fatal error
+	 *         results in no agreement but there might be protocols that allow a
+	 *         session to end with an error but stick with a already reached
+	 *         agreement as well.
+	 */
+	public Throwable getError() {
+		return error;
+	}
+
+	@Override
+	public String toString() {
+		return "SessionResult[" + participants + "," + agreement + ","
+				+ penalties + "," + error + "]";
+	}
+
+	@Override
+	public int hashCode() {
+		final int prime = 31;
+		int result = 1;
+		result = prime * result
+				+ ((agreement == null) ? 0 : agreement.hashCode());
+		result = prime * result + ((error == null) ? 0 : error.hashCode());
+		result = prime * result
+				+ ((participants == null) ? 0 : participants.hashCode());
+		result = prime * result
+				+ ((penalties == null) ? 0 : penalties.hashCode());
+		return result;
+	}
+
+	@Override
+	public boolean equals(Object obj) {
+		if (this == obj)
+			return true;
+		if (obj == null)
+			return false;
+		if (getClass() != obj.getClass())
+			return false;
+		SessionResult other = (SessionResult) obj;
+		if (agreement == null) {
+			if (other.agreement != null)
+				return false;
+		} else if (!agreement.equals(other.agreement))
+			return false;
+		if (error == null) {
+			if (other.error != null)
+				return false;
+		} else if (!error.equals(other.error))
+			return false;
+		if (participants == null) {
+			if (other.participants != null)
+				return false;
+		} else if (!participants.equals(other.participants))
+			return false;
+		if (penalties == null) {
+			if (other.penalties != null)
+				return false;
+		} else if (!penalties.equals(other.penalties))
+			return false;
+		return true;
+	}
+
+}
Index: protocol/src/main/java/geniusweb/protocol/session/SessionState.java
===================================================================
--- protocol/src/main/java/geniusweb/protocol/session/SessionState.java	(revision 18)
+++ protocol/src/main/java/geniusweb/protocol/session/SessionState.java	(revision 20)
@@ -65,3 +65,10 @@
 	 */
 	Bid getAgreement();
+
+	/**
+	 * 
+	 * @return the {@link SessionResult}. Assumes {@link #isFinal(long)}. result
+	 *         may be undefined if not.
+	 */
+	SessionResult getResult();
 }
Index: protocol/src/main/java/geniusweb/protocol/session/saop/SAOPState.java
===================================================================
--- protocol/src/main/java/geniusweb/protocol/session/saop/SAOPState.java	(revision 18)
+++ protocol/src/main/java/geniusweb/protocol/session/saop/SAOPState.java	(revision 20)
@@ -19,4 +19,5 @@
 import geniusweb.protocol.partyconnection.ProtocolToPartyConnections;
 import geniusweb.protocol.session.DefaultSessionState;
+import geniusweb.protocol.session.SessionResult;
 import geniusweb.protocol.session.SessionSettings;
 import geniusweb.references.PartyWithProfile;
@@ -248,3 +249,12 @@
 	}
 
+	@Override
+	public SessionResult getResult() {
+		List<Double> emptylist = new LinkedList<>();
+		for (int n = 0; n < getConnections().size(); n++)
+			emptylist.add(0d);
+		return new SessionResult(getSettings().getAllParties(), getAgreement(),
+				emptylist, getError());
+	}
+
 }
Index: protocol/src/main/java/geniusweb/protocol/session/shaop/BareSHAOPState.java
===================================================================
--- protocol/src/main/java/geniusweb/protocol/session/shaop/BareSHAOPState.java	(revision 18)
+++ protocol/src/main/java/geniusweb/protocol/session/shaop/BareSHAOPState.java	(revision 20)
@@ -1,4 +1,5 @@
 package geniusweb.protocol.session.shaop;
 
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.LinkedList;
@@ -13,4 +14,5 @@
 import geniusweb.protocol.ProtocolException;
 import geniusweb.protocol.partyconnection.ProtocolToPartyConnections;
+import geniusweb.protocol.session.SessionResult;
 import geniusweb.protocol.session.SessionSettings;
 import geniusweb.protocol.session.SessionState;
@@ -169,4 +171,21 @@
 
 	@Override
+	public SessionResult getResult() {
+		Double[] penalties = new Double[partyNumbers.size()];
+		for (PartyId party : partyNumbers.keySet()) {
+			Double spent = totalSpent.get(party);
+			if (spent == null) {
+				spent = 0d;
+			} else {
+				spent = Math.max(0, Math.min(1.0, spent));
+			}
+			penalties[partyNumbers.get(party)] = spent;
+		}
+		return new SessionResult(getSettings().getAllParties(), getAgreement(),
+				Arrays.asList(penalties), getError());
+
+	}
+
+	@Override
 	public int hashCode() {
 		final int prime = 31;
Index: protocol/src/main/java/geniusweb/protocol/tournament/allpermutations/AllPermutationsProtocol.java
===================================================================
--- protocol/src/main/java/geniusweb/protocol/tournament/allpermutations/AllPermutationsProtocol.java	(revision 18)
+++ protocol/src/main/java/geniusweb/protocol/tournament/allpermutations/AllPermutationsProtocol.java	(revision 20)
@@ -6,7 +6,7 @@
 import geniusweb.events.TournamentStarted;
 import geniusweb.protocol.CurrentNegoState;
-import geniusweb.protocol.SessionResult;
 import geniusweb.protocol.partyconnection.ProtocolToPartyConnFactory;
 import geniusweb.protocol.session.SessionProtocol;
+import geniusweb.protocol.session.SessionResult;
 import geniusweb.protocol.session.SessionSettings;
 import geniusweb.protocol.session.SessionState;
@@ -83,7 +83,5 @@
 				// List<TeamOfPartiesAndProfiles> participants =
 				// sessionstate.getSettings().getParticipants()
-				SessionResult result = new SessionResult(
-						sessionstate.getSettings().getAllParties(),
-						sessionstate.getAgreement(), sessionstate.getError());
+				SessionResult result = sessionstate.getResult();
 				state = state.with(result);
 				notifyListeners(new CurrentNegoState(state));
Index: protocol/src/main/java/geniusweb/protocol/tournament/allpermutations/AllPermutationsState.java
===================================================================
--- protocol/src/main/java/geniusweb/protocol/tournament/allpermutations/AllPermutationsState.java	(revision 18)
+++ protocol/src/main/java/geniusweb/protocol/tournament/allpermutations/AllPermutationsState.java	(revision 20)
@@ -6,5 +6,5 @@
 
 import geniusweb.protocol.ProtocolException;
-import geniusweb.protocol.SessionResult;
+import geniusweb.protocol.session.SessionResult;
 import geniusweb.protocol.session.SessionSettings;
 import geniusweb.protocol.tournament.TournamentState;
Index: protocol/src/test/java/geniusweb/protocol/session/DefaultSessionStateTest.java
===================================================================
--- protocol/src/test/java/geniusweb/protocol/session/DefaultSessionStateTest.java	(revision 18)
+++ protocol/src/test/java/geniusweb/protocol/session/DefaultSessionStateTest.java	(revision 20)
@@ -139,3 +139,14 @@
 	}
 
+	@Override
+	public SessionResult getResult() {
+
+		List<Double> emptylist = new LinkedList<>();
+		for (int n = 0; n < getConnections().size(); n++)
+			emptylist.add(0d);
+		return new SessionResult(getSettings().getAllParties(), getAgreement(),
+				emptylist, getError());
+
+	}
+
 }
Index: protocol/src/test/java/geniusweb/protocol/session/SessionResultTest.java
===================================================================
--- protocol/src/test/java/geniusweb/protocol/session/SessionResultTest.java	(revision 18)
+++ protocol/src/test/java/geniusweb/protocol/session/SessionResultTest.java	(revision 20)
@@ -19,5 +19,4 @@
 import geniusweb.issuevalue.DiscreteValue;
 import geniusweb.issuevalue.Value;
-import geniusweb.protocol.SessionResult;
 import geniusweb.references.Parameters;
 import geniusweb.references.PartyRef;
@@ -32,8 +31,10 @@
 
 	private final String ISSUE1 = "issue1";
-	private SessionResult result1, result1a, result2, result3;// , result4;
+	private SessionResult result1, result1a, result2, result3, result4;
 	private String errorstring; // created dynamically: eclipse and maven
 								// generate different stacktrace.
-	private String jsonstring = "{\"participants\":[{\"party\":{\"partyref\":\"party1\",\"parameters\":{}},\"profile\":\"profile1\"},{\"party\":{\"partyref\":\"party2\",\"parameters\":{}},\"profile\":\"profile2\"}],\"agreement\":{\"issuevalues\":{\"issue1\":\"a\"}},\"error\":null}";
+	private String jsonstring = "{\"participants\":[{\"party\":{\"partyref\":\"party1\",\"parameters\":{}},\"profile\":\"profile1\"},{\"party\":{\"partyref\":\"party2\",\"parameters\":{}},\"profile\":\"profile2\"}],\"agreement\":{\"issuevalues\":{\"issue1\":\"a\"}},\"penalties\":[0.0,0.0],\"error\":null}";
+	private List<Double> nopenalties = Arrays.asList(0d, 0d);
+	private List<Double> penalties = Arrays.asList(0.1d, 0.2d);
 
 	@Before
@@ -63,11 +64,15 @@
 
 		result1 = new SessionResult(Arrays.asList(partyprofile1, partyprofile2),
-				bid1, null);
+				bid1, nopenalties, null);
 		result1a = new SessionResult(
-				Arrays.asList(partyprofile1, partyprofile2), bid1, null);
+				Arrays.asList(partyprofile1, partyprofile2), bid1, nopenalties,
+				null);
 		result2 = new SessionResult(Arrays.asList(partyprofile1, partyprofile2),
-				bid2, null);
+				bid2, nopenalties, null);
 		result3 = new SessionResult(Arrays.asList(partyprofile2, partyprofile1),
-				bid2, null);
+				bid2, nopenalties, null);
+		result4 = new SessionResult(Arrays.asList(partyprofile2, partyprofile1),
+				bid2, penalties, null);
+
 		// IGNORE ERROR for now, it fails somewhere deep in maven suddenly.
 		// result4 = new SessionResult(Arrays.asList(partyprofile1,
@@ -78,7 +83,6 @@
 	public List<List<SessionResult>> getGeneralTestData() {
 		return Arrays.asList(Arrays.asList(result1, result1a),
-				Arrays.asList(result2), Arrays.asList(result3)
-		// ,Arrays.asList(result4)
-		);
+				Arrays.asList(result2), Arrays.asList(result3),
+				Arrays.asList(result4));
 	}
 
@@ -86,8 +90,8 @@
 	public List<String> getGeneralTestStrings() {
 		return Arrays.asList(
-				"SessionResult.*party1.*profile1.*,.*party2.*profile2.*Bid.*issue1=\"a\".*null.",
-				"SessionResult.*party1.*profile1.*,.*party2.*profile2.*Bid.*issue1=\"b\".*null.*",
-				"SessionResult.*party2.*profile2.*,.*party1.*profile1.*Bid.*issue1=\"b\".*null.*"
-		// ,"SessionResult.*party1.*profile1.*,.*party2.*profile2.*Bid.*issue1=\"a\".*null.*"
+				"SessionResult.*party1.*profile1.*,.*party2.*profile2.*Bid.*issue1=\"a\".*0\\.0.*0\\.0.*null.*",
+				"SessionResult.*party1.*profile1.*,.*party2.*profile2.*Bid.*issue1=\"b\".*0\\.0.*0\\.0.*null.*",
+				"SessionResult.*party2.*profile2.*,.*party1.*profile1.*Bid.*issue1=\"b\".*0\\.0.*0\\.0.*null.*",
+				"SessionResult.*party2.*profile2.*,.*party1.*profile1.*Bid.*issue1=\"b\".*0\\.1.*0\\.2.*null.*"
 
 		);
Index: protocol/src/test/java/geniusweb/protocol/session/shaop/SHAOPStateTest.java
===================================================================
--- protocol/src/test/java/geniusweb/protocol/session/shaop/SHAOPStateTest.java	(revision 18)
+++ protocol/src/test/java/geniusweb/protocol/session/shaop/SHAOPStateTest.java	(revision 20)
@@ -31,4 +31,5 @@
 import geniusweb.protocol.partyconnection.ProtocolToPartyConn;
 import geniusweb.protocol.partyconnection.ProtocolToPartyConnections;
+import geniusweb.protocol.session.SessionResult;
 import geniusweb.protocol.session.TeamOfPartiesAndProfiles;
 import tudelft.utilities.junit.GeneralTests;
@@ -314,3 +315,15 @@
 	}
 
+	@Test
+	public void getResultTest() {
+
+		Map<PartyId, Double> spent = new HashMap<>();
+		spent.put(party1, 0.1d);
+		SHAOPState state = new SHAOPState(actions, connections4,
+				new ProgressRounds(10, 0, null), settings, null, 0, partynrs,
+				spent);
+		SessionResult res = state.getResult();
+
+	}
+
 }
Index: protocol/src/test/java/geniusweb/protocol/tournament/allpermutations/AllPermutationsProtocolTest.java
===================================================================
--- protocol/src/test/java/geniusweb/protocol/tournament/allpermutations/AllPermutationsProtocolTest.java	(revision 18)
+++ protocol/src/test/java/geniusweb/protocol/tournament/allpermutations/AllPermutationsProtocolTest.java	(revision 20)
@@ -23,7 +23,7 @@
 import geniusweb.protocol.CurrentNegoState;
 import geniusweb.protocol.NegoState;
-import geniusweb.protocol.SessionResult;
 import geniusweb.protocol.partyconnection.ProtocolToPartyConnFactory;
 import geniusweb.protocol.session.SessionProtocol;
+import geniusweb.protocol.session.SessionResult;
 import geniusweb.protocol.session.SessionSettings;
 import geniusweb.protocol.session.SessionState;
@@ -46,4 +46,5 @@
 	private Bid agreement = mock(Bid.class);
 	private final long NOW = 1000;
+	private SessionResult finalstate = mock(SessionResult.class);
 
 	@Before
@@ -53,4 +54,6 @@
 		when(finalsessionstate.getSettings()).thenReturn(settings);
 		when(finalsessionstate.getAgreement()).thenReturn(agreement);
+		when(finalsessionstate.getResult()).thenReturn(finalstate);
+		when(finalstate.getAgreement()).thenReturn(agreement);
 		when(state.with(any())).thenReturn(newstate);
 	}
Index: protocol/src/test/java/geniusweb/protocol/tournament/allpermutations/AllPermutationsStateTest.java
===================================================================
--- protocol/src/test/java/geniusweb/protocol/tournament/allpermutations/AllPermutationsStateTest.java	(revision 18)
+++ protocol/src/test/java/geniusweb/protocol/tournament/allpermutations/AllPermutationsStateTest.java	(revision 20)
@@ -13,5 +13,5 @@
 import org.junit.Test;
 
-import geniusweb.protocol.SessionResult;
+import geniusweb.protocol.session.SessionResult;
 import geniusweb.protocol.session.SessionSettings;
 import geniusweb.references.PartyWithProfile;
