Skip to content

Comment the semantic diff on the pull request as Markdown - #8958

Merged
cknitt merged 9 commits into
masterfrom
semantic-diff-markdown
Oct 22, 2026
Merged

cknitt merged 9 commits into
masterfrom
semantic-diff-markdown

Conversation

@cknitt

@cknitt cknitt commented Oct 22, 2026 •

Copy link
Copy Markdown
Member

Following feedback that the semantic diff would be nicer directly in the pull request: the Semantic Diff workflow's comment now holds the commit records themselves, drawn as GitHub Markdown, with the link to the full page at the top.

A comment can't carry the page's HTML (GitHub strips styles and classes), so each form is drawn in what GitHub renders natively:

Form In the comment
trees, JS, Lambda, ReScript, diagnostics, text ```diff block from the page's line alignment (red/green lines)
matrices, mappings the same, columns and arrows padded to align
reanalyze reports a diff of findings; a run of unchanged findings is one … N unchanged findings line
typing rules ```math (\dfrac premises/conclusion, rule name), Before and After side by side in a table, changed parts \color{red} / \color{green}
examples, single versions fenced rescript / js blocks
Why / Breaking / Review blockquote / [!CAUTION] alert / list

The page keeps every commit, but each comment holds only the commits its push added (--since with github.event.before, when that is an ancestor of the new head). When the pull request is opened or reopened, or after a force push, the comment holds every commit. Each push therefore gets its own comment (tagged by head, so a re-run updates it) instead of replacing the previous one. A push that adds only merge commits posts nothing. The comment is headed N commits · Full page, or after a push 1 new commit (7 total) · Full page, the total left out when it equals the count; the page is headed N commits.

Each commit is an open <details> block. Prose is escaped for Markdown; @name written outside backticks (e.g. @react.component, or a handle starting with a digit such as @0x) is drawn as code so it doesn't mention a user; fences are longer than any backtick run in their content, since fork pull requests' messages are untrusted. A comment holds at most 65536 characters: past a 60000 budget the largest commits drop their forms (pointing to the page), then trailing commits are left out.

