diff --git a/src/handlers/rendered_link.rs b/src/handlers/rendered_link.rs
index 81547701..037f0607 100644
--- a/src/handlers/rendered_link.rs
+++ b/src/handlers/rendered_link.rs
@@ -1,3 +1,5 @@
+use anyhow::bail;
+
 use crate::{
     github::{Event, IssuesAction, IssuesEvent},
     handlers::Context,
@@ -10,6 +12,10 @@ pub async fn handle(ctx: &Context, event: &Event) -> anyhow::Result<()> {
         return Ok(());
     };
 
+    if !e.issue.is_pr() {
+        return Ok(());
+    }
+
     let repo = e.issue.repository();
     let prefix = match (&*repo.organization, &*repo.repository) {
         ("rust-lang", "rfcs") => "text/",
@@ -25,32 +31,69 @@ pub async fn handle(ctx: &Context, event: &Event) -> anyhow::Result<()> {
 }
 
 async fn add_rendered_link(ctx: &Context, e: &IssuesEvent, prefix: &str) -> anyhow::Result<()> {
-    if e.action == IssuesAction::Opened {
+    if e.action == IssuesAction::Opened
+        || e.action == IssuesAction::Closed
+        || e.action == IssuesAction::Reopened
+    {
         let files = e.issue.files(&ctx.github).await?;
 
         if let Some(file) = files.iter().find(|f| f.filename.starts_with(prefix)) {
-            if !e.issue.body.contains("[Rendered]") {
-                // This URL should be stable while the PR is open, even if the
-                // user pushes new commits.
-                //
-                // It will go away if the user deletes their branch, or if
-                // they reset it (such as if they created a PR from master).
-                // That should usually only happen after the PR is closed.
-                // During the closing process, the closer should update the
-                // Rendered link to the new location (which we should
-                // automate!).
-                let head = e.issue.head.as_ref().unwrap();
-                let url = format!(
-                    "https://github.com/{}/blob/{}/{}",
-                    head.repo.full_name, head.git_ref, file.filename
-                );
-                e.issue
-                    .edit_body(
-                        &ctx.github,
-                        &format!("{}\n\n[Rendered]({})", e.issue.body, url),
-                    )
-                    .await?;
-            }
+            let head = e.issue.head.as_ref().unwrap();
+            let base = e.issue.base.as_ref().unwrap();
+
+            // This URL should be stable while the PR is open, even if the
+            // user pushes new commits.
+            //
+            // It will go away if the user deletes their branch, or if
+            // they reset it (such as if they created a PR from master).
+            // That should usually only happen after the PR is closed
+            // a which point we switch to a SHA-based url.
+            //
+            // If the PR is merged we use a URL that points to the actual
+            // repository, as to be resilient to branch deletion, as well
+            // be in sync with current "master" branch.
+            //
+            // For a PR "octocat:master" <- "Bob:patch-1", we generate,
+            //  - if merged: `https://github.com/octocat/REPO/blob/master/FILEPATH`
+            //  - if open: `https://github.com/Bob/REPO/blob/patch-1/FILEPATH`
+            //  - if closed: `https://github.com/octocat/REPO/blob/SHA/FILEPATH`
+            let rendered_link = format!(
+                "[Rendered](https://github.com/{}/blob/{}/{})",
+                if e.issue.merged || e.action == IssuesAction::Closed {
+                    &e.repository.full_name
+                } else {
+                    &head.repo.full_name
+                },
+                if e.issue.merged {
+                    &base.git_ref
+                } else if e.action == IssuesAction::Closed {
+                    &head.sha
+                } else {
+                    &head.git_ref
+                },
+                file.filename
+            );
+
+            let new_body = if !e.issue.body.contains("[Rendered]") {
+                // add rendered link to the end of the body
+                format!("{}\n\n{rendered_link}", e.issue.body)
+            } else if let Some(start_pos) = e.issue.body.find("[Rendered](") {
+                let Some(end_offset) = &e.issue.body[start_pos..].find(')') else {
+                    bail!("no `)` after `[Rendered]` found")
+                };
+
+                // replace the current rendered link with the new one
+                e.issue.body.replace(
+                    &e.issue.body[start_pos..=(start_pos + end_offset)],
+                    &rendered_link,
+                )
+            } else {
+                bail!(
+                    "found `[Rendered]` but not it's associated link, can't replace it, bailing out"
+                )
+            };
+
+            e.issue.edit_body(&ctx.github, &new_body).await?;
         }
     }