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;