scripts/recordMarkdown.js reuses the parser and alignment from recordRender.js (now exported, with the form pairing, prose chunking and column widths factored out so both renderers share them; the page's output is unchanged). commitRecords.js takes --markdown <file> --url <page>.

Co-authors (from Co-Authored-By: trailers) now sit on the identity line next to the author, on the page and in the comment, instead of a separate "with …" line closing each commit.

Records. The skill now requires a description in every commit, as a line or two of prose or a Why: section, and shows a small commit next to the full example. The parser keeps a Why:, Review: or Breaking: that wrapped prose runs onto as prose (no message of 2026 parses differently).

New tests: scripts/recordMarkdown.test.js, added to yarn test-commit-records; commitRecords.test.js gains tests for --since and for a section name wrapped into a paragraph.

Companion to #8957, which keeps merged pull requests' pages.

🤖 Generated with Claude Code

https://claude.ai/code/session_01AzPS5F8RDSGZ6dhfK6NdZp

The Semantic Diff workflow now comments each pull request's commit records
drawn as GitHub Markdown, with the page's link: code, trees, matrices,
mappings and reanalyze reports as unified diffs, typing rules as math.
Past a size budget the largest commits leave their forms to the page.

Area: ci docs
Changelog: none
Output: unchanged
Tests: +scripts/recordMarkdown.test.js
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AzPS5F8RDSGZ6dhfK6NdZp
Signed-off-by: Christoph Knittel <ck@cca.io>
@cknitt cknitt added the changelog:skip No release notes needed label Oct 22, 2026
@pkg-pr-new

pkg-pr-new Bot commented Oct 22, 2026 •

Copy link
Copy Markdown

Open in StackBlitz

rescript

npm i https://pkg.pr.new/rescript@8958

@rescript/belt

npm i https://pkg.pr.new/@rescript/belt@8958

@rescript/darwin-arm64

npm i https://pkg.pr.new/@rescript/darwin-arm64@8958

@rescript/linux-arm64

npm i https://pkg.pr.new/@rescript/linux-arm64@8958

@rescript/linux-x64

npm i https://pkg.pr.new/@rescript/linux-x64@8958

@rescript/runtime

npm i https://pkg.pr.new/@rescript/runtime@8958

@rescript/win32-x64

npm i https://pkg.pr.new/@rescript/win32-x64@8958

commit: 4b538de

@github-actions

Copy link
Copy Markdown

cknitt and others added 3 commits October 22, 2026 05:48
The "with …" line closing each commit moves next to the author, on the
page and in the comment.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AzPS5F8RDSGZ6dhfK6NdZp
Signed-off-by: Christoph Knittel <ck@cca.io>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AzPS5F8RDSGZ6dhfK6NdZp
Signed-off-by: Christoph Knittel <ck@cca.io>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AzPS5F8RDSGZ6dhfK6NdZp
Signed-off-by: Christoph Knittel <ck@cca.io>
@github-actions

Copy link
Copy Markdown

Semantic Diff

4 commits · Full page

Comment the semantic diff on the pull request as Markdown

de79800 · Christoph Knittel with Claude Opus 5.5 · Oct 22, 2026

The Semantic Diff workflow now comments each pull request's commit records drawn as GitHub Markdown, with the page's link: code, trees, matrices, mappings and reanalyze reports as unified diffs, typing rules as math. Past a size budget the largest commits leave their forms to the page.

Show co-authors on the identity line

902b201 · Christoph Knittel with Claude Opus 5.5 · Oct 22, 2026

The "with …" line closing each commit moves next to the author, on the page and in the comment.

Head the comment with the commit count and a link to the full page

9c54137 · Christoph Knittel with Claude Opus 5.5 · Oct 22, 2026

Head the page with the commit count alone

12a8468 · Christoph Knittel with Claude Opus 5.5 · Oct 22, 2026

After a push that keeps the previous head, the comment draws the commits
it added; after a force push, or when the pull request is opened, every
commit. Each push gets its own comment; the page still shows all commits.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AzPS5F8RDSGZ6dhfK6NdZp
Signed-off-by: Christoph Knittel <ck@cca.io>
@github-actions

Copy link
Copy Markdown

Semantic Diff

1 new commit · Full page

Comment only the commits a push added

fc685e1 · Christoph Knittel with Claude Opus 5.5 · Oct 22, 2026

After a push that keeps the previous head, the comment draws the commits it added; after a force push, or when the pull request is opened, every commit. Each push gets its own comment; the page still shows all commits.

@cknitt

cknitt commented Oct 22, 2026

Copy link
Copy Markdown
Member Author

Example: this is how the new comment renders a real commit with rich records: 798978d from #8905 (Pexp_spread), which shows a parse-tree diff, a typed tree added in After only, and a formatter diff. It's the comment the workflow posted on the test PR #8959, which puts #8905's commit on top of this branch. Below the line is the generated Markdown, unchanged.


Semantic Diff

1 commit · Full page

Represent array and list literals with spreads with a Pexp_spread node

798978d · Christoph Knittel with Claude Opus 5.5 · Oct 18, 2026

Why

The parser turned [a, ...b] and list{...a, b} into calls of Primitive_array.spread and Primitive_list.spread marked with res.spread, so the formatter had to rebuild the literal from the call and got it wrong: spreads of literals were flattened, attributes on the literal were dropped and an empty list spread printed as an empty element.

Pexp_spread keeps the items and spreads in source order, and the type checker gives it a Texp_spread node. Translation emits new Parray_spread and Plist_spread primitives that compile to the same runtime calls. A list literal whose only spread is its tail stays a chain of ::. The parsetree and CMT magic numbers are bumped.

AST modified (array literal with a spread)

let x = [1, ...ys]

parse

 expression
-  Pexp_apply
-  expression
-    attribute "res.spread"
-    Pexp_ident "Primitive_array.spread"
-    <arg>
-    Nolabel
+  Pexp_spread array
+    Pspread_item
       expression
-        Pexp_array
-          expression
-            Pexp_array
-              expression
-                Pexp_constant PConst_int (1,None)
-          expression
-            Pexp_ident "ys"
+        Pexp_constant PConst_int (1,None)
+    Pspread
+      expression
+        Pexp_ident "ys"

Typedtree added (Texp_spread)

let ys = [2]
let x = [1, ...ys]

typed · After

expression
  Texp_spread array
    expression
      Texp_array
        expression
          Texp_constant Const_int 1
    expression
      Texp_ident "ys/1001"

Format modified (literals with spreads)

let x = [...[1, 2], 3, ...[]]
let y = @attr list{...xs, ...list{}, 1}

rescript

-let x = [1, 2, 3, ]
-let y = list{...xs, , 1}
+let x = [...[1, 2], 3, ...[]]
+let y = @attr list{...xs, ...list{}, 1}

Review

  • Why do the generated item groups have ghost locations? The v0 encoding has no marker on them, and the ghost flag tells a group of items from an array or list literal that is spread. A call built by a PPX with real locations decodes to spreads only, which concatenates the same values.
  • Why does the typed node hold the concatenated parts rather than the elements? The parts are the arrays and cons chains the runtime call takes, so the items keep the errors of array and list literals and translation needs no list building of its own.

@cknitt

cknitt commented Oct 22, 2026

Copy link
Copy Markdown
Member Author

@codex review

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 22, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review 🔄 Running since 2026-10-22T08:22:30.258215Z 507e040 Manual request
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AzPS5F8RDSGZ6dhfK6NdZp
Signed-off-by: Christoph Knittel <ck@cca.io>
@github-actions

Copy link
Copy Markdown

Semantic Diff

1 new commit (6 total) · Full page

Count all commits next to the new ones in the comment

70798a2 · Christoph Knittel with Claude Opus 5.5 · Oct 22, 2026

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: fc685e124c

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread scripts/recordMarkdown.js Outdated
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AzPS5F8RDSGZ6dhfK6NdZp
Signed-off-by: Christoph Knittel <ck@cca.io>
@cknitt

cknitt commented Oct 22, 2026

Copy link
Copy Markdown
Member Author

@codex review

@github-actions

Copy link
Copy Markdown

Semantic Diff

1 new commit (7 total) · Full page

Draw handles starting with a digit as code in the comment

507e040 · Christoph Knittel with Claude Opus 5.5 · Oct 22, 2026

@github-actions

Copy link
Copy Markdown

Semantic Diff

1 new commit (8 total) · Full page

Require a description in every commit record

f652cdf · Christoph Knittel with Claude Opus 5.5 · Oct 22, 2026

The skill listed only the subject and Signed-off-by as required, and the expected line or two of prose sat under the object blocks' section, so a subject alone read as enough. It now requires a description, prose or a

Why

section, and shows a small commit next to the full example.

The skill listed only the subject and Signed-off-by as required, and the
expected line or two of prose sat under the object blocks' section, so a
subject alone read as enough. It now requires a description, as prose
or as a `Why:` section, and shows a small commit next to the full
example.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AzPS5F8RDSGZ6dhfK6NdZp
Signed-off-by: Christoph Knittel <ck@cca.io>
@cknitt
cknitt force-pushed the semantic-diff-markdown branch from f652cdf to 76c45d4 Compare October 22, 2026 08:39
@github-actions

Copy link
Copy Markdown

Semantic Diff

8 commits · Full page

Comment the semantic diff on the pull request as Markdown

de79800 · Christoph Knittel with Claude Opus 5.5 · Oct 22, 2026

The Semantic Diff workflow now comments each pull request's commit records drawn as GitHub Markdown, with the page's link: code, trees, matrices, mappings and reanalyze reports as unified diffs, typing rules as math. Past a size budget the largest commits leave their forms to the page.

Show co-authors on the identity line

902b201 · Christoph Knittel with Claude Opus 5.5 · Oct 22, 2026

The "with …" line closing each commit moves next to the author, on the page and in the comment.

Head the comment with the commit count and a link to the full page

9c54137 · Christoph Knittel with Claude Opus 5.5 · Oct 22, 2026

Head the page with the commit count alone

12a8468 · Christoph Knittel with Claude Opus 5.5 · Oct 22, 2026

Comment only the commits a push added

fc685e1 · Christoph Knittel with Claude Opus 5.5 · Oct 22, 2026

After a push that keeps the previous head, the comment draws the commits it added; after a force push, or when the pull request is opened, every commit. Each push gets its own comment; the page still shows all commits.

Count all commits next to the new ones in the comment

70798a2 · Christoph Knittel with Claude Opus 5.5 · Oct 22, 2026

Draw handles starting with a digit as code in the comment

507e040 · Christoph Knittel with Claude Opus 5.5 · Oct 22, 2026

Require a description in every commit record

76c45d4 · Christoph Knittel with Claude Opus 5.5 · Oct 22, 2026

The skill listed only the subject and Signed-off-by as required, and the expected line or two of prose sat under the object blocks' section, so a subject alone read as enough. It now requires a description, as prose or as a Why: section, and shows a small commit next to the full example.

A paragraph wrapped so that a line starts with `Why:`, `Review:` or
`Breaking:` was cut there into a section. Such a line now continues the
paragraph, and those sections start after a blank line or another
section; no message of this year parses differently.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AzPS5F8RDSGZ6dhfK6NdZp
Signed-off-by: Christoph Knittel <ck@cca.io>
@github-actions

Copy link
Copy Markdown

Semantic Diff

1 new commit (9 total) · Full page

Keep a section's name that prose wraps onto as prose

4b538de · Christoph Knittel with Claude Opus 5.5 · Oct 22, 2026

A paragraph wrapped so that a line starts with Why:, Review: or Breaking: was cut there into a section. Such a line now continues the paragraph, and those sections start after a blank line or another section; no message of this year parses differently.

@cknitt
cknitt marked this pull request as ready for review October 22, 2026 09:05
@cknitt
cknitt requested a review from cristianoc October 22, 2026 09:05

@cristianoc cristianoc left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we can tweak the PR info a little further but this is already great.

@cristianoc

Copy link
Copy Markdown
Collaborator

One opportunity we're missing is having an agent summarise rather than paste verbatim. Though not sure. That would require running an agent only for that in the cloud somewhere.
Unless, we have a skill for the PR description.

@cknitt

cknitt commented Oct 22, 2026

Copy link
Copy Markdown
Member Author

One opportunity we're missing is having an agent summarise rather than paste verbatim.

Yes, we can discuss/develop that further in scope of #8910.

@cknitt
cknitt merged commit 0326cb5 into master Oct 22, 2026
38 of 40 checks passed
@cknitt
cknitt deleted the semantic-diff-markdown branch October 22, 2026 09:42
cknitt added a commit that referenced this pull request Oct 22, 2026
A pull request's run takes the workflow from its merge into master but
checked out the renderer from the branch, so a branch made before #8958
passed --markdown to a commitRecords.js that took it for a revision. The
renderer now comes from the merge as well.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AzPS5F8RDSGZ6dhfK6NdZp
Signed-off-by: Christoph Knittel <ck@cca.io>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

changelog:skip No release notes needed

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants