diff --git a/app/assets/javascripts/app/collections/comments.js b/app/assets/javascripts/app/collections/comments.js
index efd825988d8fde9bcf00d0db7bd0baf8f721a31b..0b53b8cf0db9ae46323a760cbaa72489df0ec0f0 100644
--- a/app/assets/javascripts/app/collections/comments.js
+++ b/app/assets/javascripts/app/collections/comments.js
@@ -7,5 +7,18 @@ app.collections.Comments = Backbone.Collection.extend({
 
   initialize : function(models, options) {
     this.post = options.post
+  },
+
+  make : function(text){
+    var self = this
+
+    var comment = new app.models.Comment({text: text })
+      , deferred = comment.save({}, {url : self.url()})
+
+    comment.set({author: app.currentUser.toJSON(), parent: self.post })
+
+    this.add(comment)
+
+    return deferred
   }
 });
diff --git a/app/assets/javascripts/app/collections/reshares.js b/app/assets/javascripts/app/collections/reshares.js
new file mode 100644
index 0000000000000000000000000000000000000000..d2c74c8e530a769cff06616cd05e5c5bda0dba75
--- /dev/null
+++ b/app/assets/javascripts/app/collections/reshares.js
@@ -0,0 +1,4 @@
+app.collections.Reshares = Backbone.Collection.extend({
+  model: app.models.Reshare,
+  url : "/reshares"
+});
diff --git a/app/assets/javascripts/app/models/participation.js b/app/assets/javascripts/app/models/participation.js
deleted file mode 100644
index 01c53d9e2be3735a1359a06380752a20321a5ce4..0000000000000000000000000000000000000000
--- a/app/assets/javascripts/app/models/participation.js
+++ /dev/null
@@ -1 +0,0 @@
-app.models.Participation = Backbone.Model.extend({ });
diff --git a/app/assets/javascripts/app/models/post.js b/app/assets/javascripts/app/models/post.js
index e6f01de60d83ed7183ba68e5f16ea7036f065c81..7ed5c69cdea4a4cf669539d2cadc67aff8bb2fa8 100644
--- a/app/assets/javascripts/app/models/post.js
+++ b/app/assets/javascripts/app/models/post.js
@@ -2,27 +2,27 @@ app.models.Post = Backbone.Model.extend(_.extend({}, app.models.formatDateMixin,
   urlRoot : "/posts",
 
   initialize : function() {
-    this.setupCollections();
-    this.bind("change", this.setupCollections, this)
+    this.interactions = new app.models.Post.Interactions(_.extend({post : this}, this.get("interactions")))
+    this.delegateToInteractions()
   },
 
-  setupCollections: function() {
-    this.comments = new app.collections.Comments(this.get("comments") || this.get("last_three_comments"), {post : this});
-    this.likes = this.likes || new app.collections.Likes([], {post : this}); // load in the user like initially
-    this.participations = this.participations || new app.collections.Participations([], {post : this}); // load in the user like initially
+  delegateToInteractions : function(){
+    this.comments = this.interactions.comments
+    this.likes = this.interactions.likes
+
+    this.comment = function(){
+      this.interactions.comment.apply(this.interactions, arguments)
+    }
   },
 
   setFrameName : function(){
-    var templatePicker = new app.models.Post.TemplatePicker(this)
-    this.set({frame_name : templatePicker.getFrameName()})
+    this.set({frame_name : new app.models.Post.TemplatePicker(this).getFrameName()})
   },
 
   interactedAt : function() {
     return this.timeOf("interacted_at");
   },
 
-  createReshareUrl : "/reshares",
-
   reshare : function(){
     return this._reshare = this._reshare || new app.models.Reshare({root_guid : this.get("guid")});
   },
@@ -31,15 +31,6 @@ app.models.Post = Backbone.Model.extend(_.extend({}, app.models.formatDateMixin,
     return this.get("author")
   },
 
-  toggleLike : function() {
-    var userLike = this.get("user_like")
-    if(userLike) {
-      this.unlike()
-    } else {
-      this.like()
-    }
-  },
-
   toggleFavorite : function(options){
     this.set({favorite : !this.get("favorite")})
 
@@ -47,40 +38,6 @@ app.models.Post = Backbone.Model.extend(_.extend({}, app.models.formatDateMixin,
     if(options.save){ this.save() }
   },
 
-  like : function() {
-    var self = this;
-    this.likes.create({}, {success : function(resp){
-      self.set(resp)
-      self.trigger('interacted', self)
-    }});
-
-  },
-
-  unlike : function() {
-    var self = this;
-    var likeModel = new app.models.Like(this.get("user_like"));
-    likeModel.url = this.likes.url + "/" + likeModel.id;
-
-    likeModel.destroy({success : function(model, resp) {
-      self.set(resp);
-      self.trigger('interacted', this)
-    }});
-  },
-
-  comment : function (text) {
-
-    var self = this
-      , postComments = this.comments;
-
-    postComments.create({"text": text}, {
-      url : postComments.url(),
-      wait:true, // added a wait for the time being.  0.5.3 was not optimistic, but 0.9.2 is.
-      error:function () {
-        alert(Diaspora.I18n.t("failed_to_post_message"));
-      }
-    });
-  },
-
   headline : function() {
     var headline = this.get("text").trim()
       , newlineIdx = headline.indexOf("\n")
diff --git a/app/assets/javascripts/app/models/post/interactions.js b/app/assets/javascripts/app/models/post/interactions.js
new file mode 100644
index 0000000000000000000000000000000000000000..0cd51de819b09894278ae95eb75bfb76dc587e64
--- /dev/null
+++ b/app/assets/javascripts/app/models/post/interactions.js
@@ -0,0 +1,116 @@
+//require ../post
+
+app.models.Post.Interactions = Backbone.Model.extend({
+  url : function(){
+    return this.post.url() + "/interactions"
+  },
+
+  initialize : function(options){
+    this.post = options.post
+    this.comments = new app.collections.Comments(this.get("comments"), {post : this.post})
+    this.likes = new app.collections.Likes(this.get("likes"), {post : this.post});
+    this.reshares = new app.collections.Reshares(this.get("reshares"), {post : this.post});
+  },
+
+  parse : function(resp){
+    this.comments.reset(resp.comments)
+    this.likes.reset(resp.likes)
+    this.reshares.reset(resp.reshares)
+
+    var comments = this.comments
+      , likes = this.likes
+      , reshares = this.reshares
+
+    return {
+      comments : comments,
+      likes : likes,
+      reshares : reshares,
+      fetched : true
+    }
+  },
+
+  likesCount : function(){
+    return (this.get("fetched") ? this.likes.models.length : this.get("likes_count") )
+  },
+
+  resharesCount : function(){
+    return this.get("fetched") ? this.reshares.models.length : this.get("reshares_count")
+  },
+
+  commentsCount : function(){
+    return this.get("fetched") ? this.comments.models.length : this.get("comments_count")
+  },
+
+  userLike : function(){
+    return this.likes.select(function(like){ return like.get("author").guid == app.currentUser.get("guid")})[0]
+  },
+
+  userReshare : function(){
+    return this.reshares.select(function(reshare){ return reshare.get("author").guid == app.currentUser.get("guid")})[0]
+  },
+
+  toggleLike : function() {
+    if(this.userLike()) {
+      this.unlike()
+    } else {
+      this.like()
+    }
+  },
+
+  like : function() {
+    var self = this;
+    this.likes.create({}, {success : function(){
+      self.trigger("change")
+      self.set({"likes_count" : self.get("likes_count") + 1})
+    }})
+  },
+
+  unlike : function() {
+    var self = this;
+    this.userLike().destroy({success : function(model, resp) {
+      self.trigger('change')
+      self.set({"likes_count" : self.get("likes_count") - 1})
+    }});
+  },
+
+  comment : function (text) {
+    var self = this;
+
+    this.comments.make(text).fail(function () {
+      alert(Diaspora.I18n.t("failed_to_post_message"));
+    }).done(function() {
+      self.trigger('change') //updates after sync
+    });
+
+    this.trigger("change") //updates count in an eager manner
+  },
+
+  reshare : function(){
+    var interactions = this
+      , reshare = this.post.reshare()
+
+    reshare.save({}, {
+      success : function(resp){
+        var flash = new Diaspora.Widgets.FlashMessages;
+        flash.render({
+          success: true,
+          notice: Diaspora.I18n.t("reshares.successful")
+        });
+      }
+    }).done(function(){
+        interactions.reshares.add(reshare)
+      }).done(function(){
+        interactions.trigger("change")
+      });
+  },
+
+  userCanReshare : function(){
+    var isReshare = this.post.get("post_type") == "Reshare"
+      , rootExists = (isReshare ? this.post.get("root") : true)
+      , publicPost = this.post.get("public")
+      , userIsNotAuthor = this.post.get("author").diaspora_id != app.currentUser.get("diaspora_id")
+      , userIsNotRootAuthor = rootExists && (isReshare ? this.post.get("root").author.diaspora_id != app.currentUser.get("diaspora_id") : true)
+
+    return publicPost && app.currentUser.authenticated() && userIsNotAuthor && userIsNotRootAuthor;
+  }
+});
\ No newline at end of file
diff --git a/app/assets/javascripts/app/models/reshare.js b/app/assets/javascripts/app/models/reshare.js
index 68320eb80e81d228c4aaec76809170b84487bee2..7a4b83ff7d99a7da0daea371fc4cb4335fcf5dd1 100644
--- a/app/assets/javascripts/app/models/reshare.js
+++ b/app/assets/javascripts/app/models/reshare.js
@@ -1,4 +1,6 @@
 app.models.Reshare = app.models.Post.extend({
+  urlRoot : "/reshares",
+
   rootPost : function(){
     this._rootPost = this._rootPost || new app.models.Post(this.get("root"));
     return this._rootPost
diff --git a/app/assets/javascripts/app/pages/post-viewer.js b/app/assets/javascripts/app/pages/post-viewer.js
index 17b0c19f895e3870137bb6fa586703cfc9fa3572..71f1d663d24afac15ff692a1abd88c0e8f9774a1 100644
--- a/app/assets/javascripts/app/pages/post-viewer.js
+++ b/app/assets/javascripts/app/pages/post-viewer.js
@@ -9,8 +9,10 @@ app.pages.PostViewer = app.views.Base.extend({
   },
 
   initialize : function(options) {
-    this.model = new app.models.Post({ id : options.id });
+    var post = this.model = new app.models.Post({ id : options.id });
     this.model.preloadOrFetch().done(_.bind(this.initViews, this));
+    this.model.interactions.fetch() //async, yo, might want to throttle this later.
+
     this.bindEvents()
   },
 
diff --git a/app/assets/javascripts/app/views/comment_stream_view.js b/app/assets/javascripts/app/views/comment_stream_view.js
index c97374fefcc18125882e2217e3f1cdd69a765e4c..fbdda24d5a29fe542668222c34c694d9c8c904e9 100644
--- a/app/assets/javascripts/app/views/comment_stream_view.js
+++ b/app/assets/javascripts/app/views/comment_stream_view.js
@@ -31,8 +31,9 @@ app.views.CommentStream = app.views.Base.extend({
 
   presenter: function(){
     return _.extend(this.defaultPresenter(), {
-      moreCommentsCount : (this.model.get("comments_count") - 3),
-      showExpandCommentsLink : (this.model.get("comments_count") > 3)
+      moreCommentsCount : (this.model.interactions.commentsCount() - 3),
+      showExpandCommentsLink : (this.model.interactions.commentsCount() > 3),
+      commentsCount : this.model.interactions.commentsCount()
     })
   },
 
diff --git a/app/assets/javascripts/app/views/comment_view.js b/app/assets/javascripts/app/views/comment_view.js
index cbed276a5220c1fdf7e2df6660c2f2dea5859118..4a826a33df8dbc7d7e5322b849c3755d02842dea 100644
--- a/app/assets/javascripts/app/views/comment_view.js
+++ b/app/assets/javascripts/app/views/comment_view.js
@@ -4,11 +4,15 @@ app.views.Comment = app.views.Content.extend({
   className : "comment media",
 
   events : function() {
-    return _.extend(app.views.Content.prototype.events, {
+    return _.extend({}, app.views.Content.prototype.events, {
       "click .comment_delete": "destroyModel"
     });
   },
 
+  initialize : function(){
+    this.model.on("change", this.render, this)
+  },
+
   presenter : function() {
     return _.extend(this.defaultPresenter(), {
       canRemove: this.canRemove(),
diff --git a/app/assets/javascripts/app/views/feedback_view.js b/app/assets/javascripts/app/views/feedback_view.js
index 86f83bb7f95abf3fb804de6b4517010db41f966f..57e3a8ac8402e0824f4f69ba3084d8ef5b530bef 100644
--- a/app/assets/javascripts/app/views/feedback_view.js
+++ b/app/assets/javascripts/app/views/feedback_view.js
@@ -1,5 +1,4 @@
 app.views.Feedback = app.views.Base.extend({
-
   templateName: "feedback",
 
   className : "info",
@@ -10,47 +9,30 @@ app.views.Feedback = app.views.Base.extend({
   },
 
   initialize : function() {
-    this.model.bind('interacted', this.render, this);
+    this.model.interactions.on('change', this.render, this);
   },
 
   presenter : function() {
-    return _.extend(this.defaultPresenter(), {
-      userCanReshare : this.userCanReshare()
+    var interactions = this.model.interactions
+
+    return _.extend(this.defaultPresenter(),{
+      commentsCount : interactions.commentsCount(),
+      likesCount : interactions.likesCount(),
+      resharesCount : interactions.resharesCount(),
+      userCanReshare : interactions.userCanReshare(),
+      userLike : interactions.userLike(),
+      userReshare : interactions.userReshare(),
     })
   },
 
   toggleLike: function(evt) {
     if(evt) { evt.preventDefault(); }
-    this.model.toggleLike();
+    this.model.interactions.toggleLike();
   },
 
   resharePost : function(evt) {
     if(evt) { evt.preventDefault(); }
     if(!window.confirm(Diaspora.I18n.t("reshares.post", {name: this.model.reshareAuthor().name}))) { return }
-    var reshare = this.model.reshare()
-    var model = this.model
-
-    reshare.save({}, {
-      url: this.model.createReshareUrl,
-      success : function(resp){
-        var flash = new Diaspora.Widgets.FlashMessages;
-        flash.render({
-          success: true,
-          notice: Diaspora.I18n.t("reshares.successful")
-        });
-        model.trigger("interacted")
-      }
-    });
-  },
-
-  userCanReshare : function() {
-    var isReshare = this.model.get("post_type") == "Reshare"
-    var rootExists = (isReshare ? this.model.get("root") : true)
-
-    var publicPost = this.model.get("public");
-    var userIsNotAuthor = this.model.get("author").diaspora_id != app.currentUser.get("diaspora_id");
-    var userIsNotRootAuthor = rootExists && (isReshare ? this.model.get("root").author.diaspora_id != app.currentUser.get("diaspora_id") : true)
-
-    return publicPost && app.currentUser.authenticated() && userIsNotAuthor && userIsNotRootAuthor;
+    this.model.interactions.reshare();
   }
 });
diff --git a/app/assets/javascripts/app/views/likes_info_view.js b/app/assets/javascripts/app/views/likes_info_view.js
index 5069f8946f448eda5e09fc307569de8b33443e4a..f4f3071bb5d5f3235ce2679fcb9210bff51defd3 100644
--- a/app/assets/javascripts/app/views/likes_info_view.js
+++ b/app/assets/javascripts/app/views/likes_info_view.js
@@ -10,23 +10,19 @@ app.views.LikesInfo = app.views.StreamObject.extend({
   tooltipSelector : ".avatar",
 
   initialize : function() {
-    this.model.bind('expandedLikes', this.render, this)
+    this.model.interactions.bind('change', this.render, this)
   },
 
   presenter : function() {
     return _.extend(this.defaultPresenter(), {
-      likes : this.model.likes.models
+      likes : this.model.interactions.likes.toJSON(),
+      likesCount : this.model.interactions.likesCount(),
+      likes_fetched : this.model.interactions.get("fetched"),
     })
   },
 
   showAvatars : function(evt){
     if(evt) { evt.preventDefault() }
-    var self = this;
-    this.model.likes.fetch()
-      .done(function(resp){
-      // set like attribute and like collection
-      self.model.set({likes : self.model.likes.reset(resp)})
-      self.model.trigger("expandedLikes")
-    })
+    this.model.interactions.fetch()
   }
 });
diff --git a/app/assets/javascripts/app/views/post-viewer/feedback.js b/app/assets/javascripts/app/views/post-viewer/feedback.js
index 7f8584ba419a8295a95191afe6c0ba8d3d56e4b3..de63cbbb16c28404d5f20e6634dea180c598d11f 100644
--- a/app/assets/javascripts/app/views/post-viewer/feedback.js
+++ b/app/assets/javascripts/app/views/post-viewer/feedback.js
@@ -18,6 +18,11 @@ app.views.PostViewerFeedback = app.views.Feedback.extend({
 
   tooltipSelector : ".label, .home-button",
 
+  initialize : function(){
+    this.model.interactions.on("change", this.render, this)
+  },
+
+
   postRenderTemplate : function() {
     this.sneakyVisiblity()
   },
@@ -36,5 +41,4 @@ app.views.PostViewerFeedback = app.views.Feedback.extend({
     alert("you must be logged in to do that!")
     return false;
   }
-
 });
\ No newline at end of file
diff --git a/app/assets/javascripts/app/views/post-viewer/interactions.js b/app/assets/javascripts/app/views/post-viewer/interactions.js
index a0b17600b43c18d8477f0886f2923f09ea7a8654..7d78f72646131441b3dcdd778c7d0da6dd04ac07 100644
--- a/app/assets/javascripts/app/views/post-viewer/interactions.js
+++ b/app/assets/javascripts/app/views/post-viewer/interactions.js
@@ -5,7 +5,8 @@ app.views.PostViewerInteractions = app.views.Base.extend({
   subviews : {
     "#post-feedback" : "feedbackView",
     "#post-reactions" : "reactionsView",
-    "#new-post-comment" : "newCommentView"
+    "#new-post-comment" : "newCommentView",
+    ".interaction_counts" : "interactionCountsView"
   },
 
   templateName: "post-viewer/interactions",
@@ -18,7 +19,7 @@ app.views.PostViewerInteractions = app.views.Base.extend({
   },
 
   initViews : function() {
-    this.reactionsView = new app.views.PostViewerReactions({ model : this.model })
+    this.reactionsView = new app.views.PostViewerReactions({ model : this.model.interactions })
 
     /* subviews that require user */
     this.feedbackView = new app.views.PostViewerFeedback({ model : this.model })
diff --git a/app/assets/javascripts/app/views/post-viewer/new_comment.js b/app/assets/javascripts/app/views/post-viewer/new_comment.js
index 16775a80c340914960718c5c736f81966f03f64c..f31da66ca4a7f8929bf576f643c93a1bda55144c 100644
--- a/app/assets/javascripts/app/views/post-viewer/new_comment.js
+++ b/app/assets/javascripts/app/views/post-viewer/new_comment.js
@@ -10,7 +10,7 @@ app.views.PostViewerNewComment = app.views.Base.extend({
   scrollableArea : "#post-reactions",
 
   initialize : function(){
-    this.model.comments.bind("sync", this.clearAndReactivateForm, this)
+    this.model.interactions.comments.bind("sync", this.clearAndReactivateForm, this)
   },
 
   postRenderTemplate : function() {
@@ -25,7 +25,6 @@ app.views.PostViewerNewComment = app.views.Base.extend({
   },
 
   clearAndReactivateForm : function() {
-    this.model.trigger("interacted")
     this.toggleFormState()
     this.$("textarea").val("")
       .css('height', '18px')
diff --git a/app/assets/javascripts/app/views/post-viewer/reactions.js b/app/assets/javascripts/app/views/post-viewer/reactions.js
index 145ed1b02a18a59655214de468eef2ecf969e317..1447bde224c249355fef95afb00726935252144b 100644
--- a/app/assets/javascripts/app/views/post-viewer/reactions.js
+++ b/app/assets/javascripts/app/views/post-viewer/reactions.js
@@ -7,7 +7,16 @@ app.views.PostViewerReactions = app.views.Base.extend({
   tooltipSelector : ".avatar",
 
   initialize : function() {
-    this.model.bind('interacted', this.render, this);
+    this.model.on('change', this.render, this);
+    this.model.comments.bind("add", this.appendComment, this)
+  },
+
+  presenter : function(){
+    return {
+      likes : this.model.likes.toJSON(),
+      comments : this.model.comments.toJSON(),
+      reshares : this.model.reshares.toJSON()
+    }
   },
 
   postRenderTemplate : function() {
@@ -21,14 +30,15 @@ app.views.PostViewerReactions = app.views.Base.extend({
 
   /* copy pasta from commentStream */
   appendComment: function(comment) {
-    // Set the post as the comment's parent, so we can check
-    // on post ownership in the Comment view.
-    comment.set({parent : this.model.toJSON()})
+    // Set the post as the comment's parent, so we can check on post ownership in the Comment view.
+    // model was post on old view, is interactions on new view
+
+    var parent = this.model.get("post_type") ? this.model.toJSON : this.model.post.toJSON()
+    comment.set({parent : parent})
 
     this.$("#post-comments").append(new app.views.Comment({
       model: comment,
       className : "post-comment media"
     }).render().el);
   }
-
 });
\ No newline at end of file
diff --git a/app/assets/templates/comment-stream.jst.hbs b/app/assets/templates/comment-stream.jst.hbs
index 200235fdaff9c73512c0c17a558ea8e430cbcf7a..a41b612d9f814620c42cd6cbde493752db84ca39 100644
--- a/app/assets/templates/comment-stream.jst.hbs
+++ b/app/assets/templates/comment-stream.jst.hbs
@@ -11,7 +11,7 @@
 <div class="comments"> </div>
 
 {{#if loggedIn}}
-  <div class="comment no-border media new_comment_form_wrapper {{#unless comments_count}} hidden {{/unless}}">
+  <div class="comment no-border media new_comment_form_wrapper {{#unless commentsCount}} hidden {{/unless}}">
     {{#with current_user}}
       <a href="/people/{{guid}}" class="img">
         {{{personImage this}}}
diff --git a/app/assets/templates/feedback.jst.hbs b/app/assets/templates/feedback.jst.hbs
index f22facbd23167b1b7f7a0bef5e6928fed5532a6a..bdf99a2af3611573f2ec7f4deb50bf875a2c3bc9 100644
--- a/app/assets/templates/feedback.jst.hbs
+++ b/app/assets/templates/feedback.jst.hbs
@@ -15,7 +15,7 @@
 
 
 <a href="#" class="like_action" rel='nofollow'>
-  {{#if user_like}}
+  {{#if userLike}}
     {{t "stream.unlike"}}
   {{else}}
     {{t "stream.like"}}
diff --git a/app/assets/templates/likes-info.jst.hbs b/app/assets/templates/likes-info.jst.hbs
index 6a833be78c5e0f8596a913c2749ce2789459b871..6820ffb0547857745af3704026a0e277367963c3 100644
--- a/app/assets/templates/likes-info.jst.hbs
+++ b/app/assets/templates/likes-info.jst.hbs
@@ -1,4 +1,4 @@
-{{#if likes_count}}
+{{#if likesCount}}
   <div class="comment">
     <div class="media">
       <span class="img">
@@ -6,21 +6,20 @@
       </span>
 
       <div class="bd">
-        {{#unless likes.length}}
+        {{#unless likes_fetched}}
           <a href="#" class="expand_likes grey">
-            {{t "stream.likes" count=likes_count}}
+            {{t "stream.likes" count=likesCount}}
           </a>
 
         {{else}}
 
           {{#each likes}}
-            {{#with attributes.author}}
+            {{#with author}}
               <a href="/people/{{guid}}">
                 <img src="{{avatar.small}}" class="avatar micro" title="{{name}}"/>
               </a>
             {{/with}}
           {{/each}}
-
         {{/unless}}
       </div>
     </div>
diff --git a/app/assets/templates/post-viewer/feedback.jst.hbs b/app/assets/templates/post-viewer/feedback.jst.hbs
index 742d052c59e4afbe2c718b0ce44084298f1af020..823db8cf92c40825ca5ece33e18c8830661e91ae 100644
--- a/app/assets/templates/post-viewer/feedback.jst.hbs
+++ b/app/assets/templates/post-viewer/feedback.jst.hbs
@@ -1,35 +1,35 @@
-<a href="#" rel="auth-required" class="label like" title="{{#if user_like}} {{t "viewer.unlike"}} {{else}} {{t "viewer.like"}} {{/if}}">
-  {{#if user_like}}
+<a href="#" rel="auth-required" class="label like" title="{{#if userLike}} {{t "viewer.unlike"}} {{else}} {{t "viewer.like"}} {{/if}}">
+  {{#if userLike}}
     <i class="icon-heart icon-red"></i>
   {{else}}
     <i class="icon-heart icon-white"></i>
   {{/if}}
-  {{likes_count}}
+  {{likesCount}}
 </a>
 
 {{#if userCanReshare}}
-  <a href="#" rel="auth-required" class="label reshare" title="{{#if user_reshare}} {{t "viewer.reshared"}} {{else}} {{t "viewer.reshare"}} {{/if}}">
-    {{#if user_reshare}}
+  <a href="#" rel="auth-required" class="label reshare" title="{{#if userReshare}} {{t "viewer.reshared"}} {{else}} {{t "viewer.reshare"}} {{/if}}">
+    {{#if userReshare}}
       <i class="icon-retweet icon-blue"></i>
     {{else}}
       <i class="icon-retweet icon-white"></i>
     {{/if}}
-    {{reshares_count}}
+    {{resharesCount}}
   </a>
 {{else}}
-  <a class="label reshare-viewonly" title="{{#if user_reshare}} {{t "viewer.reshared"}} {{else}} {{t "viewer.reshare"}} {{/if}}">
-    {{#if user_reshare}}
+  <a class="label reshare-viewonly" title="{{#if userReshare}} {{t "viewer.reshared"}} {{else}} {{t "viewer.reshare"}} {{/if}}">
+    {{#if userReshare}}
       <i class="icon-retweet icon-blue"></i>
     {{else}}
       <i class="icon-retweet icon-white"></i>
     {{/if}}
-    {{reshares_count}}
+    {{resharesCount}}
    </a>
 {{/if}}
 
 <a href="#" class="label comment" rel="invoke-interaction-pane" title="{{t "viewer.comment"}}">
   <i class="icon-comment icon-white"></i>
-  {{comments_count}}
+  {{commentsCount}}
 </a>
 
 <!-- this acts as a dock underlay -->
diff --git a/app/assets/templates/small-frame.jst.hbs b/app/assets/templates/small-frame.jst.hbs
index 51b7158b53349e28144fd9a9bc087bd7d40fa6d8..8c07e73107cea9ed578d6b5e1bb8e79181d9c9b4 100644
--- a/app/assets/templates/small-frame.jst.hbs
+++ b/app/assets/templates/small-frame.jst.hbs
@@ -38,9 +38,9 @@
         <i class="icon-time timestamp" title="{{created_at}}" rel="tooltip"></i>
         <i class="icon-chevron-right permalink" title="View Post" rel="tooltip"></i>
 
-        <i class="icon-heart"></i> {{likes_count}}
-        <i class="icon-retweet"></i> {{reshares_count}}
-        <i class="icon-comment"></i> {{comments_count}}
+        <i class="icon-heart"></i> {{likesCount}}
+        <i class="icon-retweet"></i> {{resharesCount}}
+        <i class="icon-comment"></i> {{commentsCount}}
 
     </div>
 </div>
diff --git a/app/controllers/comments_controller.rb b/app/controllers/comments_controller.rb
index 58b683405702374ecc539b325490364b651f118e..d8f43fc3d8342f0395b54283110282268161ccea 100644
--- a/app/controllers/comments_controller.rb
+++ b/app/controllers/comments_controller.rb
@@ -56,7 +56,7 @@ class CommentsController < ApplicationController
 
     @comments = @post.comments.for_a_stream
     respond_with do |format|
-      format.json  { render :json => CommentPresenter.new(@comments), :status => 200 }
+      format.json  { render :json => CommentPresenter.as_collection(@comments), :status => 200 }
       format.mobile{render :layout => false}
     end
   end
diff --git a/app/controllers/likes_controller.rb b/app/controllers/likes_controller.rb
index 1eaf0faa159c2702fdbad7b989147332bf18e50a..1d99009f5e7b33b7a3e56d10789683e83a51662c 100644
--- a/app/controllers/likes_controller.rb
+++ b/app/controllers/likes_controller.rb
@@ -13,13 +13,13 @@ class LikesController < ApplicationController
              :json
 
   def create
-    @like = current_user.like!(target) if target
+    @like = current_user.like!(target) if target rescue ActiveRecord::RecordInvalid
 
     if @like
       respond_to do |format|
         format.html { render :nothing => true, :status => 201 }
         format.mobile { redirect_to post_path(@like.post_id) }
-        format.json { render :json => find_json_for_like, :status => 201 }
+        format.json { render :json => @like.as_api_response(:backbone), :status => 201 }
       end
     else
       render :nothing => true, :status => 422
@@ -27,32 +27,22 @@ class LikesController < ApplicationController
   end
 
   def destroy
-    @like = Like.where(:id => params[:id], :author_id => current_user.person.id).first
+    @like = Like.find_by_id_and_author_id!(params[:id], current_user.person.id)
 
-    if @like
-      current_user.retract(@like)
-      respond_to do |format|
-        format.json { render :json => find_json_for_like, :status => 202 }
-      end
-    else
-      respond_to do |format|
-        format.mobile { redirect_to :back }
-        format.json { render :nothing => true, :status => 403}
-      end
+    current_user.retract(@like)
+    respond_to do |format|
+      format.json { render :nothing => true, :status => 204 }
     end
   end
 
+  #I can go when the old stream goes.
   def index
-    if target
-      @likes = target.likes.includes(:author => :profile)
-      @people = @likes.map(&:author)
+    @likes = target.likes.includes(:author => :profile)
+    @people = @likes.map(&:author)
 
-      respond_to do |format|
-        format.all{ render :layout => false }
-        format.json{ render :json => @likes.as_api_response(:backbone) }
-      end
-    else
-      render :nothing => true, :status => 404
+    respond_to do |format|
+      format.all { render :layout => false }
+      format.json { render :json => @likes.as_api_response(:backbone) }
     end
   end
 
@@ -60,21 +50,11 @@ class LikesController < ApplicationController
 
   def target
     @target ||= if params[:post_id]
-      current_user.find_visible_shareable_by_id(Post, params[:post_id])
+      current_user.find_visible_shareable_by_id(Post, params[:post_id]) || raise(ActiveRecord::RecordNotFound.new)
     else
-      comment = Comment.find(params[:comment_id])
-      comment = nil unless current_user.find_visible_shareable_by_id(Post, comment.commentable_id)
-      comment
-    end
-  end
-
-  def find_json_for_like
-    if @like.parent.is_a? Post
-      ExtremePostPresenter.new(@like.parent, current_user).as_json
-    elsif @like.parent.is_a? Comment
-      CommentPresenter.new(@like.parent)
-    else
-      @like.parent.respond_to?(:as_api_response) ? @like.parent.as_api_response(:backbone) : @like.parent.as_json
+      Comment.find(params[:comment_id]).tap do |comment|
+       raise(ActiveRecord::RecordNotFound.new) unless current_user.find_visible_shareable_by_id(Post, comment.commentable_id)
+      end
     end
   end
 end
diff --git a/app/controllers/participations_controller.rb b/app/controllers/participations_controller.rb
deleted file mode 100644
index 64336862106861b122563f0fd5e95bc0450e27bd..0000000000000000000000000000000000000000
--- a/app/controllers/participations_controller.rb
+++ /dev/null
@@ -1,68 +0,0 @@
-#   Copyright (c) 2010-2011, Diaspora Inc.  This file is
-#   licensed under the Affero General Public License version 3 or later.  See
-#   the COPYRIGHT file.
-
-require Rails.root.join("app", "presenters", "post_presenter")
-
-class ParticipationsController < ApplicationController
-  include ApplicationHelper
-  before_filter :authenticate_user!
-
-  respond_to :mobile,
-             :json
-
-  def create
-    @participation = current_user.participate!(target) if target
-
-    if @participation
-      respond_to do |format|
-        format.mobile { redirect_to post_path(@participation.post_id) }
-        format.json { render :json => ExtremePostPresenter.new(@participation.parent, current_user), :status => 201 }
-      end
-    else
-      render :nothing => true, :status => 422
-    end
-  end
-
-  def destroy
-    @participation = Participation.where(:id => params[:id], :author_id => current_user.person.id).first
-
-    if @participation
-      current_user.retract(@participation)
-      respond_to do |format|
-        format.json { render :json => ExtremePostPresenter.new(@participation.parent, current_user), :status => 202 }
-      end
-    else
-      respond_to do |format|
-        format.mobile { redirect_to :back }
-        format.json { render :nothing => true, :status => 403}
-      end
-    end
-  end
-
-  def index
-    if target
-      @participations = target.participations.includes(:author => :profile)
-      @people = @participations.map(&:author)
-
-      respond_to do |format|
-        format.all{ render :layout => false }
-        format.json{ render :json => @participations.as_api_response(:backbone) }
-      end
-    else
-      render :nothing => true, :status => 404
-    end
-  end
-
-  protected
-
-  def target
-    @target ||= if params[:post_id]
-      current_user.find_visible_shareable_by_id(Post, params[:post_id])
-    else
-      comment = Comment.find(params[:comment_id])
-      comment = nil unless current_user.find_visible_shareable_by_id(Post, comment.commentable_id)
-      comment
-    end
-  end
-end
diff --git a/app/controllers/posts_controller.rb b/app/controllers/posts_controller.rb
index 711f2561d680ebd93fc5841fd98a7eb2f21d23c2..761028768c84841b1d117f1cb11565f166df9501 100644
--- a/app/controllers/posts_controller.rb
+++ b/app/controllers/posts_controller.rb
@@ -9,7 +9,7 @@ class PostsController < ApplicationController
   
   before_filter :authenticate_user!, :except => [:show, :iframe, :oembed]
   before_filter :set_format_if_malformed_from_status_net, :only => :show
-  before_filter :find_post, :only => [:show, :next, :previous]
+  before_filter :find_post, :only => [:show, :next, :previous, :interactions]
 
   layout 'post'
 
@@ -25,15 +25,13 @@ class PostsController < ApplicationController
   end
 
   def show
-    return log_and_redirect_back unless @post
-
     mark_corresponding_notification_read if user_signed_in?
 
     respond_to do |format|
-      format.html{ gon.post = ExtremePostPresenter.new(@post, current_user); render 'posts/show.html.haml' }
+      format.html{ gon.post = PostPresenter.new(@post, current_user); render 'posts/show.html.haml' }
       format.xml{ render :xml => @post.to_diaspora_xml }
       format.mobile{render 'posts/show.mobile.haml', :layout => "application"}
-      format.json{ render :json => ExtremePostPresenter.new(@post, current_user) }
+      format.json{ render :json => PostPresenter.new(@post, current_user) }
     end
   end
 
@@ -43,7 +41,7 @@ class PostsController < ApplicationController
 
   def oembed
     post_id = OEmbedPresenter.id_from_url(params.delete(:url))
-    post = find_by_guid_or_id_with_current_user(post_id) 
+    post = Post.find_by_guid_or_id_with_user(post_id, current_user)
     if post.present?
       oembed = OEmbedPresenter.new(post, params.slice(:format, :maxheight, :minheight))
       render :json => oembed
@@ -52,72 +50,54 @@ class PostsController < ApplicationController
     end
   end
 
-  def destroy
-    @post = current_user.posts.where(:id => params[:id]).first
-    if @post
-      current_user.retract(@post)
-      respond_to do |format|
-        format.js {render 'destroy'}
-        format.json { render :nothing => true, :status => 204 }
-        format.all {redirect_to stream_path}
-      end
-    else
-      Rails.logger.info "event=post_destroy status=failure user=#{current_user.diaspora_handle} reason='User does not own post'"
-      render :nothing => true, :status => 404
-    end
-  end
-
-  def update
-    @post = current_user.posts.find(params[:id])
-    if @post
-      @post.favorite = !@post.favorite
-      @post.save
-      render :nothing => true, :status => 202
-    end
-  end
-
   def next
-    next_post = visible_posts_from_author.newer(@post)
+    next_post = Post.visible_from_author(@post.author, current_user).newer(@post)
 
     respond_to do |format|
       format.html{ redirect_to post_path(next_post) }
-      format.json{ render :json => ExtremePostPresenter.new(next_post, current_user)}
+      format.json{ render :json => PostPresenter.new(next_post, current_user)}
     end
   end
 
   def previous
-    previous_post = visible_posts_from_author.older(@post)
+    previous_post = Post.visible_from_author(@post.author, current_user).older(@post)
 
     respond_to do |format|
       format.html{ redirect_to post_path(previous_post) }
-      format.json{ render :json => ExtremePostPresenter.new(previous_post, current_user)}
+      format.json{ render :json => PostPresenter.new(previous_post, current_user)}
     end
   end
 
-  protected
+  def interactions
+    respond_with(PostInteractionPresenter.new(@post, current_user))
+  end
+
+  def destroy
+    find_current_user_post(params[:id])
+    current_user.retract(@post)
 
-  def log_and_redirect_back #preserving old functionality, but this should probably be removed
-    user_id = (user_signed_in? ? current_user : nil)
-    Rails.logger.info(":event => :link_to_nonexistent_post, :ref => #{request.env['HTTP_REFERER']}, :user_id => #{user_id}, :post_id => #{params[:id]}")
-    flash[:error] = I18n.t('posts.show.not_found')
-    redirect_to :back
+    respond_to do |format|
+      format.js { render 'destroy' }
+      format.json { render :nothing => true, :status => 204 }
+      format.all { redirect_to stream_path }
+    end
   end
 
-  def find_post
-    @post = find_by_guid_or_id_with_current_user(params[:id])
+  def update
+    find_current_user_post(params[:id])
+    @post.favorite = !@post.favorite
+    @post.save
+    render :nothing => true, :status => 202
   end
 
-  def visible_posts_from_author
-    Post.visible_from_author(@post.author, current_user)
+  protected
+
+  def find_post #checks whether current user can see it
+    @post = Post.find_by_guid_or_id_with_user(params[:id], current_user)
   end
 
-  def find_by_guid_or_id_with_current_user(id)
-    key = id.to_s.length <= 8 ? :id : :guid
-    if user_signed_in?
-      current_user.find_visible_shareable_by_id(Post, id, :key => key)
-    else
-      Post.where(key => id, :public => true).includes(:author, :comments => :author).first
-    end
+  def find_current_user_post(id) #makes sure current_user can modify
+    @post = current_user.posts.find(id)
   end
 
   def set_format_if_malformed_from_status_net
diff --git a/app/models/post.rb b/app/models/post.rb
index 1dc27a93d2f84950aeea0e150a228b4e28ce6e81..6e24533a7f28d57a20c938131a15936898759ab6 100644
--- a/app/models/post.rb
+++ b/app/models/post.rb
@@ -143,4 +143,15 @@ class Post < ActiveRecord::Base
   def nsfw
     self.author.profile.nsfw?
   end
+
+  def self.find_by_guid_or_id_with_user(id, user=nil)
+    key = id.to_s.length <= 8 ? :id : :guid
+    post = if user
+             user.find_visible_shareable_by_id(Post, id, :key => key)
+           else
+             Post.where(key => id, :public => true).includes(:author, :comments => :author).first
+           end
+
+    post || raise(ActiveRecord::RecordNotFound.new("could not find a post with id #{id}"))
+  end
 end
diff --git a/app/presenters/extreme_post_presenter.rb b/app/presenters/extreme_post_presenter.rb
index 49d872a185da22ab0f4ad42bd85326e8dd0f4e65..c35b54088476a7d27514c47b61e8a11a87f64dd2 100644
--- a/app/presenters/extreme_post_presenter.rb
+++ b/app/presenters/extreme_post_presenter.rb
@@ -9,6 +9,6 @@ class ExtremePostPresenter
   def as_json(options={})
     post = PostPresenter.new(@post, @current_user)
     interactions = PostInteractionPresenter.new(@post, @current_user)
-    post.as_json.merge!(interactions.as_json)
+    post.as_json.merge!(:interactions => interactions.as_json)
   end
 end
\ No newline at end of file
diff --git a/app/presenters/last_three_comments_decorator.rb b/app/presenters/last_three_comments_decorator.rb
index 884d0dc4916332eb1e5c8055568473cbe61521ed..04e1c91b344c197685631b5a3e192571d6105633 100644
--- a/app/presenters/last_three_comments_decorator.rb
+++ b/app/presenters/last_three_comments_decorator.rb
@@ -4,6 +4,8 @@ class LastThreeCommentsDecorator
   end
 
   def as_json(options={})
-    @presenter.as_json.merge({:last_three_comments => CommentPresenter.as_collection(@presenter.post.last_three_comments)})
+    @presenter.as_json.tap do |post|
+      post[:interactions].merge!(:comments => CommentPresenter.as_collection(@presenter.post.last_three_comments))
+    end
   end
 end
\ No newline at end of file
diff --git a/app/presenters/post_presenter.rb b/app/presenters/post_presenter.rb
index 40b2fb95422e45763482d7650f4da649083b8114..151f51176d6b2d6c3417ac169b0dfb5c669bc0f2 100644
--- a/app/presenters/post_presenter.rb
+++ b/app/presenters/post_presenter.rb
@@ -20,9 +20,6 @@ class PostPresenter
         :public => @post.public,
         :created_at => @post.created_at,
         :interacted_at => @post.interacted_at,
-        :comments_count => @post.comments_count,
-        :likes_count => @post.likes_count,
-        :reshares_count => @post.reshares_count,
         :provider_display_name => @post.provider_display_name,
         :post_type => @post.post_type,
         :image_url => @post.image_url,
@@ -38,8 +35,14 @@ class PostPresenter
         :title => title,
         :next_post => next_post_path,
         :previous_post => previous_post_path,
-        :user_like => user_like,
-        :user_reshare => user_reshare
+
+        :interactions => {
+            :likes => [user_like].compact,
+            :reshares => [user_reshare].compact,
+            :comments_count => @post.comments_count,
+            :likes_count => @post.likes_count,
+            :reshares_count => @post.reshares_count,
+        }
     }
   end
 
diff --git a/config/routes.rb b/config/routes.rb
index 9944d9e84b8d8c3b930d5667d144b92b9ba14ece..249eea6e048331a36e4eaf9e5743772381f8869e 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -17,8 +17,10 @@ Diaspora::Application.routes.draw do
     member do
       get :next
       get :previous
+      get :interactions
     end
-    resources :likes, :only => [:create, :destroy, :index]
+
+    resources :likes, :only => [:create, :destroy, :index ]
     resources :participations, :only => [:create, :destroy, :index]
     resources :comments, :only => [:new, :create, :destroy, :index]
   end
diff --git a/features/post_viewer.feature b/features/post_viewer.feature
index 7841367591d217f250720a2061ea4a394590809f..e099c3c9785d62dddc26fac5ce50b2e926d2e2c7 100644
--- a/features/post_viewer.feature
+++ b/features/post_viewer.feature
@@ -7,9 +7,10 @@ Feature: Post Viewer
   Background:
     Given a user with email "alice@alice.com"
     And I sign in as "alice@alice.com"
-    
-  @wip
-  Scenario: Paging through posts
-    Given I have posts for each type of template
-    Then I visit all of my posts
-    And I should have seen all of my posts displayed with the correct template
+
+#  Wip tag sad on new cucumber, commenting for now.
+#  @wip
+#  Scenario: Paging through posts
+#    Given I have posts for each type of template
+#    Then I visit all of my posts
+#    And I should have seen all of my posts displayed with the correct template
diff --git a/lib/federated/generator.rb b/lib/federated/generator.rb
index ba90546dbf398a3e5b32250edb8fc28a76de1981..96fe9006c640729bd09d4c9f80e03a5feb41d4ab 100644
--- a/lib/federated/generator.rb
+++ b/lib/federated/generator.rb
@@ -7,7 +7,7 @@ module Federated
 
     def create!(options={})
       relayable = build(options)
-      if relayable.save
+      if relayable.save!
         FEDERATION_LOGGER.info("user:#{@user.id} dispatching #{relayable.class}:#{relayable.guid}")
         Postzord::Dispatcher.defer_build_and_post(@user, relayable)
         relayable
diff --git a/spec/controllers/likes_controller_spec.rb b/spec/controllers/likes_controller_spec.rb
index 1b91262ca0f7f9f198c1c12c95a15ed7ffd489fe..8b27516b9f73665c74f3693ccaea5901a9299a59 100644
--- a/spec/controllers/likes_controller_spec.rb
+++ b/spec/controllers/likes_controller_spec.rb
@@ -1,4 +1,4 @@
-#   Copyright (c) 2010-2011, Diaspora Inc.  This file is
+  #   Copyright (c) 2010-2011, Diaspora Inc.  This file is
 #   licensed under the Affero General Public License version 3 or later.  See
 #   the COPYRIGHT file.
 
@@ -88,7 +88,7 @@ describe LikesController do
 
         it 'returns a 404 for a post not visible to the user' do
           sign_in eve
-          get :index, id_field => @message.id
+          expect{get :index, id_field => @message.id}.to raise_error(ActiveRecord::RecordNotFound)
         end
 
         it 'returns an array of likes for a post' do
@@ -114,22 +114,19 @@ describe LikesController do
           expect {
             delete :destroy, :format => :json, id_field => @like.target_id, :id => @like.id
           }.should change(Like, :count).by(-1)
-          response.status.should == 202
+          response.status.should == 204
         end
 
         it 'does not let a user destroy other likes' do
           like2 = eve.like!(@message)
 
+          like_count = Like.count
           expect {
             delete :destroy, :format => :json, id_field => like2.target_id, :id => like2.id
-          }.should_not change(Like, :count)
+          }.should raise_error(ActiveRecord::RecordNotFound)
 
-          response.status.should == 403
-        end
+          Like.count.should == like_count
 
-        it 'returns the parent post presenter' do
-          delete :destroy, :format => :json, id_field => @like.target_id, :id => @like.id
-          response.body.should include 'post' if class_const != Comment
         end
       end
     end
diff --git a/spec/controllers/participations_controller_spec.rb b/spec/controllers/participations_controller_spec.rb
deleted file mode 100644
index 63970b7a189616d33f15826e4948237ea833bf69..0000000000000000000000000000000000000000
--- a/spec/controllers/participations_controller_spec.rb
+++ /dev/null
@@ -1,128 +0,0 @@
-#   Copyright (c) 2010-2011, Diaspora Inc.  This file is
-#   licensed under the Affero General Public License version 3 or later.  See
-#   the COPYRIGHT file.
-
-require 'spec_helper'
-
-describe ParticipationsController do
-  before do
-    @alices_aspect = alice.aspects.where(:name => "generic").first
-    @bobs_aspect = bob.aspects.where(:name => "generic").first
-
-    sign_in :user, alice
-  end
-
-  context "Posts" do
-      let(:id_field){ "post_id" }
-
-    describe '#create' do
-      let(:participation_hash) {
-        { id_field => "#{@target.id}",
-          :format => :json}
-      }
-      let(:disparticipation_hash) {
-        { id_field => "#{@target.id}",
-          :format => :json }
-      }
-
-      context "on my own post" do
-        it 'succeeds' do
-          @target = alice.post :status_message, :text => "AWESOME", :to => @alices_aspect.id
-          post :create, participation_hash
-          response.code.should == '201'
-        end
-      end
-
-      context "on a post from a contact" do
-        before do
-          @target = bob.post(:status_message, :text => "AWESOME", :to => @bobs_aspect.id)
-        end
-
-        it 'participations' do
-          post :create, participation_hash
-          response.code.should == '201'
-        end
-
-        it 'disparticipations' do
-          post :create, disparticipation_hash
-          response.code.should == '201'
-        end
-
-        it "doesn't post multiple times" do
-          alice.participate!(@target)
-          post :create, disparticipation_hash
-          response.code.should == '422'
-        end
-      end
-
-      context "on a post from a stranger" do
-        before do
-          @target = eve.post :status_message, :text => "AWESOME", :to => eve.aspects.first.id
-        end
-
-        it "doesn't post" do
-          alice.should_not_receive(:participate!)
-          post :create, participation_hash
-          response.code.should == '422'
-        end
-      end
-    end
-
-    describe '#index' do
-      before do
-        @message = alice.post(:status_message, :text => "hey", :to => @alices_aspect.id)
-      end
-
-      it 'generates a jasmine fixture', :fixture => true do
-        get :index, id_field => @message.id, :format => :json
-
-        save_fixture(response.body, "ajax_participations_on_posts")
-      end
-
-      it 'returns a 404 for a post not visible to the user' do
-        sign_in eve
-        get :index, id_field => @message.id, :format => :json
-      end
-
-      it 'returns an array of participations for a post' do
-        bob.participate!(@message)
-        get :index, id_field => @message.id, :format => :json
-        assigns[:participations].map(&:id).should == @message.participation_ids
-      end
-
-      it 'returns an empty array for a post with no participations' do
-        get :index, id_field => @message.id, :format => :json
-        assigns[:participations].should == []
-      end
-    end
-
-    describe '#destroy' do
-      before do
-        @message = bob.post(:status_message, :text => "hey", :to => @alices_aspect.id)
-        @participation = alice.participate!(@message)
-      end
-
-      it 'lets a user destroy their participation' do
-        expect {
-          delete :destroy, :format => :json, id_field => @participation.target_id, :id => @participation.id
-        }.should change(Participation, :count).by(-1)
-        response.status.should == 202
-      end
-
-      it 'does not let a user destroy other participations' do
-        participation2 = eve.participate!(@message)
-
-        expect {
-          delete :destroy, :format => :json, id_field => participation2.target_id, :id => participation2.id
-        }.should_not change(Participation, :count)
-
-        response.status.should == 403
-      end
-
-      it 'returns the parent post presenter' do
-        delete :destroy, :format => :json, id_field => @participation.target_id, :id => @participation.id
-        response.body.should include 'post'
-      end
-    end
-  end
-end
diff --git a/spec/controllers/posts_controller_spec.rb b/spec/controllers/posts_controller_spec.rb
index 5fb918bf3a21f00ff6cc35d2bf826da588de7384..ad74d2d9a60e71d689b7c643ab087231e944df85 100644
--- a/spec/controllers/posts_controller_spec.rb
+++ b/spec/controllers/posts_controller_spec.rb
@@ -55,9 +55,8 @@ describe PostsController do
         response.should be_success
       end
 
-      it 'redirects if the post is missing' do
-        get :show, :id => 1234567
-        response.should be_redirect
+      it '404 if the post is missing' do
+        expect { get :show, :id => 1234567 }.to raise_error(ActiveRecord::RecordNotFound)
       end
     end
 
@@ -86,8 +85,7 @@ describe PostsController do
 
       it 'does not show a private post' do
         status = alice.post(:status_message, :text => "hello", :public => false, :to => 'all')
-        get :show, :id => status.id
-        response.status = 302
+        expect { get :show, :id => status.id }.to raise_error(ActiveRecord::RecordNotFound)
       end
 
       # We want to be using guids from now on for this post route, but do not want to break
@@ -128,8 +126,7 @@ describe PostsController do
     end
 
     it 'returns a 404 response when the post is not found' do
-      get :oembed, :url => "/posts/#{@message.id}"
-      response.should_not be_success
+      expect { get :oembed, :url => "/posts/#{@message.id}" }.to raise_error(ActiveRecord::RecordNotFound)
     end
   end
 
@@ -155,15 +152,13 @@ describe PostsController do
 
     it 'will not let you destroy posts visible to you' do
       message = bob.post(:status_message, :text => "hey", :to => bob.aspects.first.id)
-      delete :destroy, :format => :js, :id => message.id
-      response.should_not be_success
+      expect { delete :destroy, :format => :js, :id => message.id }.to raise_error(ActiveRecord::RecordNotFound)
       StatusMessage.exists?(message.id).should be_true
     end
 
     it 'will not let you destory posts you do not own' do
       message = eve.post(:status_message, :text => "hey", :to => eve.aspects.first.id)
-      delete :destroy, :format => :js, :id => message.id
-      response.should_not be_success
+      expect { delete :destroy, :format => :js, :id => message.id }.to raise_error(ActiveRecord::RecordNotFound)
       StatusMessage.exists?(message.id).should be_true
     end
   end
@@ -171,8 +166,8 @@ describe PostsController do
   describe "#next" do
     before do
       sign_in alice
-      #lets make a class and unit test it, because this is still not working
-      @controller.stub_chain(:visible_posts_from_author, :newer).and_return(next_post)
+      Post.stub(:find_by_guid_or_id_with_user).and_return(mock_model(Post, :author => 4))
+      Post.stub_chain(:visible_from_author, :newer).and_return(next_post)
     end
 
     let(:next_post){ mock_model(StatusMessage, :id => 34)}
@@ -181,7 +176,7 @@ describe PostsController do
       let(:mock_presenter) { mock(:as_json => {:title => "the unbearable lightness of being"}) }
 
       it "should return a show presenter the next post" do
-        ExtremePostPresenter.should_receive(:new).with(next_post, alice).and_return(mock_presenter)
+        PostPresenter.should_receive(:new).with(next_post, alice).and_return(mock_presenter)
         get :next, :id => 14, :format => :json
         response.body.should == {:title => "the unbearable lightness of being"}.to_json
       end
@@ -198,8 +193,8 @@ describe PostsController do
   describe "previous" do
     before do
       sign_in alice
-      #lets make a class and unit test it, because this is still not working
-      @controller.stub_chain(:visible_posts_from_author, :older).and_return(previous_post)
+      Post.stub(:find_by_guid_or_id_with_user).and_return(mock_model(Post, :author => 4))
+      Post.stub_chain(:visible_from_author, :older).and_return(previous_post)
     end
 
     let(:previous_post){ mock_model(StatusMessage, :id => 11)}
@@ -208,7 +203,7 @@ describe PostsController do
       let(:mock_presenter) { mock(:as_json => {:title => "existential crises"})}
 
       it "should return a show presenter the next post" do
-        ExtremePostPresenter.should_receive(:new).with(previous_post, alice).and_return(mock_presenter)
+        PostPresenter.should_receive(:new).with(previous_post, alice).and_return(mock_presenter)
         get :previous, :id => 14, :format => :json
         response.body.should == {:title => "existential crises"}.to_json
       end
diff --git a/spec/javascripts/app/models/post/interacations_spec.js b/spec/javascripts/app/models/post/interacations_spec.js
new file mode 100644
index 0000000000000000000000000000000000000000..f6a5be3ad6d92f150e1e26bb065e7b1796a18786
--- /dev/null
+++ b/spec/javascripts/app/models/post/interacations_spec.js
@@ -0,0 +1,45 @@
+describe("app.models.Post.Interactions", function(){
+  beforeEach(function(){
+    this.interactions = factory.post()
+    this.interactions = this.interactions.interactions
+    this.author = factory.author({guid: "loggedInAsARockstar"})
+    loginAs({guid: "loggedInAsARockstar"})
+
+    this.userLike = new app.models.Like({author : this.author})
+  })
+  
+  describe("toggleLike", function(){
+    it("calls unliked when the user_like exists", function(){
+      this.interactions.likes.add(this.userLike)
+      spyOn(this.interactions, "unlike").andReturn(true);
+      this.interactions.toggleLike();
+      expect(this.interactions.unlike).toHaveBeenCalled();
+    })
+
+    it("calls liked when the user_like does not exist", function(){
+      this.interactions.likes.reset([]);
+      spyOn(this.interactions, "like").andReturn(true);
+      this.interactions.toggleLike();
+      expect(this.interactions.like).toHaveBeenCalled();
+    })
+  })
+
+  describe("like", function(){
+    it("calls create on the likes collection", function(){
+      spyOn(this.interactions.likes, "create");
+
+      this.interactions.like();
+      expect(this.interactions.likes.create).toHaveBeenCalled();
+    })
+  })
+
+  describe("unlike", function(){
+    it("calls destroy on the likes collection", function(){
+      this.interactions.likes.add(this.userLike)
+      spyOn(this.userLike, "destroy");
+
+      this.interactions.unlike();
+      expect(this.userLike.destroy).toHaveBeenCalled();
+    })
+  })
+})
\ No newline at end of file
diff --git a/spec/javascripts/app/models/post_spec.js b/spec/javascripts/app/models/post_spec.js
index 90dbca87cca0b3368f37bb04ffe5e14b2b16480f..c6f6ef14b81aef32cd350d83b6c7f76d7084e02b 100644
--- a/spec/javascripts/app/models/post_spec.js
+++ b/spec/javascripts/app/models/post_spec.js
@@ -36,43 +36,4 @@ describe("app.models.Post", function() {
       expect(this.post.createdAt()).toEqual(+date);
     });
   });
-
-  describe("toggleLike", function(){
-    it("calls unliked when the user_like exists", function(){
-      this.post.set({user_like : "123"});
-      spyOn(this.post, "unlike").andReturn(true);
-
-      this.post.toggleLike();
-      expect(this.post.unlike).toHaveBeenCalled();
-    })
-
-    it("calls liked when the user_like does not exist", function(){
-      this.post.set({user_like : null});
-      spyOn(this.post, "like").andReturn(true);
-
-      this.post.toggleLike();
-      expect(this.post.like).toHaveBeenCalled();
-    })
-  })
-
-  describe("like", function(){
-    it("calls create on the likes collection", function(){
-      spyOn(this.post.likes, "create");
-
-      this.post.like();
-      expect(this.post.likes.create).toHaveBeenCalled();
-    })
-  })
-
-  describe("unlike", function(){
-    it("calls destroy on the likes collection", function(){
-      var like = new app.models.Like();
-      this.post.set({user_like : like.toJSON()})
-
-      spyOn(app.models.Like.prototype, "destroy");
-
-      this.post.unlike();
-      expect(app.models.Like.prototype.destroy).toHaveBeenCalled();
-    })
-  })
 });
diff --git a/spec/javascripts/app/views/comment_stream_view_spec.js b/spec/javascripts/app/views/comment_stream_view_spec.js
index bcb72a470ca76c75e18bbf4f83b7b25815b5f00c..f808a43df3fb2c4bbd7edca8335688b25fb32e28 100644
--- a/spec/javascripts/app/views/comment_stream_view_spec.js
+++ b/spec/javascripts/app/views/comment_stream_view_spec.js
@@ -29,28 +29,6 @@ describe("app.views.CommentStream", function(){
     })
   })
 
-  describe("createComment", function(){
-    beforeEach(function(){
-      spyOn(this.view.model.comments, "create")
-    })
-
-    it("clears the new comment textarea", function(){
-      var comment = {
-        "id": 1234,
-        "text": "hey",
-        "author": "not_null"
-      };
-      spyOn($, "ajax").andCallFake(function(params) {
-        params.success(comment);
-      });
-
-      $(this.view.el).html($("<textarea/>", {"class" : 'comment_box'}).val(comment.text))
-      this.view.createComment()
-      expect(this.view.$(".comment_box").val()).toBe("")
-      expect(this.view.model.comments.create).toHaveBeenCalled()
-    })
-  })
-
   describe("appendComment", function(){
     it("appends this.model as 'parent' to the comment", function(){
       var comment = new app.models.Comment(factory.comment())
diff --git a/spec/javascripts/app/views/feedback_view_spec.js b/spec/javascripts/app/views/feedback_view_spec.js
index 223a41e3765a8a45fbc8ed7db3c430d771163239..3c6b9ee5c4518ac7eac3eb2efbb37723faeb87e4 100644
--- a/spec/javascripts/app/views/feedback_view_spec.js
+++ b/spec/javascripts/app/views/feedback_view_spec.js
@@ -19,7 +19,7 @@ describe("app.views.Feedback", function(){
   describe("triggers", function() {
     it('re-renders when the model triggers feedback', function(){
       spyOn(this.view, "postRenderTemplate")
-      this.view.model.trigger("interacted")
+      this.view.model.interactions.trigger("change")
       expect(this.view.postRenderTemplate).toHaveBeenCalled()
     })
   })
@@ -32,15 +32,17 @@ describe("app.views.Feedback", function(){
 
     context("likes", function(){
       it("calls 'toggleLike' on the target post", function(){
+        loginAs(this.post.interactions.likes.models[0].get("author"))
         this.view.render();
-        spyOn(this.post, "toggleLike");
-
+        spyOn(this.post.interactions, "toggleLike");
         this.link().click();
-        expect(this.post.toggleLike).toHaveBeenCalled();
+        expect(this.post.interactions.toggleLike).toHaveBeenCalled();
       })
 
       context("when the user likes the post", function(){
         it("the like action should be 'Unlike'", function(){
+          spyOn(this.post.interactions, "userLike").andReturn(factory.like());
+          this.view.render()
           expect(this.link().text()).toContain(Diaspora.I18n.t('stream.unlike'))
         })
       })
@@ -137,7 +139,7 @@ describe("app.views.Feedback", function(){
 
     it("reshares the model", function(){
       spyOn(window, "confirm").andReturn(true);
-      spyOn(this.view.model.reshare(), "save")
+      spyOn(this.view.model.reshare(), "save").andReturn(new $.Deferred)
       this.view.$(".reshare_action").first().click();
       expect(this.view.model.reshare().save).toHaveBeenCalled();
     })
diff --git a/spec/javascripts/app/views/likes_info_view_spec.js b/spec/javascripts/app/views/likes_info_view_spec.js
index e018112453adc1a56ecd6855b851b59295602848..a7ffb548430c4c2b0ad0ae426a72834cc9673c43 100644
--- a/spec/javascripts/app/views/likes_info_view_spec.js
+++ b/spec/javascripts/app/views/likes_info_view_spec.js
@@ -16,34 +16,32 @@ describe("app.views.LikesInfo", function(){
 
   describe(".render", function(){
     it("displays a the like count if it is above zero", function() {
+      spyOn(this.view.model.interactions, "likesCount").andReturn(3);
       this.view.render();
-      this.view.model.set({"likes_count" : 1})
-
       expect($(this.view.el).find(".expand_likes").length).toBe(1)
     })
 
     it("does not display the like count if it is zero", function() {
-      this.post.save({likes_count : 0});
+      spyOn(this.view.model.interactions, "likesCount").andReturn(0);
       this.view.render();
-
       expect($(this.view.el).html().trim()).toBe("");
     })
 
     it("fires on a model change", function(){
       spyOn(this.view, "postRenderTemplate")
-      this.view.model.trigger('expandedLikes')
+      this.view.model.interactions.trigger('change')
       expect(this.view.postRenderTemplate).toHaveBeenCalled()
     })
   })
 
   describe("showAvatars", function(){
     beforeEach(function(){
-      spyOn(this.post.likes, "fetch").andCallThrough()
+      spyOn(this.post.interactions, "fetch").andCallThrough()
     })
 
     it("calls fetch on the model's like collection", function(){
       this.view.showAvatars();
-      expect(this.post.likes.fetch).toHaveBeenCalled();
+      expect(this.post.interactions.fetch).toHaveBeenCalled();
     })
 
     it("sets the fetched response to the model's likes", function(){
diff --git a/spec/javascripts/helpers/factory.js b/spec/javascripts/helpers/factory.js
index fc836574060727d591af73ea6a45f9ade985431a..48adcd0cfbc8de6c3d9bafc0a081a95c9ee658af 100644
--- a/spec/javascripts/helpers/factory.js
+++ b/spec/javascripts/helpers/factory.js
@@ -57,20 +57,24 @@ factory = {
       "provider_display_name" : null,
       "created_at" : "2012-01-03T19:53:13Z",
       "interacted_at" : '2012-01-03T19:53:13Z',
-      "last_three_comments" : null,
       "public" : false,
       "guid" : this.guid(),
       "image_url" : null,
       "o_embed_cache" : null,
       "photos" : [],
       "text" : "jasmine is bomb",
-      "reshares_count" : 0,
       "id" : this.id.next(),
       "object_url" : null,
       "root" : null,
       "post_type" : "StatusMessage",
-      "likes_count" : 0,
-      "comments_count" : 0
+      "interactions" : {
+        "reshares_count" : 0,
+        "likes_count" : 0,
+        "comments_count" : 0,
+        "comments" : [],
+        "likes" : [],
+        "reshares" : []
+      }
     }
   },
 
diff --git a/spec/models/user/social_actions_spec.rb b/spec/models/user/social_actions_spec.rb
index a9a88078b58d7f4d32515c9f4c40693fbd2f257e..33c99e6756e6642df91f31eaa734e7da80b417b0 100644
--- a/spec/models/user/social_actions_spec.rb
+++ b/spec/models/user/social_actions_spec.rb
@@ -77,9 +77,10 @@ describe User::SocialActions do
 
     it "does not allow multiple likes" do
       alice.like!(@status)
-      lambda {
-        alice.like!(@status)
-      }.should_not change(@status, :likes)
+      likes = @status.likes
+      expect { alice.like!(@status) }.to raise_error
+
+      @status.reload.likes.should == likes
     end
   end
 end
\ No newline at end of file