AGENTS.md: adopt the commit-message standard - #1561
Conversation
`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
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
Deploying with
|
| 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
left a comment
There was a problem hiding this comment.
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 aChangelog: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 standardis 44 chars, 52 with(#1561),AGENTS.mdis one of the areas §8.5 lists, and the description carriesChangelog: noneimmediately before the trailer block. node bin/linkcheck.mjs— the broken-link set is byte-identical between this head and2df303a9(151 lines each,diffclean). The new#85-commit-messagesand#84-breaking-changes-and-versioninganchors both resolve:### 8.5 Commit messagesat AGENTS.md:1321 and### 8.4 Breaking changes and versioningat :1265.
One thing to fix: the release-tag boundary is off by one
The new §8.4 bullet says:
Releases through
0.44.0are 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 all — git 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 andBring 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 likeRemove unreachable throw in djs serializer's constSerialize (#1544)andAdd 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. |
- 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
left a comment
There was a problem hiding this comment.
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.0are untagged; leave them so.
Re-checked on this head:
package.json"version"is0.45.0, andchangelog/0.45.0/exists —0.45.0shipped in8804e783(0.45.0 (#1555)), onmainbefore 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.0and add an explicit retroactive step: tag8804e783asv0.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.mjson this head vsde959db7: identical broken-link sets, 129 entries on both — all pre-existing. The new anchors#85-commit-messagesand#84-breaking-changes-and-versioningresolve 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.mdandtodo/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.
|
Dropped the tag rule rather than fixing the boundary — The review's off-by-one was real (
Two consequences worth naming, since the tag range query had downstream readers:
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 On the two observations: both stand as forward-looking, and I left them alone. The 72-character cap and the 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 Generated by Claude Code |
o2alexanderfedin
left a comment
There was a problem hiding this comment.
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 tag→ 0 tags.git ls-remote --tags origin→ 0 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.json→0.45.0, shipped by8804e783("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 through0.44.0are the singlechangelog/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 messagesare 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 againstorigin/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 ("sayChangelog: nonein 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.0example 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.
maintakes one squash commit per PR, titledPR-title (#NNN)with the PRdescription 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 descriptiontitle within 72characters including the
(#NNN)GitHub appends, the mandatoryChangelog: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/, orChangelog: 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-changelogis linked fromAGENTS.md §2,
changelog/README.md, and several moduletodo/files, sorenumbering 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 PRthat 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 releasetags" as its range query, now reads the release commit's bare-version title.
todo/commit-message-standard.mdstays: 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.mdwas waiting on this adoption and nolonger 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