Repository: DefinitelyTyped/dt-mergebot
Pull request #407 (2021-05-19 12:44:30)

Link to the main comment if someone tries to request an early merge
Re: [This discussion in Discord](https://discord.com/channels/508357248330760243/757992230077333655/844252513968717824)

This disambiguates what you are waiting on when you ask for a merge before it's time.

Also updates the GraphQL types (so I could add the new attribute)


Patch:
diff --git a/package.json b/package.json
index b62d2e8..43edb5f 100644
--- a/package.json
+++ b/package.json
@@ -22,7 +22,7 @@
     "dayjs": "^1.10.3",
     "fast-json-patch": "^3.0.0-1",
     "fs-extra": "^9.0.1",
-    "graphql": "^14.5.8",
+    "graphql": "15.5.0",
     "node-fetch": "^2.6.1",
     "prettyjson": "^1.2.1",
     "yargs": "^17.0.1"
diff --git a/src/comments.ts b/src/comments.ts
index 8b3782d..ca86584 100644
--- a/src/comments.ts
+++ b/src/comments.ts
@@ -78,12 +78,12 @@ and I'll merge this PR almost instantly. Thanks for helping out! :heart:
 ${otherOwners.length === 0 ? "" : `
 (${otherOwners.map(o => "@" + o).join(", ")}: you can do this too.)`}`}));
 
-export const WaitUntilMergeIsOK = (user: string, abbrOid: string, uri: string) => ({
+export const WaitUntilMergeIsOK = (user: string, abbrOid: string, uri: string, mainCommentID: number | undefined) => ({
     // at most one reminder per update
     tag: `wait-for-merge-offer-${abbrOid}`,
     status: `:passport_control: Hi @${user},
 
-I can't [accept a merge request](${uri}) until the PR has a green CI and was appropriately reviewed. I will let you know once that happens.
+I can't [accept a pull request](${uri}) until all of the checks in the "Status" section of [this comment](#issuecomment-${mainCommentID || "???"}) are green. I will let you know once that happens.
 
 Thanks, and happy typing!`
 });
diff --git a/src/compute-pr-actions.ts b/src/compute-pr-actions.ts
index 5a1d0fb..eab0678 100644
--- a/src/compute-pr-actions.ts
+++ b/src/compute-pr-actions.ts
@@ -137,7 +137,7 @@ function extendPrInfo(info: PrInfo): ExtendedPrInfo {
         requireMaintainer, blessable, blessingKind, failedCI, blockedCI, ciResult, staleness,
         packages, hasMultiplePackages, hasDefinitions, hasTests, isUntested, newPackages, hasNewPackages, hasEditedPackages,
         approvedReviews, changereqReviews, staleReviews, approvedBy, hasChangereqs,
-        needsAuthorAction, reviewColumn, isAuthor,
+        needsAuthorAction, reviewColumn, isAuthor
     };
 
     // Staleness timeline configurations (except for texts that are all in `comments.ts`)
@@ -327,7 +327,7 @@ export function process(prInfo: BotResult,
     }
 
     if (!actions.shouldMerge && info.mergeRequestUser) {
-        post(Comments.WaitUntilMergeIsOK(info.mergeRequestUser, headCommitAbbrOid, urls.workflow));
+        post(Comments.WaitUntilMergeIsOK(info.mergeRequestUser, headCommitAbbrOid, urls.workflow, info.mainBotCommentID));
     }
 
     // Timeline-related actions
diff --git a/src/pr-info.ts b/src/pr-info.ts
index 7f8a995..b9d9043 100644
--- a/src/pr-info.ts
+++ b/src/pr-info.ts
@@ -136,6 +136,9 @@ export interface PrInfo {
     readonly pkgInfo: readonly PackageInfo[];
 
     readonly reviews: readonly ReviewInfo[];
+
+    // The ID of the main comment so that it can be linked to by other comments
+    readonly mainBotCommentID?: number;
 }
 
 export type BotResult =
@@ -190,7 +193,7 @@ export async function deriveStateForPR(
                                          pkgInfo.length === 1 ? [author, ...pkgInfo[0]!.owners] : [author],
                                          max([createdDate, reopenedDate, lastPushDate]));
     const lastActivityDate = max([createdDate, lastPushDate, lastCommentDate, blessing?.date, reopenedDate, latestReview]);
-
+    const mainBotCommentID = getMainCommentID(comments);
     return {
         type: "info",
         now,
@@ -206,6 +209,7 @@ export async function deriveStateForPR(
         popularityLevel,
         pkgInfo,
         reviews,
+        mainBotCommentID,
         ...getCIResult(headCommit.checkSuites),
     };
 
@@ -226,6 +230,12 @@ function getReopenedDate(timelineItems: PR_repository_pullRequest_timelineItems)
         || undefined;
 }
 
+function getMainCommentID(comments: PR_repository_pullRequest_comments_nodes[]) {
+    const comment = comments.find(c => !authorNotBot(c) && c.body.includes("<!--typescript_bot_welcome-->"));
+    if (!comment) return undefined;
+    return comment.databaseId!;
+}
+
 function getLastCommentishActivityDate(prInfo: PR_repository_pullRequest) {
     const getCommentDate = (comment: { createdAt: string }) => new Date(comment.createdAt);
     const latestIssueCommentDate = noNullish(prInfo.comments.nodes)
diff --git a/src/pr-trigger.ts b/src/pr-trigger.ts
index e4910b3..7629c5c 100644
--- a/src/pr-trigger.ts
+++ b/src/pr-trigger.ts
@@ -126,7 +126,7 @@ const prFromEvent = async (event: EmitterWebhookEvent<typeof eventNames[number]>
         case "project_card": {
             const url = event.payload.project_card.content_url;
             return url ? { number: +url.replace(/^.*\//, "") }
-                : new IgnoredBecause(`Couldn't find PR number since contentent_url is missing: ${
+                : new IgnoredBecause(`Couldn't find PR number since content_url is missing: ${
                                         JSON.stringify(event.payload.project_card)}`);
         }
         case "pull_request": return event.payload.pull_request;
diff --git a/src/queries/pr-query.ts b/src/queries/pr-query.ts
index cf1b0e2..e60ede2 100644
--- a/src/queries/pr-query.ts
+++ b/src/queries/pr-query.ts
@@ -124,6 +124,7 @@ query PR($prNumber: Int!) {
             author {
               login
             }
+            databaseId
             body
             createdAt
             reactions(first: 100, content: THUMBS_UP) {
diff --git a/src/queries/schema/CardIdToPr.ts b/src/queries/schema/CardIdToPr.ts
index cb9abdf..13c5549 100644
--- a/src/queries/schema/CardIdToPr.ts
+++ b/src/queries/schema/CardIdToPr.ts
@@ -9,8 +9,8 @@ import { PullRequestState } from "./graphql-global-types";
 // GraphQL query operation: CardIdToPr
 // ====================================================
 
-export interface CardIdToPr_node_CodeOfConduct {
-  __typename: "CodeOfConduct" | "Enterprise" | "EnterpriseUserAccount" | "Organization" | "Package" | "PackageVersion" | "PackageFile" | "Release" | "User" | "Project" | "ProjectColumn" | "Issue" | "UserContentEdit" | "Label" | "PullRequest" | "Reaction" | "Repository" | "License" | "BranchProtectionRule" | "Ref" | "PushAllowance" | "App" | "Team" | "UserStatus" | "TeamDiscussion" | "TeamDiscussionComment" | "OrganizationInvitation" | "ReviewDismissalAllowance" | "CommitComment" | "Commit" | "CheckSuite" | "CheckRun" | "Push" | "Deployment" | "DeploymentStatus" | "Status" | "StatusContext" | "StatusCheckRollup" | "Tree" | "DeployKey" | "Language" | "Milestone" | "PinnedIssue" | "RepositoryTopic" | "Topic" | "RepositoryVulnerabilityAlert" | "SecurityAdvisory" | "CWE" | "IssueComment" | "PullRequestCommit" | "PullRequestReview" | "PullRequestReviewComment" | "ReviewRequest" | "Mannequin" | "PullRequestReviewThread" | "AssignedEvent" | "Bot" | "BaseRefDeletedEvent" | "BaseRefForcePushedEvent" | "ClosedEvent" | "CommitCommentThread" | "CrossReferencedEvent" | "DemilestonedEvent" | "DeployedEvent" | "DeploymentEnvironmentChangedEvent" | "HeadRefDeletedEvent" | "HeadRefForcePushedEvent" | "HeadRefRestoredEvent" | "LabeledEvent" | "LockedEvent" | "MergedEvent" | "MilestonedEvent" | "ReferencedEvent" | "RenamedTitleEvent" | "ReopenedEvent" | "ReviewDismissedEvent" | "ReviewRequestRemovedEvent" | "ReviewRequestedEvent" | "SubscribedEvent" | "UnassignedEvent" | "UnlabeledEvent" | "UnlockedEvent" | "UnsubscribedEvent" | "UserBlockedEvent" | "AddedToProjectEvent" | "AutoMergeDisabledEvent" | "AutoMergeEnabledEvent" | "AutoRebaseEnabledEvent" | "AutoSquashEnabledEvent" | "AutomaticBaseChangeFailedEvent" | "AutomaticBaseChangeSucceededEvent" | "BaseRefChangedEvent" | "CommentDeletedEvent" | "ConnectedEvent" | "ConvertToDraftEvent" | "ConvertedNoteToIssueEvent" | "DisconnectedEvent" | "MarkedAsDuplicateEvent" | "MentionedEvent" | "MovedColumnsInProjectEvent" | "PinnedEvent" | "PullRequestCommitCommentThread" | "ReadyForReviewEvent" | "RemovedFromProjectEvent" | "TransferredEvent" | "UnmarkedAsDuplicateEvent" | "UnpinnedEvent" | "Gist" | "GistComment" | "SponsorsListing" | "SponsorsTier" | "Sponsorship" | "PublicKey" | "SavedReply" | "ReleaseAsset" | "MembersCanDeleteReposClearAuditEntry" | "MembersCanDeleteReposDisableAuditEntry" | "MembersCanDeleteReposEnableAuditEntry" | "OauthApplicationCreateAuditEntry" | "OrgAddBillingManagerAuditEntry" | "OrgAddMemberAuditEntry" | "OrgBlockUserAuditEntry" | "OrgConfigDisableCollaboratorsOnlyAuditEntry" | "OrgConfigEnableCollaboratorsOnlyAuditEntry" | "OrgCreateAuditEntry" | "OrgDisableOauthAppRestrictionsAuditEntry" | "OrgDisableSamlAuditEntry" | "OrgDisableTwoFactorRequirementAuditEntry" | "OrgEnableOauthAppRestrictionsAuditEntry" | "OrgEnableSamlAuditEntry" | "OrgEnableTwoFactorRequirementAuditEntry" | "OrgInviteMemberAuditEntry" | "OrgInviteToBusinessAuditEntry" | "OrgOauthAppAccessApprovedAuditEntry" | "OrgOauthAppAccessDeniedAuditEntry" | "OrgOauthAppAccessRequestedAuditEntry" | "OrgRemoveBillingManagerAuditEntry" | "OrgRemoveMemberAuditEntry" | "OrgRemoveOutsideCollaboratorAuditEntry" | "OrgRestoreMemberAuditEntry" | "OrgUnblockUserAuditEntry" | "OrgUpdateDefaultRepositoryPermissionAuditEntry" | "OrgUpdateMemberAuditEntry" | "OrgUpdateMemberRepositoryCreationPermissionAuditEntry" | "OrgUpdateMemberRepositoryInvitationPermissionAuditEntry" | "PrivateRepositoryForkingDisableAuditEntry" | "PrivateRepositoryForkingEnableAuditEntry" | "RepoAccessAuditEntry" | "RepoAddMemberAuditEntry" | "RepoAddTopicAuditEntry" | "RepoArchivedAuditEntry" | "RepoChangeMergeSettingAuditEntry" | "RepoConfigDisableAnonymousGitAccessAuditEntry" | "RepoConfigDisableCollaboratorsOnlyAuditEntry" | "RepoConfigDisableContributorsOnlyAuditEntry" | "RepoConfigDisableSockpuppetDisallowedAuditEntry" | "RepoConfigEnableAnonymousGitAccessAuditEntry" | "RepoConfigEnableCollaboratorsOnlyAuditEntry" | "RepoConfigEnableContributorsOnlyAuditEntry" | "RepoConfigEnableSockpuppetDisallowedAuditEntry" | "RepoConfigLockAnonymousGitAccessAuditEntry" | "RepoConfigUnlockAnonymousGitAccessAuditEntry" | "RepoCreateAuditEntry" | "RepoDestroyAuditEntry" | "RepoRemoveMemberAuditEntry" | "RepoRemoveTopicAuditEntry" | "RepositoryVisibilityChangeDisableAuditEntry" | "RepositoryVisibilityChangeEnableAuditEntry" | "TeamAddMemberAuditEntry" | "TeamAddRepositoryAuditEntry" | "TeamChangeParentTeamAuditEntry" | "TeamRemoveMemberAuditEntry" | "TeamRemoveRepositoryAuditEntry" | "VerifiableDomain" | "IpAllowListEntry" | "OrganizationIdentityProvider" | "ExternalIdentity" | "EnterpriseServerInstallation" | "EnterpriseServerUserAccount" | "EnterpriseServerUserAccountEmail" | "EnterpriseServerUserAccountsUpload" | "EnterpriseRepositoryInfo" | "EnterpriseAdministratorInvitation" | "RepositoryInvitation" | "EnterpriseIdentityProvider" | "MarketplaceCategory" | "MarketplaceListing" | "Blob" | "PackageTag" | "Tag";
+export interface CardIdToPr_node_AddedToProjectEvent {
+  __typename: "AddedToProjectEvent" | "App" | "AssignedEvent" | "AutoMergeDisabledEvent" | "AutoMergeEnabledEvent" | "AutoRebaseEnabledEvent" | "AutoSquashEnabledEvent" | "AutomaticBaseChangeFailedEvent" | "AutomaticBaseChangeSucceededEvent" | "BaseRefChangedEvent" | "BaseRefDeletedEvent" | "BaseRefForcePushedEvent" | "Blob" | "Bot" | "BranchProtectionRule" | "CWE" | "CheckRun" | "CheckSuite" | "ClosedEvent" | "CodeOfConduct" | "CommentDeletedEvent" | "Commit" | "CommitComment" | "CommitCommentThread" | "ConnectedEvent" | "ConvertToDraftEvent" | "ConvertedNoteToIssueEvent" | "CrossReferencedEvent" | "DemilestonedEvent" | "DeployKey" | "DeployedEvent" | "Deployment" | "DeploymentEnvironmentChangedEvent" | "DeploymentStatus" | "DisconnectedEvent" | "Enterprise" | "EnterpriseAdministratorInvitation" | "EnterpriseIdentityProvider" | "EnterpriseRepositoryInfo" | "EnterpriseServerInstallation" | "EnterpriseServerUserAccount" | "EnterpriseServerUserAccountEmail" | "EnterpriseServerUserAccountsUpload" | "EnterpriseUserAccount" | "ExternalIdentity" | "Gist" | "GistComment" | "HeadRefDeletedEvent" | "HeadRefForcePushedEvent" | "HeadRefRestoredEvent" | "IpAllowListEntry" | "Issue" | "IssueComment" | "Label" | "LabeledEvent" | "Language" | "License" | "LockedEvent" | "Mannequin" | "MarkedAsDuplicateEvent" | "MarketplaceCategory" | "MarketplaceListing" | "MembersCanDeleteReposClearAuditEntry" | "MembersCanDeleteReposDisableAuditEntry" | "MembersCanDeleteReposEnableAuditEntry" | "MentionedEvent" | "MergedEvent" | "Milestone" | "MilestonedEvent" | "MovedColumnsInProjectEvent" | "OauthApplicationCreateAuditEntry" | "OrgAddBillingManagerAuditEntry" | "OrgAddMemberAuditEntry" | "OrgBlockUserAuditEntry" | "OrgConfigDisableCollaboratorsOnlyAuditEntry" | "OrgConfigEnableCollaboratorsOnlyAuditEntry" | "OrgCreateAuditEntry" | "OrgDisableOauthAppRestrictionsAuditEntry" | "OrgDisableSamlAuditEntry" | "OrgDisableTwoFactorRequirementAuditEntry" | "OrgEnableOauthAppRestrictionsAuditEntry" | "OrgEnableSamlAuditEntry" | "OrgEnableTwoFactorRequirementAuditEntry" | "OrgInviteMemberAuditEntry" | "OrgInviteToBusinessAuditEntry" | "OrgOauthAppAccessApprovedAuditEntry" | "OrgOauthAppAccessDeniedAuditEntry" | "OrgOauthAppAccessRequestedAuditEntry" | "OrgRemoveBillingManagerAuditEntry" | "OrgRemoveMemberAuditEntry" | "OrgRemoveOutsideCollaboratorAuditEntry" | "OrgRestoreMemberAuditEntry" | "OrgUnblockUserAuditEntry" | "OrgUpdateDefaultRepositoryPermissionAuditEntry" | "OrgUpdateMemberAuditEntry" | "OrgUpdateMemberRepositoryCreationPermissionAuditEntry" | "OrgUpdateMemberRepositoryInvitationPermissionAuditEntry" | "Organization" | "OrganizationIdentityProvider" | "OrganizationInvitation" | "Package" | "PackageFile" | "PackageTag" | "PackageVersion" | "PinnedEvent" | "PinnedIssue" | "PrivateRepositoryForkingDisableAuditEntry" | "PrivateRepositoryForkingEnableAuditEntry" | "Project" | "ProjectColumn" | "PublicKey" | "PullRequest" | "PullRequestCommit" | "PullRequestCommitCommentThread" | "PullRequestReview" | "PullRequestReviewComment" | "PullRequestReviewThread" | "Push" | "PushAllowance" | "Reaction" | "ReadyForReviewEvent" | "Ref" | "ReferencedEvent" | "Release" | "ReleaseAsset" | "RemovedFromProjectEvent" | "RenamedTitleEvent" | "ReopenedEvent" | "RepoAccessAuditEntry" | "RepoAddMemberAuditEntry" | "RepoAddTopicAuditEntry" | "RepoArchivedAuditEntry" | "RepoChangeMergeSettingAuditEntry" | "RepoConfigDisableAnonymousGitAccessAuditEntry" | "RepoConfigDisableCollaboratorsOnlyAuditEntry" | "RepoConfigDisableContributorsOnlyAuditEntry" | "RepoConfigDisableSockpuppetDisallowedAuditEntry" | "RepoConfigEnableAnonymousGitAccessAuditEntry" | "RepoConfigEnableCollaboratorsOnlyAuditEntry" | "RepoConfigEnableContributorsOnlyAuditEntry" | "RepoConfigEnableSockpuppetDisallowedAuditEntry" | "RepoConfigLockAnonymousGitAccessAuditEntry" | "RepoConfigUnlockAnonymousGitAccessAuditEntry" | "RepoCreateAuditEntry" | "RepoDestroyAuditEntry" | "RepoRemoveMemberAuditEntry" | "RepoRemoveTopicAuditEntry" | "Repository" | "RepositoryInvitation" | "RepositoryTopic" | "RepositoryVisibilityChangeDisableAuditEntry" | "RepositoryVisibilityChangeEnableAuditEntry" | "RepositoryVulnerabilityAlert" | "ReviewDismissalAllowance" | "ReviewDismissedEvent" | "ReviewRequest" | "ReviewRequestRemovedEvent" | "ReviewRequestedEvent" | "SavedReply" | "SecurityAdvisory" | "SponsorsListing" | "SponsorsTier" | "Sponsorship" | "Status" | "StatusCheckRollup" | "StatusContext" | "SubscribedEvent" | "Tag" | "Team" | "TeamAddMemberAuditEntry" | "TeamAddRepositoryAuditEntry" | "TeamChangeParentTeamAuditEntry" | "TeamDiscussion" | "TeamDiscussionComment" | "TeamRemoveMemberAuditEntry" | "TeamRemoveRepositoryAuditEntry" | "Topic" | "TransferredEvent" | "Tree" | "UnassignedEvent" | "UnlabeledEvent" | "UnlockedEvent" | "UnmarkedAsDuplicateEvent" | "UnpinnedEvent" | "UnsubscribedEvent" | "User" | "UserBlockedEvent" | "UserContentEdit" | "UserStatus" | "VerifiableDomain";
 }
 
 export interface CardIdToPr_node_ProjectCard_content_Issue {
@@ -39,7 +39,7 @@ export interface CardIdToPr_node_ProjectCard {
   content: CardIdToPr_node_ProjectCard_content | null;
 }
 
-export type CardIdToPr_node = CardIdToPr_node_CodeOfConduct | CardIdToPr_node_ProjectCard;
+export type CardIdToPr_node = CardIdToPr_node_AddedToProjectEvent | CardIdToPr_node_ProjectCard;
 
 export interface CardIdToPr {
   /**
diff --git a/src/queries/schema/GetFileContent.ts b/src/queries/schema/GetFileContent.ts
index 6c313ad..810a76e 100644
--- a/src/queries/schema/GetFileContent.ts
+++ b/src/queries/schema/GetFileContent.ts
@@ -8,7 +8,7 @@
 // ====================================================
 
 export interface GetFileContent_repository_object_Commit {
-  __typename: "Commit" | "Tree" | "Tag";
+  __typename: "Commit" | "Tag" | "Tree";
 }
 
 export interface GetFileContent_repository_object_Blob {
diff --git a/src/queries/schema/PR.ts b/src/queries/schema/PR.ts
index 4cef6ed..57dda14 100644
--- a/src/queries/schema/PR.ts
+++ b/src/queries/schema/PR.ts
@@ -10,7 +10,7 @@ import { CommentAuthorAssociation, MergeableState, PullRequestState, PullRequest
 // ====================================================
 
 export interface PR_repository_pullRequest_author {
-  __typename: "EnterpriseUserAccount" | "Organization" | "User" | "Mannequin" | "Bot";
+  __typename: "Bot" | "EnterpriseUserAccount" | "Mannequin" | "Organization" | "User";
   /**
    * The username of the actor.
    */
@@ -62,7 +62,7 @@ export interface PR_repository_pullRequest_timelineItems_nodes_ReadyForReviewEve
 }
 
 export interface PR_repository_pullRequest_timelineItems_nodes_MovedColumnsInProjectEvent_actor {
-  __typename: "EnterpriseUserAccount" | "Organization" | "User" | "Mannequin" | "Bot";
+  __typename: "Bot" | "EnterpriseUserAccount" | "Mannequin" | "Organization" | "User";
   /**
    * The username of the actor.
    */
@@ -96,7 +96,7 @@ export interface PR_repository_pullRequest_timelineItems {
 }
 
 export interface PR_repository_pullRequest_reviews_nodes_author {
-  __typename: "EnterpriseUserAccount" | "Organization" | "User" | "Mannequin" | "Bot";
+  __typename: "Bot" | "EnterpriseUserAccount" | "Mannequin" | "Organization" | "User";
   /**
    * The username of the actor.
    */
@@ -112,7 +112,7 @@ export interface PR_repository_pullRequest_reviews_nodes_commit {
 }
 
 export interface PR_repository_pullRequest_reviews_nodes_comments_nodes_author {
-  __typename: "EnterpriseUserAccount" | "Organization" | "User" | "Mannequin" | "Bot";
+  __typename: "Bot" | "EnterpriseUserAccount" | "Mannequin" | "Organization" | "User";
   /**
    * The username of the actor.
    */
@@ -244,7 +244,7 @@ export interface PR_repository_pullRequest_commits_nodes_commit_checkSuites {
 }
 
 export interface PR_repository_pullRequest_commits_nodes_commit_status_contexts_creator {
-  __typename: "EnterpriseUserAccount" | "Organization" | "User" | "Mannequin" | "Bot";
+  __typename: "Bot" | "EnterpriseUserAccount" | "Mannequin" | "Organization" | "User";
   /**
    * The username of the actor.
    */
@@ -332,7 +332,7 @@ export interface PR_repository_pullRequest_commits {
 }
 
 export interface PR_repository_pullRequest_comments_nodes_author {
-  __typename: "EnterpriseUserAccount" | "Organization" | "User" | "Mannequin" | "Bot";
+  __typename: "Bot" | "EnterpriseUserAccount" | "Mannequin" | "Organization" | "User";
   /**
    * The username of the actor.
    */
@@ -370,6 +370,10 @@ export interface PR_repository_pullRequest_comments_nodes {
    * The actor who authored the comment.
    */
   author: PR_repository_pullRequest_comments_nodes_author | null;
+  /**
+   * Identifies the primary key from the database.
+   */
+  databaseId: number | null;
   /**
    * The body as Markdown.
    */


Test patch:
diff --git a/src/_tests/fixtures/45836/mutations.json b/src/_tests/fixtures/45836/mutations.json
index 5e5a615..3cdff7c 100644
--- a/src/_tests/fixtures/45836/mutations.json
+++ b/src/_tests/fixtures/45836/mutations.json
@@ -45,7 +45,7 @@
     "variables": {
       "input": {
         "subjectId": "MDExOlB1bGxSZXF1ZXN0NDQzMDQ3Njgy",
-        "body": ":passport_control: Hi @mmorearty,\n\nI can't [accept a merge request](https://github.com/DefinitelyTyped/DefinitelyTyped#user-content-make-a-pull-request) until the PR has a green CI and was appropriately reviewed. I will let you know once that happens.\n\nThanks, and happy typing!\n<!--typescript_bot_wait-for-merge-offer-6c7735e-->"
+        "body": ":passport_control: Hi @mmorearty,\n\nI can't [accept a pull request](https://github.com/DefinitelyTyped/DefinitelyTyped#user-content-make-a-pull-request) until all of the checks in the \"Status\" section of [this comment](#issuecomment-???) are green. I will let you know once that happens.\n\nThanks, and happy typing!\n<!--typescript_bot_wait-for-merge-offer-6c7735e-->"
       }
     }
   },
diff --git a/src/_tests/fixtures/45836/result.json b/src/_tests/fixtures/45836/result.json
index 055b972..10f87f4 100644
--- a/src/_tests/fixtures/45836/result.json
+++ b/src/_tests/fixtures/45836/result.json
@@ -12,7 +12,7 @@
     },
     {
       "tag": "wait-for-merge-offer-6c7735e",
-      "status": ":passport_control: Hi @mmorearty,\n\nI can't [accept a merge request](https://github.com/DefinitelyTyped/DefinitelyTyped#user-content-make-a-pull-request) until the PR has a green CI and was appropriately reviewed. I will let you know once that happens.\n\nThanks, and happy typing!"
+      "status": ":passport_control: Hi @mmorearty,\n\nI can't [accept a pull request](https://github.com/DefinitelyTyped/DefinitelyTyped#user-content-make-a-pull-request) until all of the checks in the \"Status\" section of [this comment](#issuecomment-???) are green. I will let you know once that happens.\n\nThanks, and happy typing!"
     }
   ],
   "shouldClose": false,
diff --git a/src/_tests/fixtures/46120/mutations.json b/src/_tests/fixtures/46120/mutations.json
index f0d98ae..295eb56 100644
--- a/src/_tests/fixtures/46120/mutations.json
+++ b/src/_tests/fixtures/46120/mutations.json
@@ -31,7 +31,7 @@
     "variables": {
       "input": {
         "subjectId": "MDExOlB1bGxSZXF1ZXN0NDQ5ODI3NTQ3",
-        "body": ":passport_control: Hi @reubenrybnik,\n\nI can't [accept a merge request](https://github.com/DefinitelyTyped/DefinitelyTyped#user-content-make-a-pull-request) until the PR has a green CI and was appropriately reviewed. I will let you know once that happens.\n\nThanks, and happy typing!\n<!--typescript_bot_wait-for-merge-offer-5ef8fe2-->"
+        "body": ":passport_control: Hi @reubenrybnik,\n\nI can't [accept a pull request](https://github.com/DefinitelyTyped/DefinitelyTyped#user-content-make-a-pull-request) until all of the checks in the \"Status\" section of [this comment](#issuecomment-???) are green. I will let you know once that happens.\n\nThanks, and happy typing!\n<!--typescript_bot_wait-for-merge-offer-5ef8fe2-->"
       }
     }
   }
diff --git a/src/_tests/fixtures/46120/result.json b/src/_tests/fixtures/46120/result.json
index fd568cd..38e207a 100644
--- a/src/_tests/fixtures/46120/result.json
+++ b/src/_tests/fixtures/46120/result.json
@@ -17,7 +17,7 @@
     },
     {
       "tag": "wait-for-merge-offer-5ef8fe2",
-      "status": ":passport_control: Hi @reubenrybnik,\n\nI can't [accept a merge request](https://github.com/DefinitelyTyped/DefinitelyTyped#user-content-make-a-pull-request) until the PR has a green CI and was appropriately reviewed. I will let you know once that happens.\n\nThanks, and happy typing!"
+      "status": ":passport_control: Hi @reubenrybnik,\n\nI can't [accept a pull request](https://github.com/DefinitelyTyped/DefinitelyTyped#user-content-make-a-pull-request) until all of the checks in the \"Status\" section of [this comment](#issuecomment-???) are green. I will let you know once that happens.\n\nThanks, and happy typing!"
     }
   ],
   "shouldClose": false,
diff --git a/src/_tests/fixtures/48652-prereq/mutations.json b/src/_tests/fixtures/48652-prereq/mutations.json
index 561dcf0..5df67e5 100644
--- a/src/_tests/fixtures/48652-prereq/mutations.json
+++ b/src/_tests/fixtures/48652-prereq/mutations.json
@@ -51,7 +51,7 @@
     "variables": {
       "input": {
         "subjectId": "MDExOlB1bGxSZXF1ZXN0NTAwNjg4ODM0",
-        "body": ":passport_control: Hi @mgol,\n\nI can't [accept a merge request](https://github.com/DefinitelyTyped/DefinitelyTyped#user-content-make-a-pull-request) until the PR has a green CI and was appropriately reviewed. I will let you know once that happens.\n\nThanks, and happy typing!\n<!--typescript_bot_wait-for-merge-offer-06d8d67-->"
+        "body": ":passport_control: Hi @mgol,\n\nI can't [accept a pull request](https://github.com/DefinitelyTyped/DefinitelyTyped#user-content-make-a-pull-request) until all of the checks in the \"Status\" section of [this comment](#issuecomment-???) are green. I will let you know once that happens.\n\nThanks, and happy typing!\n<!--typescript_bot_wait-for-merge-offer-06d8d67-->"
       }
     }
   }
diff --git a/src/_tests/fixtures/48652-prereq/result.json b/src/_tests/fixtures/48652-prereq/result.json
index 5c10d6b..aa9e0a0 100644
--- a/src/_tests/fixtures/48652-prereq/result.json
+++ b/src/_tests/fixtures/48652-prereq/result.json
@@ -21,7 +21,7 @@
     },
     {
       "tag": "wait-for-merge-offer-06d8d67",
-      "status": ":passport_control: Hi @mgol,\n\nI can't [accept a merge request](https://github.com/DefinitelyTyped/DefinitelyTyped#user-content-make-a-pull-request) until the PR has a green CI and was appropriately reviewed. I will let you know once that happens.\n\nThanks, and happy typing!"
+      "status": ":passport_control: Hi @mgol,\n\nI can't [accept a pull request](https://github.com/DefinitelyTyped/DefinitelyTyped#user-content-make-a-pull-request) until all of the checks in the \"Status\" section of [this comment](#issuecomment-???) are green. I will let you know once that happens.\n\nThanks, and happy typing!"
     }
   ],
   "shouldClose": false,
diff --git a/src/_tests/fixtures/48652-retract-merge-offer-and-prerequest/mutations.json b/src/_tests/fixtures/48652-retract-merge-offer-and-prerequest/mutations.json
index 18df243..6aca719 100644
--- a/src/_tests/fixtures/48652-retract-merge-offer-and-prerequest/mutations.json
+++ b/src/_tests/fixtures/48652-retract-merge-offer-and-prerequest/mutations.json
@@ -56,7 +56,7 @@
     "variables": {
       "input": {
         "subjectId": "MDExOlB1bGxSZXF1ZXN0NTAwNjg4ODM0",
-        "body": ":passport_control: Hi @mgol,\n\nI can't [accept a merge request](https://github.com/DefinitelyTyped/DefinitelyTyped#user-content-make-a-pull-request) until the PR has a green CI and was appropriately reviewed. I will let you know once that happens.\n\nThanks, and happy typing!\n<!--typescript_bot_wait-for-merge-offer-06d8d67-->"
+        "body": ":passport_control: Hi @mgol,\n\nI can't [accept a pull request](https://github.com/DefinitelyTyped/DefinitelyTyped#user-content-make-a-pull-request) until all of the checks in the \"Status\" section of [this comment](#issuecomment-???) are green. I will let you know once that happens.\n\nThanks, and happy typing!\n<!--typescript_bot_wait-for-merge-offer-06d8d67-->"
       }
     }
   },
diff --git a/src/_tests/fixtures/48652-retract-merge-offer-and-prerequest/result.json b/src/_tests/fixtures/48652-retract-merge-offer-and-prerequest/result.json
index 5a752f9..4365cfc 100644
--- a/src/_tests/fixtures/48652-retract-merge-offer-and-prerequest/result.json
+++ b/src/_tests/fixtures/48652-retract-merge-offer-and-prerequest/result.json
@@ -15,7 +15,7 @@
     },
     {
       "tag": "wait-for-merge-offer-06d8d67",
-      "status": ":passport_control: Hi @mgol,\n\nI can't [accept a merge request](https://github.com/DefinitelyTyped/DefinitelyTyped#user-content-make-a-pull-request) until the PR has a green CI and was appropriately reviewed. I will let you know once that happens.\n\nThanks, and happy typing!"
+      "status": ":passport_control: Hi @mgol,\n\nI can't [accept a pull request](https://github.com/DefinitelyTyped/DefinitelyTyped#user-content-make-a-pull-request) until all of the checks in the \"Status\" section of [this comment](#issuecomment-???) are green. I will let you know once that happens.\n\nThanks, and happy typing!"
     }
   ],
   "shouldClose": false,
diff --git a/src/_tests/fixtures/53121/_downloads.json b/src/_tests/fixtures/53121/_downloads.json
new file mode 100644
index 0000000..ae177e3
--- /dev/null
+++ b/src/_tests/fixtures/53121/_downloads.json
@@ -0,0 +1,3 @@
+{
+  "mathjs": 498592
+}
diff --git a/src/_tests/fixtures/53121/_files.json b/src/_tests/fixtures/53121/_files.json
new file mode 100644
index 0000000..99e0714
--- /dev/null
+++ b/src/_tests/fixtures/53121/_files.json
@@ -0,0 +1,4 @@
+{
+  "master:types/mathjs/index.d.ts": "// Type definitions for mathjs 9.3\n// Project: https://mathjs.org/\n// Definitions by: Ilya Shestakov <https://github.com/siavol>,\n//                  Andy Patterson <https://github.com/andnp>,\n//                  Brad Besserman <https://github.com/bradbesserman>,\n//                  Pawel Krol <https://github.com/pawkrol>,\n//                  Charlee Li <https://github.com/charlee>,\n//                  Mark Wiemer <https://github.com/mark-wiemer>\n//                  Opportunity Liu <https://github.com/OpportunityLiu>\n// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped\n// TypeScript Version: 2.2\n\nimport { Decimal } from \"decimal.js\";\n\ndeclare const math: math.MathJsStatic;\nexport as namespace math;\nexport = math;\n\ntype NoLiteralType<T> = T extends number ? number : T extends string ? string : T extends boolean ? boolean : T;\ndeclare namespace math {\n    type MathArray = number[] | number[][];\n    type MathType = number | BigNumber | Fraction | Complex | Unit | MathArray | Matrix;\n    type MathExpression = string | string[] | MathArray | Matrix;\n\n    type FactoryFunction<T> = (scope: any) => T;\n\n    // FactoryFunctionMap can be nested; all nested objects will be flattened\n    interface FactoryFunctionMap {\n        [key: string]: FactoryFunction<any> | FactoryFunctionMap;\n    }\n\n    /** Available options for parse */\n    interface ParseOptions {\n        /** a set of custom nodes */\n        nodes?: Record<string, MathNode>;\n    }\n    /**\n     * Parse an expression. Returns a node tree, which can be evaluated by\n     * invoking node.evaluate().\n     *\n     * Note the evaluating arbitrary expressions may involve security risks,\n     * see [https://mathjs.org/docs/expressions/security.html](https://mathjs.org/docs/expressions/security.html) for more information.\n     *\n     * Syntax:\n     *\n     *     math.parse(expr)\n     *     math.parse(expr, options)\n     *     math.parse([expr1, expr2, expr3, ...])\n     *     math.parse([expr1, expr2, expr3, ...], options)\n     *\n     * Example:\n     *\n     *     const node1 = math.parse('sqrt(3^2 + 4^2)')\n     *     node1.compile().evaluate() // 5\n     *\n     *     let scope = {a:3, b:4}\n     *     const node2 = math.parse('a * b') // 12\n     *     const code2 = node2.compile()\n     *     code2.evaluate(scope) // 12\n     *     scope.a = 5\n     *     code2.evaluate(scope) // 20\n     *\n     *     const nodes = math.parse(['a = 3', 'b = 4', 'a * b'])\n     *     nodes[2].compile().evaluate() // 12\n     *\n     * See also:\n     *\n     *     evaluate, compile\n     */\n    interface ParseFunction {\n        /**\n         * Parse an expression. Returns a node tree, which can be evaluated by\n         * invoking node.evaluate();\n         *\n         * @param expr Expression to be parsed\n         * @param options Available options\n         * @returns A node\n         */\n        (expr: MathExpression, options?: ParseOptions): MathNode;\n\n        /**\n         * Parse an expression. Returns a node tree, which can be evaluated by\n         * invoking node.evaluate();\n         *\n         * @param exprs Expressions to be parsed\n         * @param options Available options\n         * @returns An array of nodes\n         */\n        (exprs: MathExpression[], options?: ParseOptions): MathNode[];\n\n        /**\n         * Checks whether the current character `c` is a valid alpha character:\n         *\n         * - A latin letter (upper or lower case) Ascii: a-z, A-Z\n         * - An underscore                        Ascii: _\n         * - A dollar sign                        Ascii: $\n         * - A latin letter with accents          Unicode: \\u00C0 - \\u02AF\n         * - A greek letter                       Unicode: \\u0370 - \\u03FF\n         * - A mathematical alphanumeric symbol   Unicode: \\u{1D400} - \\u{1D7FF} excluding invalid code points\n         *\n         * The previous and next characters are needed to determine whether\n         * this character is part of a unicode surrogate pair.\n         *\n         * @param c      Current character in the expression\n         * @param cPrev  Previous character\n         * @param cNext  Next character\n         */\n        isAlpha(c: string, cPrev: string, cNext: string): boolean;\n        /**\n         * Test whether a character is a valid latin, greek, or letter-like character\n         *\n         * @param c\n         */\n        isValidLatinOrGreek(c: string): boolean;\n        /**\n         * Test whether two given 16 bit characters form a surrogate pair of a\n         * unicode math symbol.\n         *\n         * https://unicode-table.com/en/\n         * https://www.wikiwand.com/en/Mathematical_operators_and_symbols_in_Unicode\n         *\n         * Note: In ES6 will be unicode aware:\n         * https://stackoverflow.com/questions/280712/javascript-unicode-regexes\n         * https://mathiasbynens.be/notes/es6-unicode-regex\n         *\n         * @param high\n         * @param low\n         */\n        isValidMathSymbol(high: string, low: string): boolean;\n        /**\n         * Check whether given character c is a white space character: space, tab, or enter\n         *\n         * @param c\n         * @param nestingLevel\n         */\n        isWhitespace(c: string, nestingLevel: number): boolean;\n        /**\n         * Test whether the character c is a decimal mark (dot).\n         * This is the case when it's not the start of a delimiter '.*', './', or '.^'\n         *\n         * @param  c\n         * @param  cNext\n         */\n        isDecimalMark(c: string, cNext: string): boolean;\n        /**\n         * checks if the given char c is a digit or dot\n         *\n         * @param  c   a string with one character\n         */\n        isDigitDot(c: string): boolean;\n        /**\n         * checks if the given char c is a digit\n         *\n         * @param  c   a string with one character\n         */\n        isDigit(c: string): boolean;\n        /**\n         * checks if the given char c is a hex digit\n         *\n         * @param c   a string with one character\n         */\n        isHexDigit(c: string): boolean;\n    }\n\n    type MathJsFunctionName = keyof MathJsStatic;\n\n    interface MathJsStatic extends FactoryDependencies {\n        e: number;\n        pi: number;\n        i: number;\n        Infinity: number;\n        LN2: number;\n        LN10: number;\n        LOG2E: number;\n        LOG10E: number;\n        NaN: number;\n        phi: number;\n        SQRT1_2: number;\n        SQRT2: number;\n        tau: number;\n\n        uninitialized: any;\n        version: string;\n\n        expression: MathNode;\n        json: MathJsJson;\n\n        /**\n         * If null were to be included in this interface, it would be\n         * auto-suggested as an import in VSCode. This causes issues because\n         * `null` is not a valid label.\n         *\n         * @see https://github.com/josdejong/mathjs/issues/2019\n         */\n        // null: number;\n\n        /*************************************************************************\n         * Core functions\n         ************************************************************************/\n\n        /**\n         * Set configuration options for math.js, and get current options. Will\n         * emit a ‘config’ event, with arguments (curr, prev, changes).\n         * @param options Available options: {number} epsilon Minimum relative\n         * difference between two compared values, used by all comparison\n         * functions. {string} matrix A string ‘Matrix’ (default) or ‘Array’.\n         * {string} number A string ‘number’ (default), ‘BigNumber’, or\n         * ‘Fraction’ {number} precision The number of significant digits for\n         * BigNumbers. Not applicable for Numbers. {string} parenthesis How to\n         * display parentheses in LaTeX and string output. {string} randomSeed\n         * Random seed for seeded pseudo random number generator. Set to null to\n         * randomly seed.\n         * @returns Returns the current configuration\n         */\n        config: (options: ConfigOptions) => ConfigOptions;\n        /**\n         * Create a typed-function which checks the types of the arguments and\n         * can match them against multiple provided signatures. The\n         * typed-function automatically converts inputs in order to find a\n         * matching signature. Typed functions throw informative errors in case\n         * of wrong input arguments.\n         * @param name Optional name for the typed-function\n         * @param signatures Object with one or multiple function signatures\n         * @returns The created typed-function.\n         */\n        typed: (name: string, signatures: Record<string, (...args: any[]) => any>) => (...args: any[]) => any;\n\n        /*************************************************************************\n         * Construction functions\n         ************************************************************************/\n\n        /**\n         * Create a BigNumber, which can store numbers with arbitrary precision.\n         * When a matrix is provided, all elements will be converted to\n         * BigNumber.\n         * @param x Value for the big number, 0 by default.\n         * @returns The created bignumber\n         */\n        bignumber(\n            x?: number | string | Fraction | BigNumber | MathArray | Matrix | boolean | Fraction | null,\n        ): BigNumber;\n\n        /**\n         * Create a boolean or convert a string or number to a boolean. In case\n         * of a number, true is returned for non-zero numbers, and false in case\n         * of zero. Strings can be 'true' or 'false', or can contain a number.\n         * When value is a matrix, all elements will be converted to boolean.\n         * @param x A value of any type\n         * @returns The boolean value\n         */\n        boolean(x: string | number | boolean | MathArray | Matrix | null): boolean | MathArray | Matrix;\n\n        /**\n         * Wrap any value in a chain, allowing to perform chained operations on\n         * the value. All methods available in the math.js library can be called\n         * upon the chain, and then will be evaluated with the value itself as\n         * first argument. The chain can be closed by executing chain.done(),\n         * which returns the final value. The chain has a number of spec",
+  "c13f5d7c969561db0ac38464086406b6554e711c:types/mathjs/index.d.ts": "// Type definitions for mathjs 9.3\n// Project: https://mathjs.org/\n// Definitions by: Ilya Shestakov <https://github.com/siavol>,\n//                  Andy Patterson <https://github.com/andnp>,\n//                  Brad Besserman <https://github.com/bradbesserman>,\n//                  Pawel Krol <https://github.com/pawkrol>,\n//                  Charlee Li <https://github.com/charlee>,\n//                  Mark Wiemer <https://github.com/mark-wiemer>\n//                  Opportunity Liu <https://github.com/OpportunityLiu>\n// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped\n// TypeScript Version: 2.2\n\nimport { Decimal } from \"decimal.js\";\n\ndeclare const math: math.MathJsStatic;\nexport as namespace math;\nexport = math;\n\ntype NoLiteralType<T> = T extends number ? number : T extends string ? string : T extends boolean ? boolean : T;\ndeclare namespace math {\n    type MathArray = number[] | number[][];\n    type MathType = number | BigNumber | Fraction | Complex | Unit | MathArray | Matrix;\n    type MathExpression = string | string[] | MathArray | Matrix;\n\n    type FactoryFunction<T> = (scope: any) => T;\n\n    // FactoryFunctionMap can be nested; all nested objects will be flattened\n    interface FactoryFunctionMap {\n        [key: string]: FactoryFunction<any> | FactoryFunctionMap;\n    }\n\n    /** Available options for parse */\n    interface ParseOptions {\n        /** a set of custom nodes */\n        nodes?: Record<string, MathNode>;\n    }\n    /**\n     * Parse an expression. Returns a node tree, which can be evaluated by\n     * invoking node.evaluate().\n     *\n     * Note the evaluating arbitrary expressions may involve security risks,\n     * see [https://mathjs.org/docs/expressions/security.html](https://mathjs.org/docs/expressions/security.html) for more information.\n     *\n     * Syntax:\n     *\n     *     math.parse(expr)\n     *     math.parse(expr, options)\n     *     math.parse([expr1, expr2, expr3, ...])\n     *     math.parse([expr1, expr2, expr3, ...], options)\n     *\n     * Example:\n     *\n     *     const node1 = math.parse('sqrt(3^2 + 4^2)')\n     *     node1.compile().evaluate() // 5\n     *\n     *     let scope = {a:3, b:4}\n     *     const node2 = math.parse('a * b') // 12\n     *     const code2 = node2.compile()\n     *     code2.evaluate(scope) // 12\n     *     scope.a = 5\n     *     code2.evaluate(scope) // 20\n     *\n     *     const nodes = math.parse(['a = 3', 'b = 4', 'a * b'])\n     *     nodes[2].compile().evaluate() // 12\n     *\n     * See also:\n     *\n     *     evaluate, compile\n     */\n    interface ParseFunction {\n        /**\n         * Parse an expression. Returns a node tree, which can be evaluated by\n         * invoking node.evaluate();\n         *\n         * @param expr Expression to be parsed\n         * @param options Available options\n         * @returns A node\n         */\n        (expr: MathExpression, options?: ParseOptions): MathNode;\n\n        /**\n         * Parse an expression. Returns a node tree, which can be evaluated by\n         * invoking node.evaluate();\n         *\n         * @param exprs Expressions to be parsed\n         * @param options Available options\n         * @returns An array of nodes\n         */\n        (exprs: MathExpression[], options?: ParseOptions): MathNode[];\n\n        /**\n         * Checks whether the current character `c` is a valid alpha character:\n         *\n         * - A latin letter (upper or lower case) Ascii: a-z, A-Z\n         * - An underscore                        Ascii: _\n         * - A dollar sign                        Ascii: $\n         * - A latin letter with accents          Unicode: \\u00C0 - \\u02AF\n         * - A greek letter                       Unicode: \\u0370 - \\u03FF\n         * - A mathematical alphanumeric symbol   Unicode: \\u{1D400} - \\u{1D7FF} excluding invalid code points\n         *\n         * The previous and next characters are needed to determine whether\n         * this character is part of a unicode surrogate pair.\n         *\n         * @param c      Current character in the expression\n         * @param cPrev  Previous character\n         * @param cNext  Next character\n         */\n        isAlpha(c: string, cPrev: string, cNext: string): boolean;\n        /**\n         * Test whether a character is a valid latin, greek, or letter-like character\n         *\n         * @param c\n         */\n        isValidLatinOrGreek(c: string): boolean;\n        /**\n         * Test whether two given 16 bit characters form a surrogate pair of a\n         * unicode math symbol.\n         *\n         * https://unicode-table.com/en/\n         * https://www.wikiwand.com/en/Mathematical_operators_and_symbols_in_Unicode\n         *\n         * Note: In ES6 will be unicode aware:\n         * https://stackoverflow.com/questions/280712/javascript-unicode-regexes\n         * https://mathiasbynens.be/notes/es6-unicode-regex\n         *\n         * @param high\n         * @param low\n         */\n        isValidMathSymbol(high: string, low: string): boolean;\n        /**\n         * Check whether given character c is a white space character: space, tab, or enter\n         *\n         * @param c\n         * @param nestingLevel\n         */\n        isWhitespace(c: string, nestingLevel: number): boolean;\n        /**\n         * Test whether the character c is a decimal mark (dot).\n         * This is the case when it's not the start of a delimiter '.*', './', or '.^'\n         *\n         * @param  c\n         * @param  cNext\n         */\n        isDecimalMark(c: string, cNext: string): boolean;\n        /**\n         * checks if the given char c is a digit or dot\n         *\n         * @param  c   a string with one character\n         */\n        isDigitDot(c: string): boolean;\n        /**\n         * checks if the given char c is a digit\n         *\n         * @param  c   a string with one character\n         */\n        isDigit(c: string): boolean;\n        /**\n         * checks if the given char c is a hex digit\n         *\n         * @param c   a string with one character\n         */\n        isHexDigit(c: string): boolean;\n    }\n\n    type MathJsFunctionName = keyof MathJsStatic;\n\n    interface MathJsStatic extends FactoryDependencies {\n        e: number;\n        pi: number;\n        i: number;\n        Infinity: number;\n        LN2: number;\n        LN10: number;\n        LOG2E: number;\n        LOG10E: number;\n        NaN: number;\n        phi: number;\n        SQRT1_2: number;\n        SQRT2: number;\n        tau: number;\n\n        uninitialized: any;\n        version: string;\n\n        expression: MathNode;\n        json: MathJsJson;\n\n        /**\n         * If null were to be included in this interface, it would be\n         * auto-suggested as an import in VSCode. This causes issues because\n         * `null` is not a valid label.\n         *\n         * @see https://github.com/josdejong/mathjs/issues/2019\n         */\n        // null: number;\n\n        /*************************************************************************\n         * Core functions\n         ************************************************************************/\n\n        /**\n         * Set configuration options for math.js, and get current options. Will\n         * emit a ‘config’ event, with arguments (curr, prev, changes).\n         * @param options Available options: {number} epsilon Minimum relative\n         * difference between two compared values, used by all comparison\n         * functions. {string} matrix A string ‘Matrix’ (default) or ‘Array’.\n         * {string} number A string ‘number’ (default), ‘BigNumber’, or\n         * ‘Fraction’ {number} precision The number of significant digits for\n         * BigNumbers. Not applicable for Numbers. {string} parenthesis How to\n         * display parentheses in LaTeX and string output. {string} randomSeed\n         * Random seed for seeded pseudo random number generator. Set to null to\n         * randomly seed.\n         * @returns Returns the current configuration\n         */\n        config: (options: ConfigOptions) => ConfigOptions;\n        /**\n         * Create a typed-function which checks the types of the arguments and\n         * can match them against multiple provided signatures. The\n         * typed-function automatically converts inputs in order to find a\n         * matching signature. Typed functions throw informative errors in case\n         * of wrong input arguments.\n         * @param name Optional name for the typed-function\n         * @param signatures Object with one or multiple function signatures\n         * @returns The created typed-function.\n         */\n        typed: (name: string, signatures: Record<string, (...args: any[]) => any>) => (...args: any[]) => any;\n\n        /*************************************************************************\n         * Construction functions\n         ************************************************************************/\n\n        /**\n         * Create a BigNumber, which can store numbers with arbitrary precision.\n         * When a matrix is provided, all elements will be converted to\n         * BigNumber.\n         * @param x Value for the big number, 0 by default.\n         * @returns The created bignumber\n         */\n        bignumber(\n            x?: number | string | Fraction | BigNumber | MathArray | Matrix | boolean | Fraction | null,\n        ): BigNumber;\n\n        /**\n         * Create a boolean or convert a string or number to a boolean. In case\n         * of a number, true is returned for non-zero numbers, and false in case\n         * of zero. Strings can be 'true' or 'false', or can contain a number.\n         * When value is a matrix, all elements will be converted to boolean.\n         * @param x A value of any type\n         * @returns The boolean value\n         */\n        boolean(x: string | number | boolean | MathArray | Matrix | null): boolean | MathArray | Matrix;\n\n        /**\n         * Wrap any value in a chain, allowing to perform chained operations on\n         * the value. All methods available in the math.js library can be called\n         * upon the chain, and then will be evaluated with the value itself as\n         * first argument. The chain can be closed by executing chain.done(),\n         * which returns the final value. The chain has a number of spec"
+}
diff --git a/src/_tests/fixtures/53121/_response.json b/src/_tests/fixtures/53121/_response.json
new file mode 100644
index 0000000..bd23bad
--- /dev/null
+++ b/src/_tests/fixtures/53121/_response.json
@@ -0,0 +1,211 @@
+{
+  "data": {
+    "repository": {
+      "id": "MDEwOlJlcG9zaXRvcnk2MDkzMzE2",
+      "pullRequest": {
+        "id": "MDExOlB1bGxSZXF1ZXN0NjQ4NjIzMjYy",
+        "title": "[mathjs]: Fix simplify argument types",
+        "createdAt": "2021-05-20T09:16:27Z",
+        "author": {
+          "login": "nitroin",
+          "__typename": "User"
+        },
+        "authorAssociation": "FIRST_TIME_CONTRIBUTOR",
+        "baseRef": {
+          "name": "master",
+          "__typename": "Ref"
+        },
+        "labels": {
+          "nodes": [
+            {
+              "name": "Popular package",
+              "__typename": "Label"
+            }
+          ],
+          "__typename": "LabelConnection"
+        },
+        "isDraft": false,
+        "mergeable": "MERGEABLE",
+        "number": 53121,
+        "state": "OPEN",
+        "headRefOid": "c13f5d7c969561db0ac38464086406b6554e711c",
+        "timelineItems": {
+          "nodes": [],
+          "__typename": "PullRequestTimelineItemsConnection"
+        },
+        "reviews": {
+          "nodes": [],
+          "__typename": "PullRequestReviewConnection"
+        },
+        "commits": {
+          "totalCount": 1,
+          "nodes": [
+            {
+              "commit": {
+                "checkSuites": {
+                  "nodes": [
+                    {
+                      "databaseId": 2787240197,
+                      "app": {
+                        "name": "GitHub Actions",
+                        "__typename": "App"
+                      },
+                      "conclusion": "SUCCESS",
+                      "resourcePath": "/DefinitelyTyped/DefinitelyTyped/commit/c13f5d7c969561db0ac38464086406b6554e711c/checks?check_suite_id=2787240197",
+                      "status": "COMPLETED",
+                      "url": "https://github.com/DefinitelyTyped/DefinitelyTyped/commit/c13f5d7c969561db0ac38464086406b6554e711c/checks?check_suite_id=2787240197",
+                      "checkRuns": {
+                        "nodes": [
+                          {
+                            "title": "build",
+                            "__typename": "CheckRun"
+                          }
+                        ],
+                        "__typename": "CheckRunConnection"
+                      },
+                      "__typename": "CheckSuite"
+                    },
+                    {
+                      "databaseId": 2787240441,
+                      "app": {
+                        "name": "GitHub Actions",
+                        "__typename": "App"
+                      },
+                      "conclusion": "SUCCESS",
+                      "resourcePath": "/DefinitelyTyped/DefinitelyTyped/commit/c13f5d7c969561db0ac38464086406b6554e711c/checks?check_suite_id=2787240441",
+                      "status": "COMPLETED",
+                      "url": "https://github.com/DefinitelyTyped/DefinitelyTyped/commit/c13f5d7c969561db0ac38464086406b6554e711c/checks?check_suite_id=2787240441",
+                      "checkRuns": {
+                        "nodes": [
+                          {
+                            "title": null,
+                            "__typename": "CheckRun"
+                          }
+                        ],
+                        "__typename": "CheckRunConnection"
+                      },
+                      "__typename": "CheckSuite"
+                    },
+                    {
+                      "databaseId": 2787241779,
+                      "app": {
+                        "name": "Azure Pipelines",
+                        "__typename": "App"
+                      },
+                      "conclusion": "SUCCESS",
+                      "resourcePath": "/DefinitelyTyped/DefinitelyTyped/commit/c13f5d7c969561db0ac38464086406b6554e711c/checks?check_suite_id=2787241779",
+                      "status": "COMPLETED",
+                      "url": "https://github.com/DefinitelyTyped/DefinitelyTyped/commit/c13f5d7c969561db0ac38464086406b6554e711c/checks?check_suite_id=2787241779",
+                      "checkRuns": {
+                        "nodes": [
+                          {
+                            "title": "Build #20210520.18 succeeded",
+                            "__typename": "CheckRun"
+                          }
+                        ],
+                        "__typename": "CheckRunConnection"
+                      },
+                      "__typename": "CheckSuite"
+                    }
+                  ],
+                  "__typename": "CheckSuiteConnection"
+                },
+                "status": null,
+                "authoredDate": "2021-05-20T09:09:10Z",
+                "committedDate": "2021-05-20T09:09:10Z",
+                "pushedDate": "2021-05-20T09:10:15Z",
+                "oid": "c13f5d7c969561db0ac38464086406b6554e711c",
+                "__typename": "Commit"
+              },
+              "__typename": "PullRequestCommit"
+            }
+          ],
+          "__typename": "PullRequestCommitConnection"
+        },
+        "comments": {
+          "totalCount": 2,
+          "nodes": [
+            {
+              "id": "MDEyOklzc3VlQ29tbWVudDg0NDg5OTYzOQ==",
+              "author": {
+                "login": "typescript-bot",
+                "__typename": "User"
+              },
+              "databaseId": 844899639,
+              "body": "@nitroin Thank you for submitting this PR! I see this is your first time submitting to DefinitelyTyped 👋 — I'm the local bot who will help you through the process of getting things through.\n\n***This is a live comment which I will keep updated.***\n\n## 1 package in this PR\n\n* `mathjs` — [on npm](https://www.npmjs.com/package/mathjs), [on unpkg](https://unpkg.com/browse/mathjs@latest/)\n\n## Code Reviews\n\nBecause you edited one package and updated the tests (👏), I can help you merge this PR once someone else signs off on it.\n\n## Status\n\n * ✅ No merge conflicts\n * ✅ Continuous integration tests have passed\n * 🕐 Most recent commit is approved by type definition owners or DT maintainers\n\nOnce every item on this list is checked, I'll ask you for permission to merge and publish the changes.\n\n----------------------\n... diagnostics scrubbed ...\n<!--typescript_bot_welcome-->",
+              "createdAt": "2021-05-20T09:17:04Z",
+              "reactions": {
+                "nodes": [],
+                "__typename": "ReactionConnection"
+              },
+              "__typename": "IssueComment"
+            },
+            {
+              "id": "MDEyOklzc3VlQ29tbWVudDg0NDg5OTY1Ng==",
+              "author": {
+                "login": "typescript-bot",
+                "__typename": "User"
+              },
+              "databaseId": 844899656,
+              "body": "🔔 @siavol @andnp @bradbesserman @pawkrol @charlee @mark-wiemer @OpportunityLiu — please [review this PR](https://github.com/DefinitelyTyped/DefinitelyTyped/pull/53121/files) in the next few days. Be sure to explicitly select **`Approve`** or **`Request Changes`** in the GitHub UI so I know what's going on.\n<!--typescript_bot_pinging-reviewers-->",
+              "createdAt": "2021-05-20T09:17:06Z",
+              "reactions": {
+                "nodes": [],
+                "__typename": "ReactionConnection"
+              },
+              "__typename": "IssueComment"
+            }
+          ],
+          "__typename": "IssueCommentConnection"
+        },
+        "files": {
+          "totalCount": 2,
+          "nodes": [
+            {
+              "path": "types/mathjs/index.d.ts",
+              "additions": 14,
+              "deletions": 2,
+              "__typename": "PullRequestChangedFile"
+            },
+            {
+              "path": "types/mathjs/mathjs-tests.ts",
+              "additions": 16,
+              "deletions": 0,
+              "__typename": "PullRequestChangedFile"
+            }
+          ],
+          "pageInfo": {
+            "hasNextPage": false,
+            "endCursor": "Mg",
+            "__typename": "PageInfo"
+          },
+          "__typename": "PullRequestChangedFileConnection"
+        },
+        "projectCards": {
+          "nodes": [
+            {
+              "id": "MDExOlByb2plY3RDYXJkNjE0ODYyMDY=",
+              "project": {
+                "id": "MDc6UHJvamVjdDM3NDExMDQ=",
+                "number": 5,
+                "name": "New Pull Request Status Board",
+                "__typename": "Project"
+              },
+              "column": {
+                "id": "MDEzOlByb2plY3RDb2x1bW43NTUyOTMw",
+                "name": "Waiting for Code Reviews",
+                "__typename": "ProjectColumn"
+              },
+              "__typename": "ProjectCard"
+            }
+          ],
+          "__typename": "ProjectCardConnection"
+        },
+        "__typename": "PullRequest"
+      },
+      "__typename": "Repository"
+    }
+  },
+  "loading": false,
+  "networkStatus": 7
+}
diff --git a/src/_tests/fixtures/53121/derived.json b/src/_tests/fixtures/53121/derived.json
new file mode 100644
index 0000000..d817c0c
--- /dev/null
+++ b/src/_tests/fixtures/53121/derived.json
@@ -0,0 +1,44 @@
+{
+  "type": "info",
+  "now": "2021-05-20T13:55:13.459Z",
+  "pr_number": 53121,
+  "author": "nitroin",
+  "headCommitOid": "c13f5d7c969561db0ac38464086406b6554e711c",
+  "lastPushDate": "2021-05-20T09:10:15.000Z",
+  "lastActivityDate": "2021-05-20T09:16:27.000Z",
+  "hasMergeConflict": false,
+  "isFirstContribution": true,
+  "tooManyFiles": false,
+  "popularityLevel": "Popular",
+  "pkgInfo": [
+    {
+      "name": "mathjs",
+      "kind": "edit",
+      "files": [
+        {
+          "path": "types/mathjs/index.d.ts",
+          "kind": "definition"
+        },
+        {
+          "path": "types/mathjs/mathjs-tests.ts",
+          "kind": "test"
+        }
+      ],
+      "owners": [
+        "siavol",
+        "andnp",
+        "bradbesserman",
+        "pawkrol",
+        "charlee",
+        "mark-wiemer",
+        "OpportunityLiu"
+      ],
+      "addedOwners": [],
+      "deletedOwners": [],
+      "popularityLevel": "Popular"
+    }
+  ],
+  "reviews": [],
+  "mainBotCommentID": 844899639,
+  "ciResult": "pass"
+}
diff --git a/src/_tests/fixtures/53121/mutations.json b/src/_tests/fixtures/53121/mutations.json
new file mode 100644
index 0000000..0e2c3b3
--- /dev/null
+++ b/src/_tests/fixtures/53121/mutations.json
@@ -0,0 +1,11 @@
+[
+  {
+    "mutation": "mutation ($input: UpdateIssueCommentInput!) {\n  updateIssueComment(input: $input) {\n    __typename\n  }\n}\n",
+    "variables": {
+      "input": {
+        "id": "MDEyOklzc3VlQ29tbWVudDg0NDg5OTYzOQ==",
+        "body": "@nitroin Thank you for submitting this PR! I see this is your first time submitting to DefinitelyTyped 👋 — I'm the local bot who will help you through the process of getting things through.\n\n***This is a live comment which I will keep updated.***\n\n## 1 package in this PR\n\n* `mathjs` — [on npm](https://www.npmjs.com/package/mathjs), [on unpkg](https://unpkg.com/browse/mathjs@latest/)\n\n## Code Reviews\n\nBecause you edited one package and updated the tests (👏), I can help you merge this PR once someone else signs off on it.\n\nYou can test the changes in this [PR in the Playground](https://www.typescriptlang.org/play/?dtPR=53121&install-plugin=playground-dt-review).\n\n## Status\n\n * ✅ No merge conflicts\n * ✅ Continuous integration tests have passed\n * 🕐 Most recent commit is approved by type definition owners or DT maintainers\n\nOnce every item on this list is checked, I'll ask you for permission to merge and publish the changes.\n\n----------------------\n... diagnostics scrubbed ...\n<!--typescript_bot_welcome-->"
+      }
+    }
+  }
+]
diff --git a/src/_tests/fixtures/53121/result.json b/src/_tests/fixtures/53121/result.json
new file mode 100644
index 0000000..1ca31c5
--- /dev/null
+++ b/src/_tests/fixtures/53121/result.json
@@ -0,0 +1,19 @@
+{
+  "projectColumn": "Waiting for Code Reviews",
+  "labels": [
+    "Popular package"
+  ],
+  "responseComments": [
+    {
+      "tag": "welcome",
+      "status": "@nitroin Thank you for submitting this PR! I see this is your first time submitting to DefinitelyTyped 👋 — I'm the local bot who will help you through the process of getting things through.\n\n***This is a live comment which I will keep updated.***\n\n## 1 package in this PR\n\n* `mathjs` — [on npm](https://www.npmjs.com/package/mathjs), [on unpkg](https://unpkg.com/browse/mathjs@latest/)\n\n## Code Reviews\n\nBecause you edited one package and updated the tests (👏), I can help you merge this PR once someone else signs off on it.\n\nYou can test the changes in this [PR in the Playground](https://www.typescriptlang.org/play/?dtPR=53121&install-plugin=playground-dt-review).\n\n## Status\n\n * ✅ No merge conflicts\n * ✅ Continuous integration tests have passed\n * 🕐 Most recent commit is approved by type definition owners or DT maintainers\n\nOnce every item on this list is checked, I'll ask you for permission to merge and publish the changes.\n\n----------------------\n... diagnostics scrubbed ..."
+    },
+    {
+      "tag": "pinging-reviewers",
+      "status": "🔔 @siavol @andnp @bradbesserman @pawkrol @charlee @mark-wiemer @OpportunityLiu — please [review this PR](https://github.com/DefinitelyTyped/DefinitelyTyped/pull/53121/files) in the next few days. Be sure to explicitly select **`Approve`** or **`Request Changes`** in the GitHub UI so I know what's going on."
+    }
+  ],
+  "shouldClose": false,
+  "shouldMerge": false,
+  "shouldUpdateLabels": true
+}