From fd80aa7acde5bcf06e08c87294fda254ab5aadb9 Mon Sep 17 00:00:00 2001 From: spoukyii <61633921+spoukyii@users.noreply.github.com> Date: Thu, 5 Nov 2026 23:29:59 -0800 Subject: [PATCH 1/2] test(azure-devops): an edited pull request comment carries its edit time Reads a thread with one comment whose text was edited and one whose other fields changed. Azure reports a text edit in lastContentUpdatedDate, but decodeThreadsJson gives neither comment an editedAt, so this fails here. --- .../server/azureDevOpsPullRequestJson.test.ts | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/packages/source-control-azure-devops/src/server/azureDevOpsPullRequestJson.test.ts b/packages/source-control-azure-devops/src/server/azureDevOpsPullRequestJson.test.ts index b9b1e36a9434..9a1911655c26 100644 --- a/packages/source-control-azure-devops/src/server/azureDevOpsPullRequestJson.test.ts +++ b/packages/source-control-azure-devops/src/server/azureDevOpsPullRequestJson.test.ts @@ -248,6 +248,41 @@ describe("decodeThreadsJson", () => { expect(comments.map((comment) => comment.id)).toEqual(["4:1", "4:2", "4:3"]); }); + it("marks a comment whose text was edited, not one only otherwise updated", () => { + const comments = expectSuccess( + decodeThreadsJson( + asJson({ + value: [ + { + id: 5, + comments: [ + { + id: 1, + content: "Edited remark.", + publishedDate: "2026-07-02T00:00:00Z", + lastUpdatedDate: "2026-07-02T03:00:00Z", + lastContentUpdatedDate: "2026-07-02T03:00:00Z", + }, + { + id: 2, + content: "Updated remark.", + publishedDate: "2026-07-02T01:00:00Z", + lastUpdatedDate: "2026-07-02T04:00:00Z", + lastContentUpdatedDate: "2026-07-02T01:00:00Z", + }, + ], + }, + ], + }), + ), + ); + + expect(comments.map((comment) => comment.editedAt)).toEqual([ + "2026-07-02T03:00:00Z", + undefined, + ]); + }); + it("drops deleted threads and threads with nothing to show", () => { const comments = expectSuccess( decodeThreadsJson( From 1f13b78b9c5d322cd8a32dcd1f2addf417ec3031 Mon Sep 17 00:00:00 2001 From: spoukyii <61633921+spoukyii@users.noreply.github.com> Date: Thu, 5 Nov 2026 23:32:18 -0800 Subject: [PATCH 2/2] fix(azure-devops): edited comments wake PR watchers A PR watch wakes for a remark whose editedAt, or else createdAt, is past its watermark. Azure DevOps comments never carried editedAt, so a reviewer who edited a comment after the watch started, for instance to add the change they wanted, never woke the agent. Forgejo (#18120) and GitLab (#30403) already report their edits. decodeThreadsJson now reads each comment's lastContentUpdatedDate, which Azure moves only when the text changes, unlike lastUpdatedDate, and sets editedAt when it is later than publishedDate. Bug: an edited Azure DevOps pull request comment never wakes a PR watch --- .../src/server/azureDevOpsPullRequestJson.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/source-control-azure-devops/src/server/azureDevOpsPullRequestJson.ts b/packages/source-control-azure-devops/src/server/azureDevOpsPullRequestJson.ts index b3632ef1af98..7d9a22af1d98 100644 --- a/packages/source-control-azure-devops/src/server/azureDevOpsPullRequestJson.ts +++ b/packages/source-control-azure-devops/src/server/azureDevOpsPullRequestJson.ts @@ -85,6 +85,8 @@ const RawThreadSchema = Schema.Struct({ content: Schema.optional(Schema.NullOr(Schema.String)), author: Schema.optional(Schema.NullOr(RawIdentitySchema)), publishedDate: Schema.optional(Schema.NullOr(Schema.String)), + // lastUpdatedDate moves on any change to the comment; this one only on its text. + lastContentUpdatedDate: Schema.optional(Schema.NullOr(Schema.String)), isDeleted: Schema.optional(Schema.NullOr(Schema.Boolean)), commentType: Schema.optional(Schema.NullOr(Schema.String)), }), @@ -301,6 +303,7 @@ export function decodeThreadsJson( const path = toRepositoryPath(thread.threadContext?.filePath); for (const comment of thread.comments ?? []) { const publishedDate = trimmed(comment.publishedDate); + const editedAt = trimmed(comment.lastContentUpdatedDate); if ( comment.isDeleted === true || comment.commentType?.trim().toLowerCase() === "system" || @@ -315,6 +318,9 @@ export function decodeThreadsJson( author: toActor(comment.author), body: comment.content ?? "", createdAt: publishedDate, + ...(editedAt !== null && Date.parse(editedAt) > Date.parse(publishedDate) + ? { editedAt } + : {}), url: null, path, reviewState: null,