Skip to content

AGENTS.md: adopt the commit-message standard - #1561

Merged
sergey-shandar merged 5 commits into
mainfrom
claude/todo-changelog-directory-f47ma1
Aug 14, 2026
Merged

AGENTS.md: adopt the commit-message standard#1561
sergey-shandar merged 5 commits into
mainfrom
claude/todo-changelog-directory-f47ma1

Conversation

@sergey-shandar

@sergey-shandar sergey-shandar commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

main takes one squash commit per PR, titled PR-title (#NNN) with the PR
description as its body, so the title and description are the commit message.
A changelog generated from Git history could read nothing else, and the option
expires for every PR that merges before the format is fixed.

New §8.5 documents it: the topic: short description title within 72
characters including the (#NNN) GitHub appends, the mandatory Changelog:
section — the last section of the description before an optional trailer
block, holding the same list items as the PR's entry file in
changelog/unreleased/, or Changelog: none — and squash-merge-only landing.
§2 step 6 and CONTRIBUTING.md point at the new section.

§8.5 sits after §8.4 rather than in sequence: #83-changelog is linked from
AGENTS.md §2, changelog/README.md, and several module todo/ files, so
renumbering would rot all of them for no gain.

The proposal's release-tag step is not adopted: the repository has no Git
tags and is not going to get any. §8.4 records that instead of prescribing
tags — release membership is already in changelog/X.Y.Z/, one file per PR
that shipped in it, so a tag would be a second copy of that fact maintained by
hand. The todo keeps the tag section as a rejected design with the reasoning,
and changelog-from-git-history.md's design 1, which took "between release
tags" as its range query, now reads the release commit's bare-version title.

todo/commit-message-standard.md stays: the repository settings it asks for
(squash-only, default squash message "Pull request title and description",
branch protection) need admin rights and cannot land in a PR, and until they
are set §8.5 is a convention rather than a rule. Its format section is now
reasoning behind AGENTS.md rather than the normative text.
todo/commit-message-enforcement.md was waiting on this adoption and no
longer is.

This PR's own title and description follow the standard it adds. Note that
GitHub strips angle-bracket placeholders from a PR body even inside backticks,
so the prose above spells them out instead — worth knowing when writing a
Changelog: section that mentions a type or a generic.

Changelog: none

🤖 Generated with Claude Code

https://claude.ai/code/session_01WQFBgRCxeiy5gw1is28t2H

`main` takes one squash commit per PR, titled `<PR title> (#NNN)` with the PR
description as its body, so the title and description are the commit message.
A changelog generated from Git history could read nothing else, and the option
expires for every PR that merges before the format is fixed.

New §8.5 documents it: the `<topic>: <short description>` title within 72
characters including the ` (#NNN)` GitHub appends, the mandatory `Changelog:`
section — the last section of the description before an optional trailer
block, holding the same list items as `changelog/unreleased/<PR>.md`, or
`Changelog: none` — and squash-merge-only landing. §8.4 gains the `vX.Y.Z`
release tag, so "what shipped in this release" is a range between tags rather
than a heuristic over version-bump titles. §2 step 6 and CONTRIBUTING.md point
at the new section.

`todo/commit-message-standard.md` stays: the repository settings it asks for
(squash-only, default squash message, branch protection) need admin rights and
cannot land in a PR, and until they are set §8.5 is a convention rather than a
rule. Its format section is now reasoning behind AGENTS.md rather than the
normative text. `todo/commit-message-enforcement.md` was waiting on this
adoption and no longer is.

Changelog: none

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WQFBgRCxeiy5gw1is28t2H
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Preview URL Updated (UTC)
✅ Deployment successful!
View logs
functionalscript eafaf15 Commit Preview URL

Branch Preview URL
Aug 14 2026, 09:12 PM

@o2alexanderfedin o2alexanderfedin left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Reviewed at a57b7b1b805ec87b70878d1ee64af65d41fcdf3b, against origin/main at 2df303a9 (0.45.0 (#1555), #1557 and #1559 all merged since I last measured this material). Docs-only, so I ran the link check and re-derived every history claim rather than the code battery.

What I checked and what holds

The two corrections that #1557 needed both landed here, and I re-derived them against the current tree:

  • The trailer exemption is correct. §8.5 says the Changelog: section is "the last section before an optional trailer block (Co-Authored-By:, generated-with lines, session links)" rather than the earlier "body ends with a Changelog: section". That matters: 25 of the last 25 merged PRs end with such a trailer block, so the un-exempted wording would have been violated by essentially every PR in the series, including #1557's own description. The new wording is satisfied by all 25.
  • AGENTS.md does not repeat the claim that history already has this shape. That claim was the thing that did not survive checking (486 of 1803 first-parent commits lacked the (#NNN) suffix), and it is correctly absent from the normative text.
  • This PR self-applies: title AGENTS.md: adopt the commit-message standard is 44 chars, 52 with (#1561), AGENTS.md is one of the areas §8.5 lists, and the description carries Changelog: none immediately before the trailer block.
  • node bin/linkcheck.mjs — the broken-link set is byte-identical between this head and 2df303a9 (151 lines each, diff clean). The new #85-commit-messages and #84-breaking-changes-and-versioning anchors both resolve: ### 8.5 Commit messages at AGENTS.md:1321 and ### 8.4 Breaking changes and versioning at :1265.

One thing to fix: the release-tag boundary is off by one

The new §8.4 bullet says:

Releases through 0.44.0 are untagged; leave them so.

0.45.0 has already shipped. It is on main as 8804e783 0.45.0 (#1555), five first-parent commits back from the tip; package.json reads 0.45.0; changelog/0.45.0/ exists alongside 0.44.0.md. And the repo has no tags at allgit tag | wc -l is 0, so 0.45.0 is untagged too.

So as written, the rule "Tag the release commit vX.Y.Z once it lands on main" already applies to 0.45.0 and is already unsatisfied the moment this merges, while the sentence that is supposed to carve out the untagged past stops one release short of it. todo/commit-message-standard.md is stale for the same reason — it still reads - [ ] Tag v0.45.0 at the next release and each release after, but 0.45.0 is not the next release, it is the last one.

Reading "through 0.45.0", and v0.46.0 in the todo checklist, makes both true. (Or tag 0.45.0 in this PR and leave the text — but tagging is a push, not something a PR can do, which is presumably why the todo lists repository settings as the remaining maintainer-only work.)

Two observations, not objections

Both of these are the standard being forward-looking rather than descriptive, which is legitimate — I mention them only because #1557 carried the first as an observation and it is worth knowing the size of the change in practice.

  • The 72-character cap, now stated as a rule and now explicitly including the (#NNN) GitHub appends, is not met by recent history: 23 of the last 100 first-parent commits exceed it, 39 of the last 200, 220 of all 1805. The two newest substantive commits both fail — Bring effects/node/virtual to 100% coverage: 89.12% → 100% branch (#1559) at 75 and Bring djs/parser to 100% coverage: 94.05% → 100% branch (#1556) at 73.
  • The <topic>: <short description> title form is likewise new practice. Of the last 100 first-parent commits, 98 are non-release; 58 have no colon at all, and only 19 open with a module-path-or-area topic of the shape §8.5 describes. Titles like Remove unreachable throw in djs serializer's constSerialize (#1544) and Add RTTI serializable data form with canonical operations (#1539) are the recent norm.

I did not flag "main takes exactly one commit per PR" / "Nothing lands on main outside a PR" against the 15 merge commits and the direct-push 0.41.0, because todo/commit-message-standard.md already says plainly that until the repository settings land this is "a convention a maintainer can defeat with one click in the merge dialog or one git push."

The off-by-one is a one-word fix; everything else here checks out.

@sergey-shandar

Copy link
Copy Markdown
Contributor Author

Reviewed at a57b7b1b805ec87b70878d1ee64af65d41fcdf3b, against origin/main at 2df303a9 (0.45.0 (#1555), #1557 and #1559 all merged since I last measured this material). Docs-only, so I ran the link check and re-derived every history claim rather than the code battery.

What I checked and what holds

The two corrections that #1557 needed both landed here, and I re-derived them against the current tree:

  • The trailer exemption is correct. §8.5 says the Changelog: section is "the last section before an optional trailer block (Co-Authored-By:, generated-with lines, session links)" rather than the earlier "body ends with a Changelog: section". That matters: 25 of the last 25 merged PRs end with such a trailer block, so the un-exempted wording would have been violated by essentially every PR in the series, including todo: propose a standard for commit messages merged into main #1557's own description. The new wording is satisfied by all 25.
  • AGENTS.md does not repeat the claim that history already has this shape. That claim was the thing that did not survive checking (486 of 1803 first-parent commits lacked the (#NNN) suffix), and it is correctly absent from the normative text.
  • This PR self-applies: title AGENTS.md: adopt the commit-message standard is 44 chars, 52 with (#1561), AGENTS.md is one of the areas §8.5 lists, and the description carries Changelog: none immediately before the trailer block.
  • node bin/linkcheck.mjs — the broken-link set is byte-identical between this head and 2df303a9 (151 lines each, diff clean). The new #85-commit-messages and #84-breaking-changes-and-versioning anchors both resolve: ### 8.5 Commit messages at AGENTS.md:1321 and ### 8.4 Breaking changes and versioning at :1265.

One thing to fix: the release-tag boundary is off by one

The new §8.4 bullet says:

Releases through 0.44.0 are untagged; leave them so.

0.45.0 has already shipped. It is on main as 8804e783 0.45.0 (#1555), five first-parent commits back from the tip; package.json reads 0.45.0; changelog/0.45.0/ exists alongside 0.44.0.md. And the repo has no tags at allgit tag | wc -l is 0, so 0.45.0 is untagged too.

So as written, the rule "Tag the release commit vX.Y.Z once it lands on main" already applies to 0.45.0 and is already unsatisfied the moment this merges, while the sentence that is supposed to carve out the untagged past stops one release short of it. todo/commit-message-standard.md is stale for the same reason — it still reads - [ ] Tag v0.45.0 at the next release and each release after, but 0.45.0 is not the next release, it is the last one.

Reading "through 0.45.0", and v0.46.0 in the todo checklist, makes both true. (Or tag 0.45.0 in this PR and leave the text — but tagging is a push, not something a PR can do, which is presumably why the todo lists repository settings as the remaining maintainer-only work.)

Two observations, not objections

Both of these are the standard being forward-looking rather than descriptive, which is legitimate — I mention them only because #1557 carried the first as an observation and it is worth knowing the size of the change in practice.

  • The 72-character cap, now stated as a rule and now explicitly including the (#NNN) GitHub appends, is not met by recent history: 23 of the last 100 first-parent commits exceed it, 39 of the last 200, 220 of all 1805. The two newest substantive commits both fail — Bring effects/node/virtual to 100% coverage: 89.12% → 100% branch (#1559) at 75 and Bring djs/parser to 100% coverage: 94.05% → 100% branch (#1556) at 73.
  • The <topic>: <short description> title form is likewise new practice. Of the last 100 first-parent commits, 98 are non-release; 58 have no colon at all, and only 19 open with a module-path-or-area topic of the shape §8.5 describes. Titles like Remove unreachable throw in djs serializer's constSerialize (#1544) and Add RTTI serializable data form with canonical operations (#1539) are the recent norm.

I did not flag "main takes exactly one commit per PR" / "Nothing lands on main outside a PR" against the 15 merge commits and the direct-push 0.41.0, because todo/commit-message-standard.md already says plainly that until the repository settings land this is "a convention a maintainer can defeat with one click in the merge dialog or one git push."

The off-by-one is a one-word fix; everything else here checks out.

That's right, we don't have Git tags and don't plan to have them.

sergey-shandar pushed a commit that referenced this pull request Aug 14, 2026
- Correct the inbound-link inventory: name the four real files
  (CONTRIBUTING.md, docker/README.md, changelog/README.md,
  fjs/bnf/todo/669-bnf-matcher-shared-core.md), note the deep anchors
  gated on the §5 decision, and require a re-run once #1561 lands.
- Add a destination-map row for §8.5 Commit messages (in flight in
  #1561), pointing it at CONTRIBUTING.md.
- Make explicit that nested AGENTS.md auto-discovery is not load-bearing:
  the root briefs link to the scoped files directly; cite agents.md for
  the nested-file convention.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VQm9hHrWbGd9YBvSKgUjo4

@o2alexanderfedin o2alexanderfedin left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Re-reviewed at d38de23f against origin/main = de959db7 (types/nullable: derive map from match… (#1558)).

The head moved only by a merge from main: git diff a57b7b1b d38de23f is exactly #1558's content (changelog/unreleased/1558.md, fjs/types/nullable/*, the deleted map-from-match.md todo). AGENTS.md, CONTRIBUTING.md and both todo/ files are byte-identical to the previously reviewed head, so the one open finding is unchanged. I re-derived it against the current tree rather than assuming.

Still open — §8.4's tagging rule is off by one and is unsatisfiable at merge

The new bullet ends:

Releases through 0.44.0 are untagged; leave them so.

Re-checked on this head:

  • package.json "version" is 0.45.0, and changelog/0.45.0/ exists — 0.45.0 shipped in 8804e783 (0.45.0 (#1555)), on main before this branch's merge base.
  • git tag -l → 0 tags. git ls-remote --tags origin → empty. The repo has no tags at all.

So 0.45.0 is a released version that is neither covered by the exemption (it is past 0.44.0) nor tagged. The rule's own trigger — "Tag the release commit vX.Y.Z once it lands on main" — is written in the present-forward tense and gives no retroactive step, so nothing in §8.4 ever produces v0.45.0. The section is out of compliance with the repository the moment it merges, and stays that way until 0.46.0.

Note the contrast with the sibling sentence two bullets up — "Releases through 0.44.0 are single changelog/X.Y.Z.md files; leave them as they are" — which is true: 0.45.0 is a directory. The tag sentence copies that form but the boundary is one release behind reality.

Either wording fixes it:

  • Releases through 0.45.0 are untagged; leave them so. — matches the tree, and the next release is the first tagged one; or
  • keep 0.44.0 and add an explicit retroactive step: tag 8804e783 as v0.45.0.

The same off-by-one is in todo/commit-message-standard.md, which still reads - [ ] Tag v0.45.0 at the next release and each release after. 0.45.0 is not the next release, it is the current one — at the next release the version will be 0.46.0, so the checklist item names a tag the procedure it now points at will never create.

Verified, no objection

Docs-only, so I ran the docs battery only:

  • node bin/linkcheck.mjs on this head vs de959db7: identical broken-link sets, 129 entries on both — all pre-existing. The new anchors #85-commit-messages and #84-breaking-changes-and-versioning resolve to real headings (### 8.5 Commit messages, ### 8.4 Breaking changes and versioning).
  • §8.5's no PR link ([§8.3](#83-changelog)) is consistent with §8.3 as it stands today ("No links. The file name is the PR number…").
  • No changelog entry needed — AGENTS.md, CONTRIBUTING.md and todo/ are exactly the exemption in §8.3.
  • The #1557 corrections carried over intact from the last head: the trailer exemption in §8.5's Changelog: bullet is well-worded and holds for 25/25 recent merged PRs, and the false "history already has this shape" claim is absent from the normative text.

Unchanged observations from last round, not objections — both are about the cost of the new title rule, and both are fine as aspirational:

  • the 72-char cap including (#NNN) is exceeded by 23 of the last 100 first-parent commits, 39 of 200, and 220 of 1805;
  • the <topic>: title form is absent from 58 of the last 98 non-release titles.

Review found the tag bullet's "releases through 0.44.0 are untagged" boundary
off by one — 0.45.0 has shipped — and the answer is that the repository has no
tags and does not plan to have any.

AGENTS.md §8.4 now records that instead of prescribing tags: release
membership is already in changelog/X.Y.Z/, one file per PR that shipped, so a
tag would be a second hand-maintained copy of it. The todo's "Tag releases"
section is kept as a rejected design with the reasoning, and its task is
dropped. changelog-from-git-history.md's design 1 took "between release tags"
as its range query; it now reads the release commit's bare-version title.

Copy link
Copy Markdown
Contributor Author

Dropped the tag rule rather than fixing the boundary — 90bebdc.

The review's off-by-one was real (0.45.0 shipped in #1555, so "releases through 0.44.0 are untagged" stopped one release short), but "no tags, now or later" makes the whole bullet wrong rather than one word wrong. §8.4 now records the decision instead of prescribing tags:

The repository has no Git tags and is not going to get any. "Which entries shipped in this release" is answered by changelog/X.Y.Z/, which holds one file per PR that shipped in it; a tag would be a second copy of that fact, kept in step by hand.

Two consequences worth naming, since the tag range query had downstream readers:

  • todo/commit-message-standard.md keeps its "Tag releases" section as rejected, with the reasoning, so the next reader does not reopen it. Its task is gone; the repository settings remain the only open item there.
  • todo/changelog-from-git-history.md design 1 read "extracts trailers between release tags". That range query no longer exists, so it now takes the boundary from the release commit, whose title is the bare version under §8.5.

The PR description is updated too — under §8.5 it is the commit message, so leaving it claiming a tag rule would have landed that claim on main.

On the two observations: both stand as forward-looking, and I left them alone. The 72-character cap and the topic: short description form are new practice, not descriptions of history — 23 of the last 100 titles exceed the cap and 58 have no colon at all. That is the intended direction of a standard adopted before the enforcement in todo/commit-message-enforcement.md, and the trial time it asks for is exactly where those numbers get to move.

One thing the review could not have seen, found while writing this PR's own description: GitHub strips angle-bracket placeholders from a PR body, even inside backticks. The first version of this description posted with `<topic>: <short description>` rendered as `: `. That is a live hazard for §8.5, which makes the description a required carrier of the Changelog: section — an entry mentioning Tuple<N, T> would lose it silently. Say the word and I will add a line to §8.5 here, or file it against the linter in todo/commit-message-enforcement.md, which is the thing that could actually catch it.


Generated by Claude Code

@o2alexanderfedin o2alexanderfedin left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Approving. Reviewed at eafaf15e (previously commented at d38de23f), baseline origin/main = c3af487f.

My open finding is closed — and closed the better way

I had objected that §8.4's "Tag the release commit vX.Y.Z once it lands on main … Releases through 0.44.0 are untagged; leave them so" was unsatisfiable at merge: 0.45.0 had already shipped in 8804e783, the repo had no tags, and the rule's "once it lands on main" gave no retroactive step for the release that had already landed.

Rather than shifting the boundary to 0.45.0, the rule is withdrawn:

The repository has no Git tags and is not going to get any. "Which entries shipped in this release" is answered by changelog/X.Y.Z/, which holds one file per PR that shipped in it; a tag would be a second copy of that fact, kept in step by hand.

Re-derived against the tree rather than taken on the new wording (as I said I would):

  • git tag0 tags. git ls-remote --tags origin0 tags. So "has no Git tags" is a fact about this tree, not an aspiration, and there is nothing left to reconcile at merge — which is exactly what the old wording could not achieve.
  • Published version: package.json0.45.0, shipped by 8804e783 ("0.45.0 (#1555)", 2026-08-14). The withdrawal needs no version boundary at all, so the off-by-one cannot recur.
  • The justification checks out too: changelog/0.45.0/ is a directory in this tree (releases through 0.44.0 are the single changelog/0.44.0.md-style files, exactly as the neighbouring bullet says). So "changelog/X.Y.Z/ holds one file per PR that shipped in it" describes something that already exists rather than something promised.

The same off-by-one I flagged in todo/commit-message-standard.md ("Tag v0.45.0 at the next release") is gone: the task is deleted and the section is rewritten as "Tag releases — rejected", preserving the reasoning so the question is not reopened. todo/changelog-from-git-history.md design 1 no longer says "between release tags" but "between release commits (the repository has no tags and is not getting any, so the bare-version commit title is the boundary)", which agrees with 8804e783's bare-version title. todo/commit-message-enforcement.md's status is updated from "do not start until … adopted" to "the format is adopted", with the trial-time rationale kept.

I swept the tree for surviving tag references (git tag, release tag, vX.Y.Z, v0.4x.0): the only remaining hits are @import tags in unrelated prose and the three places above that now say tags are not used. No contradiction left.

Also checked

  • Anchors used by the new text resolve: ### 8.3 CHANGELOG, ### 8.4 Breaking changes and versioning, ### 8.5 Commit messages are at AGENTS.md:1222/1265/1321, matching #83-changelog, #84-breaking-changes-and-versioning, #85-commit-messages.
  • bin/linkcheck.mjs — broken-link sets compared line-by-line against origin/main: identical.
  • §8.5's "no PR link" for the Changelog: section agrees with §8.3's "no PR number or link inside the file". Step 6 of the checklist ("say Changelog: none in the description instead") agrees with §8.5's mandatory-section rule, and CONTRIBUTING.md's new paragraph restates the same three facts without diverging.
  • Docs-only (AGENTS.md, CONTRIBUTING.md, todo/), so no CHANGELOG entry is required and none is added — correct under §8.3.
  • The 0.45.0 example given for a release PR title matches the real commit title.

Previously settled, restated so nothing is left dangling

Both #1557 corrections are still intact at this head. The 72-character cap and the <topic>: frequency figures were observations from my earlier pass, not objections, and I am not raising them again.

Nothing outstanding.

@sergey-shandar
sergey-shandar added this pull request to the merge queue Aug 14, 2026
Merged via the queue into main with commit 0555e2c Aug 14, 2026
19 checks passed
@sergey-shandar
sergey-shandar deleted the claude/todo-changelog-directory-f47ma1 branch August 14, 2026 21:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants