diff --git a/denis/peer_review.py b/denis/peer_review.py
index b3a4212a..6d23b182 100755
--- a/denis/peer_review.py
+++ b/denis/peer_review.py
@@ -7,12 +7,17 @@
 
 ids = []
 
-ids += [sub.submission_id for sub in utilities.user_to_sub(assignment, 'review1').values() if sub]
-ids += [sub.submission_id for sub in utilities.user_to_sub(assignment, 'review2').values() if sub]
+usernames_to_subs_review1 = utilities.user_to_sub(assignment, 'review1')
+usernames_to_subs_review2 = utilities.user_to_sub(assignment, 'review2')
+
+ids += [sub.submission_id for sub in usernames_to_subs_review1.values() if sub]
+ids += [sub.submission_id for sub in usernames_to_subs_review2.values() if sub]
 
 utilities.release_subs(ids)
 
 print(f'peer review subs for {assignment} released')
 
-utilities.update_tags(assignment, 'review1')
-utilities.update_tags(assignment, 'review2')
+tags1 = utilities.update_tags(assignment, 'review1')
+tags2 = utilities.update_tags(assignment, 'review2')
+
+utilities.run_automated_checks(tags1 + tags2, usernames_to_subs_review1 | usernames_to_subs_review2, peer=True)
diff --git a/denis/utilities.py b/denis/utilities.py
index e8206513..c8b41103 100644
--- a/denis/utilities.py
+++ b/denis/utilities.py
@@ -166,7 +166,7 @@ def check_subject_tag(repo, tag):
     return msg
 
 
-def run_automated_checks(tags, username_to_subs):
+def run_automated_checks(tags, username_to_subs, peer=False):
     with tempfile.TemporaryDirectory() as repo_path:
         repo = git.Repo.clone_from(PULL_URL, repo_path)
 
@@ -178,7 +178,8 @@ def run_automated_checks(tags, username_to_subs):
             msg = 'Automated tests by denis'
             msg += '\n\n'
             msg += check_corrupt_or_missing(repo, tag, username_to_subs)
-            if msg[-3] != '!':
+
+            if msg[-3] != '!' and not peer:
                 msg += '\n\n'
                 msg += check_signed_off_by(repo, tag)
                 msg += check_subject_tag(repo, tag)
diff --git a/mailman/patchset.py b/mailman/patchset.py
index 01d41d36..d44cb267 100644
--- a/mailman/patchset.py
+++ b/mailman/patchset.py
@@ -56,6 +56,25 @@ def am_cover_letter(keep_empty=True):
     for i, patch in enumerate(patches):
         patch_abspath = str(maildir / patch.msg_id)
 
+        with open(patch_abspath, 'r') as patch_file:
+            patch_content = patch_file.read()
+
+        start = patch_content.find('From: <')+len('From: <')
+        end = patch_content.find('@', start)
+        if start == -1 or end == -1:
+            return f'patch {i+1}: no author found (should be impossible)!'
+        found_author = patch_content[start:end]
+
+        changelines = list(filter(lambda line: line.startswith('--- ') or line.startswith('+++ '), patch_content.split('\n')))
+        for change in changelines:
+            file = change.split(' ')[1].strip()
+            if file == '/dev/null':
+                continue
+            first_dir = file.split('/')[1]
+            if first_dir != found_author:
+                file_fixed = file[2:]
+                return f'illegal patch {i+1}: permission denied for path {file_fixed}!'
+
         # Try and apply and fail if there are whitespace errors
         def do_git_am(extra_args=[]):
             repo.git.execute([*git_am_args, *extra_args, patch_abspath]),
diff --git a/orbit/radius.py b/orbit/radius.py
index dc3ed7d8..244e86aa 100644
--- a/orbit/radius.py
+++ b/orbit/radius.py
@@ -426,7 +426,7 @@ class OopsStatus:
 
 class AsmtTable:
     def __init__(self, assignment, oopsieness, peer1, peer2, init,
-                 review1, review1_grade, review2, review2_grade, final, final_grade):
+                 review1, review1_grade, review2, review2_grade, final, final_grade, human_feedback):
         self.assignment = assignment
         self.name = assignment.name
         self.oopsieness = oopsieness
@@ -439,6 +439,7 @@ def __init__(self, assignment, oopsieness, peer1, peer2, init,
         self.review2_grade = review2_grade
         self.final = final
         self.final_grade = final_grade
+        self.human_feedback = human_feedback
 
     def oops_button_hover(self):
         match self.oopsieness:
@@ -529,6 +530,10 @@ def body(self):
                 <th>Automated Feedback</th>
                 <td colspan="3">{self.get_automated_feedback('final')}</td>
               </tr>
+              <tr>
+                <th>Human Feedback</th>
+                <td colspan="3">{self.human_feedback}</td>
+              </tr>
             """
         if (not self.init or
             (int(datetime.now().timestamp())
@@ -559,6 +564,10 @@ def body(self):
             <th>Automated Feedback</th>
             <td colspan="3">{self.get_automated_feedback('final')}</td>
           </tr>
+          <tr>
+            <th>Human Feedback</th>
+            <td colspan="3">{self.human_feedback}</td>
+          </tr>
         """
 
     def __str__(self):
@@ -649,8 +658,14 @@ def handle_dashboard(rocket):
             except git.GitCommandError:
                 grades[component] = None
 
+        tag = f'{assignment.name}_final_{rocket.session.username}'
+        try:
+            human_feedback = repo.git.execute(['git', 'notes', '--ref=feedback', 'show', tag])
+        except git.GitCommandError:
+            human_feedback = '-'
+
         ret += str(AsmtTable(assignment, oopsieness, peer1, peer2, init,
-                             rev1, grades['review1'], rev2, grades['review2'], final, grades['final']))
+                             rev1, grades['review1'], rev2, grades['review2'], final, grades['final'], human_feedback))
     return rocket.respond(ret + '</form>', 'Dashboard')
 
 
