docs(agents): a released-package bug fix takes a patch changeset, never none - #14789

Merged
os-zhuang merged 1 commit into
mainfrom
claude/issue-14647-bugfix-changeset-sentence
Sep 3, 2026
Merged

docs(agents): a released-package bug fix takes a patch changeset, never none#14789
os-zhuang merged 1 commit into
mainfrom
claude/issue-14647-bugfix-changeset-sentence

Conversation

@os-litant

Copy link
Copy Markdown
Collaborator

Fixes#14647

AGENTS.md:1117 told authors 「Pure bug fixes do not require a changeset.」 Every enforced text disagrees, so a bug fix in a released package that followed the sentence literally had no green path through Check Changeset.

Ruled scope (triage comment 5514271473, adopted verbatim)

One sentence, saying two things:

  1. a bug fix in a released package takes a patch changeset;
  2. skip-changeset is never the answer for a released-package bug fix — that label is for a diff that publishes nothing from any released package.

Nothing was widened or reinterpreted beyond that.

Before / after, verbatim

BeforeAGENTS.md:1116-1117:

3. **Add a changeset for feature work.** When the change is a feature or functional improvement, run `pnpm changeset`
(or add a `.changeset/*.md` entry) describing it before committing. Pure bug fixes do **not** require a changeset.

AfterAGENTS.md:1116-1119:

3. **Add a changeset for anything that publishes.** Feature, functional improvement or fix — run `pnpm changeset`
(or add a `.changeset/*.md` entry) describing it before committing. A bug fix in a released package takes a
**`patch`** changeset — never none, and ⛔ never `skip-changeset`: that label is for a diff that publishes
nothing from any released package.

The instruction that survived unchanged is the middle clause — run pnpm changeset, or add a .changeset/*.md entry, describing it before committing. Only the final sentence was replaced, and the item's lead was re-aimed from "feature work" to "anything that publishes", since that is now what the item says.

The two dates that settle the "predates the gate" reading

The triage's reading is confirmed, and by a wider margin than the card assumed. Read from full history — the container's checkout is shallow, and both probes bottom out at the horizon commit until it is unshallowed, which is a trap worth naming: git log -S on a shallow clone reports the horizon commit as the introduction of text that is in fact much older.

WhenCommitState of the changeset check
2026-05-3043625fbd6cThe sentence lands. The step emits ::warning:: only and cannot fail — a zero-changeset bug fix is green by construction.
2026-06-11a1251e4737The step becomes blocking: ::error:: plus exit 1.
2026-07-218ff9210947The step starts counting changesets added by the PR rather than globbing the whole .changeset directory. This is the form that actually reds a zero-changeset bug fix.

The 2026-07-21 commit is explicit about why the earlier form could not bite, in its own inline comment: in pre-release mode changeset version retains every consumed .md file, so "the directory is permanently non-empty and the gate can never go red".

So on the day the sentence was written it was true — nothing forced a changeset for anything. It did not become wrong by being mis-worded; it became wrong when enforcement arrived under it, twelve days later for blocking and seven weeks later for the counting form. That is a refinement of the triage's gloss, not a contradiction of it: the sentence is stale relative to a gate that post-dates it, and correcting it to "a patch changeset" is repair rather than a policy change. Reported to the dispatching seat as such.

The payment

AGENTS.md is at its line ceiling — ratchet row ['AGENTS.md', 1162] at scripts/pm/check-skill-line-ratchet.mjs:529, headroom 0 — so the correction is paid by a same-file deletion. Nothing was re-wrapped; both edits are whole-line splices.

Deleted: the eight-line ADR-0087 rationale paragraph at AGENTS.md:1136-1143, replaced by a one-line citation in the file's own established idiom (compare :15, :916, :1012 — "its header is the authority on detail").

Why it is a restatement: the paragraph is a paraphrase of scripts/check-adr-0087-registration.mjs's own failure output — the report() block at :2976-2996, which prints to the author at exactly the moment they hit the gate. That is strictly better placed than prose in an instruction file the author may never re-read.

Deleted clauseSurviving single site
the ADR-0087 gates pin ledger ↔ artifact synchronycheck-adr-0087-registration.mjs:2980-2981
the artifacts are a pure projection of the registry:2982-2983
an entry never written leaves everything consistent, every gate green:2983-2984
a removal shipped that way, caught only by a human comparing by eye:2984-2985
ledger entries are the sole channel reaching an upgrader (objectstack migrate meta, spec-changes.json, the upgrade guide):2987-2990
for a surface with no spec schema there is no tombstone or schema rejection either:2988-2990
roughly 1 declared-breaking change in 7 needs an entry, so not-required is the ordinary answer and costs one line:2992-2994
no-migration-prescription is refused when the body carries a FROM → TO prescription:227, and :2633, also emitted output

Eight of eight. The four marker spellings themselves are untouched — the fenced block immediately above the deleted paragraph still lists all four, and the sentence naming pnpm check:adr-0087-registration and its CI step is untouched too, so the citation's antecedent is two lines up.

Line arithmetic

Lines
AGENTS.md before1,162
correction, :1116-1117 becomes :1116-1119+2
payment, :1136-1143 becomes one line−7
after1,157
ceiling (ratchet row)1,162
headroom5

Every edited line is ≤ 120 bytes in UTF-8 — 115 / 110 / 112 / 37 for the correction and 110 for the citation, measured in bytes rather than characters because the em dash and ⛔ are three bytes each. The widest-table-row pin is untouched at 1,081 bytes, and check:pm-skill-id-lint's population is respected: the new text carries no issue or PR numbers.

Edit-landed-on-disk proof

MeasurementBeforeAfter
wc -l AGENTS.md1,1621,157
grep -c 'Pure bug fixes do'10
grep -c 'sole channel that reaches an upgrader'10
grep -c 'skip-changeset'01
grep -c 'released package takes a'01
grep -c 'that output is the authority'01

git diff --stat: 1 file changed, 5 insertions, 10 deletions.

Gates — head 796501faa9

The union was re-derived after the last edit with node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands. It reported the list derived from this repo at 796501faa9, change set against merge base dee4dd4ba — one path, AGENTS.md. Every exit code was captured by redirect before any pipe.

CommandExitVerdict line
pnpm check:pm-skill-ratchet0✓ check-skill-line-ratchet: AGENTS.md is 1157 lines (ceiling 1162; headroom 5). and ✓ … AGENTS.md: widest table row is 1081 bytes (pin 1081; headroom 0).
pnpm check:pm-skill-ratchet --self-test0✓ check-skill-line-ratchet self-test: 111 cases pass.
pnpm check:pm-skill-id-lint0✓ check-skill-id-lint: 23 file(s) clean (pattern /#[0-9]{3,}/g).
pnpm check:pm-governed-prose0✓ check-governed-prose: 2 instruction surface(s) name all 5 registered governed surfaces … and claim no others.
pnpm check:nul-bytes0check-nul-bytes: OK (scanned 8063 text file(s) … no raw ASCII control bytes).
pnpm check:corpus-claim-drift0check-corpus-claim-drift: OK, no new claim sites beside a pinned spelling.
node scripts/check-required-contexts.mjs0✓ check-required-contexts: 6 required context name(s) pinned across 2 workflow(s) …
pnpm check:required-contexts0✓ check-required-contexts --self-test: 150 assertions …
pnpm check:agent-test-spelling0✓ check-agent-test-spelling: 0 violations — 430 file(s) …
pnpm check:docs-audit-scope0✓ docs-accuracy-audit scope is in sync with content/docs/: 190 hand-written doc(s) …
pnpm check:pm-governed-merges0✓ check-governed-merges --self-test: 243 assertions …

The baseline ratchet verdict before the edit, for comparison: ✓ check-skill-line-ratchet: AGENTS.md is 1162 lines (ceiling 1162; headroom 0). No gate answered a "PREREQUISITE NOT MET" or exit 3, so none is recorded NOT MEASURED. The derivation also noted nine further families that would apply once a changeset file exists — this PR deliberately has none, see below.

eslint

Not a narrowing — a measurement that the intersection is empty.

  • Population, read from eslint.config.mjs itself: every files: glob is **/*.{ts,tsx,mts,cts,js,jsx,mjs,cjs} or a narrowing of it. There is no .md or .mdx glob and no markdown processor or plugin anywhere in the config.
  • --format json reading for AGENTS.md:errorCount: 0, fatalErrorCount: 0, and the single message is "File ignored because no matching configuration was supplied."
  • Invariance: the diff touches exactly one file and that file is outside eslint's population by extension. No type-aware linting is in play for it, so this diff cannot move a lint verdict on any untouched file.

Changeset

skip-changeset applied. This diff publishes nothing from any released package: it touches exactly one file, AGENTS.md, a repo-root instruction surface that no package files list ships and that changeset version never bumps. Against scripts/check-empty-changeset.mjs's own enumeration, the alternative — an empty-frontmatter changeset — is precisely what that gate exists to reject: it "buys nothing the label does not, and uniquely carries the risk", being a real input to changesets/action that can stall a release while the run still goes green.

Merge path

Draft, and it stays draft — governed AGENTS.md, human merge is the review record. Auto-merge is not enabled and no reviewers were requested; requesting review is the dispatching seat's step.


Generated by Claude Code

…er none
AGENTS.md told authors "Pure bug fixes do not require a changeset", which
contradicts every enforced text: Check Changeset (pr-automation.yml) reds a PR
that adds zero changesets and carries no skip-changeset label, and that label
is for a diff publishing nothing from any released package. A bug fix in a
released package therefore had no green path if it followed the sentence.
The sentence predates enforcement. It landed 2026-05-30 (43625fb) when the
step only emitted ::warning:: and could not fail; the check became blocking on
2026-06-11 (a1251e4), and started counting changesets added BY THE PR on
2026-07-21 (8ff9210) -- the form that actually reds a zero-changeset bug fix.
Paid same-file, AGENTS.md being at its line ceiling: the ADR-0087 rationale
paragraph is re-derived from check-adr-0087-registration.mjs's own failure
output, so it collapses to a one-line citation in the file's established idiom.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationsize/sskip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

3 participants

@os-litant@os-zhuang@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

docs(agents): a released-package bug fix takes a patch changeset, never none - #14789

Merged
os-zhuang merged 1 commit into
mainfrom
claude/issue-14647-bugfix-changeset-sentence
Sep 3, 2026
Merged

docs(agents): a released-package bug fix takes a patch changeset, never none#14789
os-zhuang merged 1 commit into
mainfrom
claude/issue-14647-bugfix-changeset-sentence

Conversation

@os-litant

Copy link
Copy Markdown
Collaborator

Fixes#14647

AGENTS.md:1117 told authors 「Pure bug fixes do not require a changeset.」 Every enforced text disagrees, so a bug fix in a released package that followed the sentence literally had no green path through Check Changeset.

Ruled scope (triage comment 5514271473, adopted verbatim)

One sentence, saying two things:

  1. a bug fix in a released package takes a patch changeset;
  2. skip-changeset is never the answer for a released-package bug fix — that label is for a diff that publishes nothing from any released package.

Nothing was widened or reinterpreted beyond that.

Before / after, verbatim

BeforeAGENTS.md:1116-1117:

3. **Add a changeset for feature work.** When the change is a feature or functional improvement, run `pnpm changeset`
(or add a `.changeset/*.md` entry) describing it before committing. Pure bug fixes do **not** require a changeset.

AfterAGENTS.md:1116-1119:

3. **Add a changeset for anything that publishes.** Feature, functional improvement or fix — run `pnpm changeset`
(or add a `.changeset/*.md` entry) describing it before committing. A bug fix in a released package takes a
**`patch`** changeset — never none, and ⛔ never `skip-changeset`: that label is for a diff that publishes
nothing from any released package.

The instruction that survived unchanged is the middle clause — run pnpm changeset, or add a .changeset/*.md entry, describing it before committing. Only the final sentence was replaced, and the item's lead was re-aimed from "feature work" to "anything that publishes", since that is now what the item says.

The two dates that settle the "predates the gate" reading

The triage's reading is confirmed, and by a wider margin than the card assumed. Read from full history — the container's checkout is shallow, and both probes bottom out at the horizon commit until it is unshallowed, which is a trap worth naming: git log -S on a shallow clone reports the horizon commit as the introduction of text that is in fact much older.

WhenCommitState of the changeset check
2026-05-3043625fbd6cThe sentence lands. The step emits ::warning:: only and cannot fail — a zero-changeset bug fix is green by construction.
2026-06-11a1251e4737The step becomes blocking: ::error:: plus exit 1.
2026-07-218ff9210947The step starts counting changesets added by the PR rather than globbing the whole .changeset directory. This is the form that actually reds a zero-changeset bug fix.

The 2026-07-21 commit is explicit about why the earlier form could not bite, in its own inline comment: in pre-release mode changeset version retains every consumed .md file, so "the directory is permanently non-empty and the gate can never go red".

So on the day the sentence was written it was true — nothing forced a changeset for anything. It did not become wrong by being mis-worded; it became wrong when enforcement arrived under it, twelve days later for blocking and seven weeks later for the counting form. That is a refinement of the triage's gloss, not a contradiction of it: the sentence is stale relative to a gate that post-dates it, and correcting it to "a patch changeset" is repair rather than a policy change. Reported to the dispatching seat as such.

The payment

AGENTS.md is at its line ceiling — ratchet row ['AGENTS.md', 1162] at scripts/pm/check-skill-line-ratchet.mjs:529, headroom 0 — so the correction is paid by a same-file deletion. Nothing was re-wrapped; both edits are whole-line splices.

Deleted: the eight-line ADR-0087 rationale paragraph at AGENTS.md:1136-1143, replaced by a one-line citation in the file's own established idiom (compare :15, :916, :1012 — "its header is the authority on detail").

Why it is a restatement: the paragraph is a paraphrase of scripts/check-adr-0087-registration.mjs's own failure output — the report() block at :2976-2996, which prints to the author at exactly the moment they hit the gate. That is strictly better placed than prose in an instruction file the author may never re-read.

Deleted clauseSurviving single site
the ADR-0087 gates pin ledger ↔ artifact synchronycheck-adr-0087-registration.mjs:2980-2981
the artifacts are a pure projection of the registry:2982-2983
an entry never written leaves everything consistent, every gate green:2983-2984
a removal shipped that way, caught only by a human comparing by eye:2984-2985
ledger entries are the sole channel reaching an upgrader (objectstack migrate meta, spec-changes.json, the upgrade guide):2987-2990
for a surface with no spec schema there is no tombstone or schema rejection either:2988-2990
roughly 1 declared-breaking change in 7 needs an entry, so not-required is the ordinary answer and costs one line:2992-2994
no-migration-prescription is refused when the body carries a FROM → TO prescription:227, and :2633, also emitted output

Eight of eight. The four marker spellings themselves are untouched — the fenced block immediately above the deleted paragraph still lists all four, and the sentence naming pnpm check:adr-0087-registration and its CI step is untouched too, so the citation's antecedent is two lines up.

Line arithmetic

Lines
AGENTS.md before1,162
correction, :1116-1117 becomes :1116-1119+2
payment, :1136-1143 becomes one line−7
after1,157
ceiling (ratchet row)1,162
headroom5

Every edited line is ≤ 120 bytes in UTF-8 — 115 / 110 / 112 / 37 for the correction and 110 for the citation, measured in bytes rather than characters because the em dash and ⛔ are three bytes each. The widest-table-row pin is untouched at 1,081 bytes, and check:pm-skill-id-lint's population is respected: the new text carries no issue or PR numbers.

Edit-landed-on-disk proof

MeasurementBeforeAfter
wc -l AGENTS.md1,1621,157
grep -c 'Pure bug fixes do'10
grep -c 'sole channel that reaches an upgrader'10
grep -c 'skip-changeset'01
grep -c 'released package takes a'01
grep -c 'that output is the authority'01

git diff --stat: 1 file changed, 5 insertions, 10 deletions.

Gates — head 796501faa9

The union was re-derived after the last edit with node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands. It reported the list derived from this repo at 796501faa9, change set against merge base dee4dd4ba — one path, AGENTS.md. Every exit code was captured by redirect before any pipe.

CommandExitVerdict line
pnpm check:pm-skill-ratchet0✓ check-skill-line-ratchet: AGENTS.md is 1157 lines (ceiling 1162; headroom 5). and ✓ … AGENTS.md: widest table row is 1081 bytes (pin 1081; headroom 0).
pnpm check:pm-skill-ratchet --self-test0✓ check-skill-line-ratchet self-test: 111 cases pass.
pnpm check:pm-skill-id-lint0✓ check-skill-id-lint: 23 file(s) clean (pattern /#[0-9]{3,}/g).
pnpm check:pm-governed-prose0✓ check-governed-prose: 2 instruction surface(s) name all 5 registered governed surfaces … and claim no others.
pnpm check:nul-bytes0check-nul-bytes: OK (scanned 8063 text file(s) … no raw ASCII control bytes).
pnpm check:corpus-claim-drift0check-corpus-claim-drift: OK, no new claim sites beside a pinned spelling.
node scripts/check-required-contexts.mjs0✓ check-required-contexts: 6 required context name(s) pinned across 2 workflow(s) …
pnpm check:required-contexts0✓ check-required-contexts --self-test: 150 assertions …
pnpm check:agent-test-spelling0✓ check-agent-test-spelling: 0 violations — 430 file(s) …
pnpm check:docs-audit-scope0✓ docs-accuracy-audit scope is in sync with content/docs/: 190 hand-written doc(s) …
pnpm check:pm-governed-merges0✓ check-governed-merges --self-test: 243 assertions …

The baseline ratchet verdict before the edit, for comparison: ✓ check-skill-line-ratchet: AGENTS.md is 1162 lines (ceiling 1162; headroom 0). No gate answered a "PREREQUISITE NOT MET" or exit 3, so none is recorded NOT MEASURED. The derivation also noted nine further families that would apply once a changeset file exists — this PR deliberately has none, see below.

eslint

Not a narrowing — a measurement that the intersection is empty.

  • Population, read from eslint.config.mjs itself: every files: glob is **/*.{ts,tsx,mts,cts,js,jsx,mjs,cjs} or a narrowing of it. There is no .md or .mdx glob and no markdown processor or plugin anywhere in the config.
  • --format json reading for AGENTS.md:errorCount: 0, fatalErrorCount: 0, and the single message is "File ignored because no matching configuration was supplied."
  • Invariance: the diff touches exactly one file and that file is outside eslint's population by extension. No type-aware linting is in play for it, so this diff cannot move a lint verdict on any untouched file.

Changeset

skip-changeset applied. This diff publishes nothing from any released package: it touches exactly one file, AGENTS.md, a repo-root instruction surface that no package files list ships and that changeset version never bumps. Against scripts/check-empty-changeset.mjs's own enumeration, the alternative — an empty-frontmatter changeset — is precisely what that gate exists to reject: it "buys nothing the label does not, and uniquely carries the risk", being a real input to changesets/action that can stall a release while the run still goes green.

Merge path

Draft, and it stays draft — governed AGENTS.md, human merge is the review record. Auto-merge is not enabled and no reviewers were requested; requesting review is the dispatching seat's step.


Generated by Claude Code

…er none
AGENTS.md told authors "Pure bug fixes do not require a changeset", which
contradicts every enforced text: Check Changeset (pr-automation.yml) reds a PR
that adds zero changesets and carries no skip-changeset label, and that label
is for a diff publishing nothing from any released package. A bug fix in a
released package therefore had no green path if it followed the sentence.
The sentence predates enforcement. It landed 2026-05-30 (43625fb) when the
step only emitted ::warning:: and could not fail; the check became blocking on
2026-06-11 (a1251e4), and started counting changesets added BY THE PR on
2026-07-21 (8ff9210) -- the form that actually reds a zero-changeset bug fix.
Paid same-file, AGENTS.md being at its line ceiling: the ADR-0087 rationale
paragraph is re-derived from check-adr-0087-registration.mjs's own failure
output, so it collapses to a one-line citation in the file's established idiom.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationsize/sskip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

3 participants

@os-litant@os-zhuang@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

docs(agents): a released-package bug fix takes a patch changeset, never none - #14789

Merged
os-zhuang merged 1 commit into
mainfrom
claude/issue-14647-bugfix-changeset-sentence
Sep 3, 2026
Merged

docs(agents): a released-package bug fix takes a patch changeset, never none#14789
os-zhuang merged 1 commit into
mainfrom
claude/issue-14647-bugfix-changeset-sentence

Conversation

@os-litant

Copy link
Copy Markdown
Collaborator

Fixes#14647

AGENTS.md:1117 told authors 「Pure bug fixes do not require a changeset.」 Every enforced text disagrees, so a bug fix in a released package that followed the sentence literally had no green path through Check Changeset.

Ruled scope (triage comment 5514271473, adopted verbatim)

One sentence, saying two things:

  1. a bug fix in a released package takes a patch changeset;
  2. skip-changeset is never the answer for a released-package bug fix — that label is for a diff that publishes nothing from any released package.

Nothing was widened or reinterpreted beyond that.

Before / after, verbatim

BeforeAGENTS.md:1116-1117:

3. **Add a changeset for feature work.** When the change is a feature or functional improvement, run `pnpm changeset`
(or add a `.changeset/*.md` entry) describing it before committing. Pure bug fixes do **not** require a changeset.

AfterAGENTS.md:1116-1119:

3. **Add a changeset for anything that publishes.** Feature, functional improvement or fix — run `pnpm changeset`
(or add a `.changeset/*.md` entry) describing it before committing. A bug fix in a released package takes a
**`patch`** changeset — never none, and ⛔ never `skip-changeset`: that label is for a diff that publishes
nothing from any released package.

The instruction that survived unchanged is the middle clause — run pnpm changeset, or add a .changeset/*.md entry, describing it before committing. Only the final sentence was replaced, and the item's lead was re-aimed from "feature work" to "anything that publishes", since that is now what the item says.

The two dates that settle the "predates the gate" reading

The triage's reading is confirmed, and by a wider margin than the card assumed. Read from full history — the container's checkout is shallow, and both probes bottom out at the horizon commit until it is unshallowed, which is a trap worth naming: git log -S on a shallow clone reports the horizon commit as the introduction of text that is in fact much older.

WhenCommitState of the changeset check
2026-05-3043625fbd6cThe sentence lands. The step emits ::warning:: only and cannot fail — a zero-changeset bug fix is green by construction.
2026-06-11a1251e4737The step becomes blocking: ::error:: plus exit 1.
2026-07-218ff9210947The step starts counting changesets added by the PR rather than globbing the whole .changeset directory. This is the form that actually reds a zero-changeset bug fix.

The 2026-07-21 commit is explicit about why the earlier form could not bite, in its own inline comment: in pre-release mode changeset version retains every consumed .md file, so "the directory is permanently non-empty and the gate can never go red".

So on the day the sentence was written it was true — nothing forced a changeset for anything. It did not become wrong by being mis-worded; it became wrong when enforcement arrived under it, twelve days later for blocking and seven weeks later for the counting form. That is a refinement of the triage's gloss, not a contradiction of it: the sentence is stale relative to a gate that post-dates it, and correcting it to "a patch changeset" is repair rather than a policy change. Reported to the dispatching seat as such.

The payment

AGENTS.md is at its line ceiling — ratchet row ['AGENTS.md', 1162] at scripts/pm/check-skill-line-ratchet.mjs:529, headroom 0 — so the correction is paid by a same-file deletion. Nothing was re-wrapped; both edits are whole-line splices.

Deleted: the eight-line ADR-0087 rationale paragraph at AGENTS.md:1136-1143, replaced by a one-line citation in the file's own established idiom (compare :15, :916, :1012 — "its header is the authority on detail").

Why it is a restatement: the paragraph is a paraphrase of scripts/check-adr-0087-registration.mjs's own failure output — the report() block at :2976-2996, which prints to the author at exactly the moment they hit the gate. That is strictly better placed than prose in an instruction file the author may never re-read.

Deleted clauseSurviving single site
the ADR-0087 gates pin ledger ↔ artifact synchronycheck-adr-0087-registration.mjs:2980-2981
the artifacts are a pure projection of the registry:2982-2983
an entry never written leaves everything consistent, every gate green:2983-2984
a removal shipped that way, caught only by a human comparing by eye:2984-2985
ledger entries are the sole channel reaching an upgrader (objectstack migrate meta, spec-changes.json, the upgrade guide):2987-2990
for a surface with no spec schema there is no tombstone or schema rejection either:2988-2990
roughly 1 declared-breaking change in 7 needs an entry, so not-required is the ordinary answer and costs one line:2992-2994
no-migration-prescription is refused when the body carries a FROM → TO prescription:227, and :2633, also emitted output

Eight of eight. The four marker spellings themselves are untouched — the fenced block immediately above the deleted paragraph still lists all four, and the sentence naming pnpm check:adr-0087-registration and its CI step is untouched too, so the citation's antecedent is two lines up.

Line arithmetic

Lines
AGENTS.md before1,162
correction, :1116-1117 becomes :1116-1119+2
payment, :1136-1143 becomes one line−7
after1,157
ceiling (ratchet row)1,162
headroom5

Every edited line is ≤ 120 bytes in UTF-8 — 115 / 110 / 112 / 37 for the correction and 110 for the citation, measured in bytes rather than characters because the em dash and ⛔ are three bytes each. The widest-table-row pin is untouched at 1,081 bytes, and check:pm-skill-id-lint's population is respected: the new text carries no issue or PR numbers.

Edit-landed-on-disk proof

MeasurementBeforeAfter
wc -l AGENTS.md1,1621,157
grep -c 'Pure bug fixes do'10
grep -c 'sole channel that reaches an upgrader'10
grep -c 'skip-changeset'01
grep -c 'released package takes a'01
grep -c 'that output is the authority'01

git diff --stat: 1 file changed, 5 insertions, 10 deletions.

Gates — head 796501faa9

The union was re-derived after the last edit with node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands. It reported the list derived from this repo at 796501faa9, change set against merge base dee4dd4ba — one path, AGENTS.md. Every exit code was captured by redirect before any pipe.

CommandExitVerdict line
pnpm check:pm-skill-ratchet0✓ check-skill-line-ratchet: AGENTS.md is 1157 lines (ceiling 1162; headroom 5). and ✓ … AGENTS.md: widest table row is 1081 bytes (pin 1081; headroom 0).
pnpm check:pm-skill-ratchet --self-test0✓ check-skill-line-ratchet self-test: 111 cases pass.
pnpm check:pm-skill-id-lint0✓ check-skill-id-lint: 23 file(s) clean (pattern /#[0-9]{3,}/g).
pnpm check:pm-governed-prose0✓ check-governed-prose: 2 instruction surface(s) name all 5 registered governed surfaces … and claim no others.
pnpm check:nul-bytes0check-nul-bytes: OK (scanned 8063 text file(s) … no raw ASCII control bytes).
pnpm check:corpus-claim-drift0check-corpus-claim-drift: OK, no new claim sites beside a pinned spelling.
node scripts/check-required-contexts.mjs0✓ check-required-contexts: 6 required context name(s) pinned across 2 workflow(s) …
pnpm check:required-contexts0✓ check-required-contexts --self-test: 150 assertions …
pnpm check:agent-test-spelling0✓ check-agent-test-spelling: 0 violations — 430 file(s) …
pnpm check:docs-audit-scope0✓ docs-accuracy-audit scope is in sync with content/docs/: 190 hand-written doc(s) …
pnpm check:pm-governed-merges0✓ check-governed-merges --self-test: 243 assertions …

The baseline ratchet verdict before the edit, for comparison: ✓ check-skill-line-ratchet: AGENTS.md is 1162 lines (ceiling 1162; headroom 0). No gate answered a "PREREQUISITE NOT MET" or exit 3, so none is recorded NOT MEASURED. The derivation also noted nine further families that would apply once a changeset file exists — this PR deliberately has none, see below.

eslint

Not a narrowing — a measurement that the intersection is empty.

  • Population, read from eslint.config.mjs itself: every files: glob is **/*.{ts,tsx,mts,cts,js,jsx,mjs,cjs} or a narrowing of it. There is no .md or .mdx glob and no markdown processor or plugin anywhere in the config.
  • --format json reading for AGENTS.md:errorCount: 0, fatalErrorCount: 0, and the single message is "File ignored because no matching configuration was supplied."
  • Invariance: the diff touches exactly one file and that file is outside eslint's population by extension. No type-aware linting is in play for it, so this diff cannot move a lint verdict on any untouched file.

Changeset

skip-changeset applied. This diff publishes nothing from any released package: it touches exactly one file, AGENTS.md, a repo-root instruction surface that no package files list ships and that changeset version never bumps. Against scripts/check-empty-changeset.mjs's own enumeration, the alternative — an empty-frontmatter changeset — is precisely what that gate exists to reject: it "buys nothing the label does not, and uniquely carries the risk", being a real input to changesets/action that can stall a release while the run still goes green.

Merge path

Draft, and it stays draft — governed AGENTS.md, human merge is the review record. Auto-merge is not enabled and no reviewers were requested; requesting review is the dispatching seat's step.


Generated by Claude Code

…er none
AGENTS.md told authors "Pure bug fixes do not require a changeset", which
contradicts every enforced text: Check Changeset (pr-automation.yml) reds a PR
that adds zero changesets and carries no skip-changeset label, and that label
is for a diff publishing nothing from any released package. A bug fix in a
released package therefore had no green path if it followed the sentence.
The sentence predates enforcement. It landed 2026-05-30 (43625fb) when the
step only emitted ::warning:: and could not fail; the check became blocking on
2026-06-11 (a1251e4), and started counting changesets added BY THE PR on
2026-07-21 (8ff9210) -- the form that actually reds a zero-changeset bug fix.
Paid same-file, AGENTS.md being at its line ceiling: the ADR-0087 rationale
paragraph is re-derived from check-adr-0087-registration.mjs's own failure
output, so it collapses to a one-line citation in the file's established idiom.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationsize/sskip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

3 participants

@os-litant@os-zhuang@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

docs(agents): a released-package bug fix takes a patch changeset, never none - #14789

Merged
os-zhuang merged 1 commit into
mainfrom
claude/issue-14647-bugfix-changeset-sentence
Sep 3, 2026
Merged

docs(agents): a released-package bug fix takes a patch changeset, never none#14789
os-zhuang merged 1 commit into
mainfrom
claude/issue-14647-bugfix-changeset-sentence

Conversation

@os-litant

Copy link
Copy Markdown
Collaborator

Fixes#14647

AGENTS.md:1117 told authors 「Pure bug fixes do not require a changeset.」 Every enforced text disagrees, so a bug fix in a released package that followed the sentence literally had no green path through Check Changeset.

Ruled scope (triage comment 5514271473, adopted verbatim)

One sentence, saying two things:

  1. a bug fix in a released package takes a patch changeset;
  2. skip-changeset is never the answer for a released-package bug fix — that label is for a diff that publishes nothing from any released package.

Nothing was widened or reinterpreted beyond that.

Before / after, verbatim

BeforeAGENTS.md:1116-1117:

3. **Add a changeset for feature work.** When the change is a feature or functional improvement, run `pnpm changeset`
(or add a `.changeset/*.md` entry) describing it before committing. Pure bug fixes do **not** require a changeset.

AfterAGENTS.md:1116-1119:

3. **Add a changeset for anything that publishes.** Feature, functional improvement or fix — run `pnpm changeset`
(or add a `.changeset/*.md` entry) describing it before committing. A bug fix in a released package takes a
**`patch`** changeset — never none, and ⛔ never `skip-changeset`: that label is for a diff that publishes
nothing from any released package.

The instruction that survived unchanged is the middle clause — run pnpm changeset, or add a .changeset/*.md entry, describing it before committing. Only the final sentence was replaced, and the item's lead was re-aimed from "feature work" to "anything that publishes", since that is now what the item says.

The two dates that settle the "predates the gate" reading

The triage's reading is confirmed, and by a wider margin than the card assumed. Read from full history — the container's checkout is shallow, and both probes bottom out at the horizon commit until it is unshallowed, which is a trap worth naming: git log -S on a shallow clone reports the horizon commit as the introduction of text that is in fact much older.

WhenCommitState of the changeset check
2026-05-3043625fbd6cThe sentence lands. The step emits ::warning:: only and cannot fail — a zero-changeset bug fix is green by construction.
2026-06-11a1251e4737The step becomes blocking: ::error:: plus exit 1.
2026-07-218ff9210947The step starts counting changesets added by the PR rather than globbing the whole .changeset directory. This is the form that actually reds a zero-changeset bug fix.

The 2026-07-21 commit is explicit about why the earlier form could not bite, in its own inline comment: in pre-release mode changeset version retains every consumed .md file, so "the directory is permanently non-empty and the gate can never go red".

So on the day the sentence was written it was true — nothing forced a changeset for anything. It did not become wrong by being mis-worded; it became wrong when enforcement arrived under it, twelve days later for blocking and seven weeks later for the counting form. That is a refinement of the triage's gloss, not a contradiction of it: the sentence is stale relative to a gate that post-dates it, and correcting it to "a patch changeset" is repair rather than a policy change. Reported to the dispatching seat as such.

The payment

AGENTS.md is at its line ceiling — ratchet row ['AGENTS.md', 1162] at scripts/pm/check-skill-line-ratchet.mjs:529, headroom 0 — so the correction is paid by a same-file deletion. Nothing was re-wrapped; both edits are whole-line splices.

Deleted: the eight-line ADR-0087 rationale paragraph at AGENTS.md:1136-1143, replaced by a one-line citation in the file's own established idiom (compare :15, :916, :1012 — "its header is the authority on detail").

Why it is a restatement: the paragraph is a paraphrase of scripts/check-adr-0087-registration.mjs's own failure output — the report() block at :2976-2996, which prints to the author at exactly the moment they hit the gate. That is strictly better placed than prose in an instruction file the author may never re-read.

Deleted clauseSurviving single site
the ADR-0087 gates pin ledger ↔ artifact synchronycheck-adr-0087-registration.mjs:2980-2981
the artifacts are a pure projection of the registry:2982-2983
an entry never written leaves everything consistent, every gate green:2983-2984
a removal shipped that way, caught only by a human comparing by eye:2984-2985
ledger entries are the sole channel reaching an upgrader (objectstack migrate meta, spec-changes.json, the upgrade guide):2987-2990
for a surface with no spec schema there is no tombstone or schema rejection either:2988-2990
roughly 1 declared-breaking change in 7 needs an entry, so not-required is the ordinary answer and costs one line:2992-2994
no-migration-prescription is refused when the body carries a FROM → TO prescription:227, and :2633, also emitted output

Eight of eight. The four marker spellings themselves are untouched — the fenced block immediately above the deleted paragraph still lists all four, and the sentence naming pnpm check:adr-0087-registration and its CI step is untouched too, so the citation's antecedent is two lines up.

Line arithmetic

Lines
AGENTS.md before1,162
correction, :1116-1117 becomes :1116-1119+2
payment, :1136-1143 becomes one line−7
after1,157
ceiling (ratchet row)1,162
headroom5

Every edited line is ≤ 120 bytes in UTF-8 — 115 / 110 / 112 / 37 for the correction and 110 for the citation, measured in bytes rather than characters because the em dash and ⛔ are three bytes each. The widest-table-row pin is untouched at 1,081 bytes, and check:pm-skill-id-lint's population is respected: the new text carries no issue or PR numbers.

Edit-landed-on-disk proof

MeasurementBeforeAfter
wc -l AGENTS.md1,1621,157
grep -c 'Pure bug fixes do'10
grep -c 'sole channel that reaches an upgrader'10
grep -c 'skip-changeset'01
grep -c 'released package takes a'01
grep -c 'that output is the authority'01

git diff --stat: 1 file changed, 5 insertions, 10 deletions.

Gates — head 796501faa9

The union was re-derived after the last edit with node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands. It reported the list derived from this repo at 796501faa9, change set against merge base dee4dd4ba — one path, AGENTS.md. Every exit code was captured by redirect before any pipe.

CommandExitVerdict line
pnpm check:pm-skill-ratchet0✓ check-skill-line-ratchet: AGENTS.md is 1157 lines (ceiling 1162; headroom 5). and ✓ … AGENTS.md: widest table row is 1081 bytes (pin 1081; headroom 0).
pnpm check:pm-skill-ratchet --self-test0✓ check-skill-line-ratchet self-test: 111 cases pass.
pnpm check:pm-skill-id-lint0✓ check-skill-id-lint: 23 file(s) clean (pattern /#[0-9]{3,}/g).
pnpm check:pm-governed-prose0✓ check-governed-prose: 2 instruction surface(s) name all 5 registered governed surfaces … and claim no others.
pnpm check:nul-bytes0check-nul-bytes: OK (scanned 8063 text file(s) … no raw ASCII control bytes).
pnpm check:corpus-claim-drift0check-corpus-claim-drift: OK, no new claim sites beside a pinned spelling.
node scripts/check-required-contexts.mjs0✓ check-required-contexts: 6 required context name(s) pinned across 2 workflow(s) …
pnpm check:required-contexts0✓ check-required-contexts --self-test: 150 assertions …
pnpm check:agent-test-spelling0✓ check-agent-test-spelling: 0 violations — 430 file(s) …
pnpm check:docs-audit-scope0✓ docs-accuracy-audit scope is in sync with content/docs/: 190 hand-written doc(s) …
pnpm check:pm-governed-merges0✓ check-governed-merges --self-test: 243 assertions …

The baseline ratchet verdict before the edit, for comparison: ✓ check-skill-line-ratchet: AGENTS.md is 1162 lines (ceiling 1162; headroom 0). No gate answered a "PREREQUISITE NOT MET" or exit 3, so none is recorded NOT MEASURED. The derivation also noted nine further families that would apply once a changeset file exists — this PR deliberately has none, see below.

eslint

Not a narrowing — a measurement that the intersection is empty.

  • Population, read from eslint.config.mjs itself: every files: glob is **/*.{ts,tsx,mts,cts,js,jsx,mjs,cjs} or a narrowing of it. There is no .md or .mdx glob and no markdown processor or plugin anywhere in the config.
  • --format json reading for AGENTS.md:errorCount: 0, fatalErrorCount: 0, and the single message is "File ignored because no matching configuration was supplied."
  • Invariance: the diff touches exactly one file and that file is outside eslint's population by extension. No type-aware linting is in play for it, so this diff cannot move a lint verdict on any untouched file.

Changeset

skip-changeset applied. This diff publishes nothing from any released package: it touches exactly one file, AGENTS.md, a repo-root instruction surface that no package files list ships and that changeset version never bumps. Against scripts/check-empty-changeset.mjs's own enumeration, the alternative — an empty-frontmatter changeset — is precisely what that gate exists to reject: it "buys nothing the label does not, and uniquely carries the risk", being a real input to changesets/action that can stall a release while the run still goes green.

Merge path

Draft, and it stays draft — governed AGENTS.md, human merge is the review record. Auto-merge is not enabled and no reviewers were requested; requesting review is the dispatching seat's step.


Generated by Claude Code

…er none
AGENTS.md told authors "Pure bug fixes do not require a changeset", which
contradicts every enforced text: Check Changeset (pr-automation.yml) reds a PR
that adds zero changesets and carries no skip-changeset label, and that label
is for a diff publishing nothing from any released package. A bug fix in a
released package therefore had no green path if it followed the sentence.
The sentence predates enforcement. It landed 2026-05-30 (43625fb) when the
step only emitted ::warning:: and could not fail; the check became blocking on
2026-06-11 (a1251e4), and started counting changesets added BY THE PR on
2026-07-21 (8ff9210) -- the form that actually reds a zero-changeset bug fix.
Paid same-file, AGENTS.md being at its line ceiling: the ADR-0087 rationale
paragraph is re-derived from check-adr-0087-registration.mjs's own failure
output, so it collapses to a one-line citation in the file's established idiom.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationsize/sskip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

3 participants

@os-litant@os-zhuang@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

docs(agents): a released-package bug fix takes a patch changeset, never none - #14789

Merged
os-zhuang merged 1 commit into
mainfrom
claude/issue-14647-bugfix-changeset-sentence
Sep 3, 2026
Merged

docs(agents): a released-package bug fix takes a patch changeset, never none#14789
os-zhuang merged 1 commit into
mainfrom
claude/issue-14647-bugfix-changeset-sentence

Conversation

@os-litant

Copy link
Copy Markdown
Collaborator

Fixes#14647

AGENTS.md:1117 told authors 「Pure bug fixes do not require a changeset.」 Every enforced text disagrees, so a bug fix in a released package that followed the sentence literally had no green path through Check Changeset.

Ruled scope (triage comment 5514271473, adopted verbatim)

One sentence, saying two things:

  1. a bug fix in a released package takes a patch changeset;
  2. skip-changeset is never the answer for a released-package bug fix — that label is for a diff that publishes nothing from any released package.

Nothing was widened or reinterpreted beyond that.

Before / after, verbatim

BeforeAGENTS.md:1116-1117:

3. **Add a changeset for feature work.** When the change is a feature or functional improvement, run `pnpm changeset`
(or add a `.changeset/*.md` entry) describing it before committing. Pure bug fixes do **not** require a changeset.

AfterAGENTS.md:1116-1119:

3. **Add a changeset for anything that publishes.** Feature, functional improvement or fix — run `pnpm changeset`
(or add a `.changeset/*.md` entry) describing it before committing. A bug fix in a released package takes a
**`patch`** changeset — never none, and ⛔ never `skip-changeset`: that label is for a diff that publishes
nothing from any released package.

The instruction that survived unchanged is the middle clause — run pnpm changeset, or add a .changeset/*.md entry, describing it before committing. Only the final sentence was replaced, and the item's lead was re-aimed from "feature work" to "anything that publishes", since that is now what the item says.

The two dates that settle the "predates the gate" reading

The triage's reading is confirmed, and by a wider margin than the card assumed. Read from full history — the container's checkout is shallow, and both probes bottom out at the horizon commit until it is unshallowed, which is a trap worth naming: git log -S on a shallow clone reports the horizon commit as the introduction of text that is in fact much older.

WhenCommitState of the changeset check
2026-05-3043625fbd6cThe sentence lands. The step emits ::warning:: only and cannot fail — a zero-changeset bug fix is green by construction.
2026-06-11a1251e4737The step becomes blocking: ::error:: plus exit 1.
2026-07-218ff9210947The step starts counting changesets added by the PR rather than globbing the whole .changeset directory. This is the form that actually reds a zero-changeset bug fix.

The 2026-07-21 commit is explicit about why the earlier form could not bite, in its own inline comment: in pre-release mode changeset version retains every consumed .md file, so "the directory is permanently non-empty and the gate can never go red".

So on the day the sentence was written it was true — nothing forced a changeset for anything. It did not become wrong by being mis-worded; it became wrong when enforcement arrived under it, twelve days later for blocking and seven weeks later for the counting form. That is a refinement of the triage's gloss, not a contradiction of it: the sentence is stale relative to a gate that post-dates it, and correcting it to "a patch changeset" is repair rather than a policy change. Reported to the dispatching seat as such.

The payment

AGENTS.md is at its line ceiling — ratchet row ['AGENTS.md', 1162] at scripts/pm/check-skill-line-ratchet.mjs:529, headroom 0 — so the correction is paid by a same-file deletion. Nothing was re-wrapped; both edits are whole-line splices.

Deleted: the eight-line ADR-0087 rationale paragraph at AGENTS.md:1136-1143, replaced by a one-line citation in the file's own established idiom (compare :15, :916, :1012 — "its header is the authority on detail").

Why it is a restatement: the paragraph is a paraphrase of scripts/check-adr-0087-registration.mjs's own failure output — the report() block at :2976-2996, which prints to the author at exactly the moment they hit the gate. That is strictly better placed than prose in an instruction file the author may never re-read.

Deleted clauseSurviving single site
the ADR-0087 gates pin ledger ↔ artifact synchronycheck-adr-0087-registration.mjs:2980-2981
the artifacts are a pure projection of the registry:2982-2983
an entry never written leaves everything consistent, every gate green:2983-2984
a removal shipped that way, caught only by a human comparing by eye:2984-2985
ledger entries are the sole channel reaching an upgrader (objectstack migrate meta, spec-changes.json, the upgrade guide):2987-2990
for a surface with no spec schema there is no tombstone or schema rejection either:2988-2990
roughly 1 declared-breaking change in 7 needs an entry, so not-required is the ordinary answer and costs one line:2992-2994
no-migration-prescription is refused when the body carries a FROM → TO prescription:227, and :2633, also emitted output

Eight of eight. The four marker spellings themselves are untouched — the fenced block immediately above the deleted paragraph still lists all four, and the sentence naming pnpm check:adr-0087-registration and its CI step is untouched too, so the citation's antecedent is two lines up.

Line arithmetic

Lines
AGENTS.md before1,162
correction, :1116-1117 becomes :1116-1119+2
payment, :1136-1143 becomes one line−7
after1,157
ceiling (ratchet row)1,162
headroom5

Every edited line is ≤ 120 bytes in UTF-8 — 115 / 110 / 112 / 37 for the correction and 110 for the citation, measured in bytes rather than characters because the em dash and ⛔ are three bytes each. The widest-table-row pin is untouched at 1,081 bytes, and check:pm-skill-id-lint's population is respected: the new text carries no issue or PR numbers.

Edit-landed-on-disk proof

MeasurementBeforeAfter
wc -l AGENTS.md1,1621,157
grep -c 'Pure bug fixes do'10
grep -c 'sole channel that reaches an upgrader'10
grep -c 'skip-changeset'01
grep -c 'released package takes a'01
grep -c 'that output is the authority'01

git diff --stat: 1 file changed, 5 insertions, 10 deletions.

Gates — head 796501faa9

The union was re-derived after the last edit with node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands. It reported the list derived from this repo at 796501faa9, change set against merge base dee4dd4ba — one path, AGENTS.md. Every exit code was captured by redirect before any pipe.

CommandExitVerdict line
pnpm check:pm-skill-ratchet0✓ check-skill-line-ratchet: AGENTS.md is 1157 lines (ceiling 1162; headroom 5). and ✓ … AGENTS.md: widest table row is 1081 bytes (pin 1081; headroom 0).
pnpm check:pm-skill-ratchet --self-test0✓ check-skill-line-ratchet self-test: 111 cases pass.
pnpm check:pm-skill-id-lint0✓ check-skill-id-lint: 23 file(s) clean (pattern /#[0-9]{3,}/g).
pnpm check:pm-governed-prose0✓ check-governed-prose: 2 instruction surface(s) name all 5 registered governed surfaces … and claim no others.
pnpm check:nul-bytes0check-nul-bytes: OK (scanned 8063 text file(s) … no raw ASCII control bytes).
pnpm check:corpus-claim-drift0check-corpus-claim-drift: OK, no new claim sites beside a pinned spelling.
node scripts/check-required-contexts.mjs0✓ check-required-contexts: 6 required context name(s) pinned across 2 workflow(s) …
pnpm check:required-contexts0✓ check-required-contexts --self-test: 150 assertions …
pnpm check:agent-test-spelling0✓ check-agent-test-spelling: 0 violations — 430 file(s) …
pnpm check:docs-audit-scope0✓ docs-accuracy-audit scope is in sync with content/docs/: 190 hand-written doc(s) …
pnpm check:pm-governed-merges0✓ check-governed-merges --self-test: 243 assertions …

The baseline ratchet verdict before the edit, for comparison: ✓ check-skill-line-ratchet: AGENTS.md is 1162 lines (ceiling 1162; headroom 0). No gate answered a "PREREQUISITE NOT MET" or exit 3, so none is recorded NOT MEASURED. The derivation also noted nine further families that would apply once a changeset file exists — this PR deliberately has none, see below.

eslint

Not a narrowing — a measurement that the intersection is empty.

  • Population, read from eslint.config.mjs itself: every files: glob is **/*.{ts,tsx,mts,cts,js,jsx,mjs,cjs} or a narrowing of it. There is no .md or .mdx glob and no markdown processor or plugin anywhere in the config.
  • --format json reading for AGENTS.md:errorCount: 0, fatalErrorCount: 0, and the single message is "File ignored because no matching configuration was supplied."
  • Invariance: the diff touches exactly one file and that file is outside eslint's population by extension. No type-aware linting is in play for it, so this diff cannot move a lint verdict on any untouched file.

Changeset

skip-changeset applied. This diff publishes nothing from any released package: it touches exactly one file, AGENTS.md, a repo-root instruction surface that no package files list ships and that changeset version never bumps. Against scripts/check-empty-changeset.mjs's own enumeration, the alternative — an empty-frontmatter changeset — is precisely what that gate exists to reject: it "buys nothing the label does not, and uniquely carries the risk", being a real input to changesets/action that can stall a release while the run still goes green.

Merge path

Draft, and it stays draft — governed AGENTS.md, human merge is the review record. Auto-merge is not enabled and no reviewers were requested; requesting review is the dispatching seat's step.


Generated by Claude Code

…er none
AGENTS.md told authors "Pure bug fixes do not require a changeset", which
contradicts every enforced text: Check Changeset (pr-automation.yml) reds a PR
that adds zero changesets and carries no skip-changeset label, and that label
is for a diff publishing nothing from any released package. A bug fix in a
released package therefore had no green path if it followed the sentence.
The sentence predates enforcement. It landed 2026-05-30 (43625fb) when the
step only emitted ::warning:: and could not fail; the check became blocking on
2026-06-11 (a1251e4), and started counting changesets added BY THE PR on
2026-07-21 (8ff9210) -- the form that actually reds a zero-changeset bug fix.
Paid same-file, AGENTS.md being at its line ceiling: the ADR-0087 rationale
paragraph is re-derived from check-adr-0087-registration.mjs's own failure
output, so it collapses to a one-line citation in the file's established idiom.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationsize/sskip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

3 participants

@os-litant@os-zhuang@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

docs(agents): a released-package bug fix takes a patch changeset, never none - #14789

Merged
os-zhuang merged 1 commit into
mainfrom
claude/issue-14647-bugfix-changeset-sentence
Sep 3, 2026
Merged

docs(agents): a released-package bug fix takes a patch changeset, never none#14789
os-zhuang merged 1 commit into
mainfrom
claude/issue-14647-bugfix-changeset-sentence

Conversation

@os-litant

Copy link
Copy Markdown
Collaborator

Fixes#14647

AGENTS.md:1117 told authors 「Pure bug fixes do not require a changeset.」 Every enforced text disagrees, so a bug fix in a released package that followed the sentence literally had no green path through Check Changeset.

Ruled scope (triage comment 5514271473, adopted verbatim)

One sentence, saying two things:

  1. a bug fix in a released package takes a patch changeset;
  2. skip-changeset is never the answer for a released-package bug fix — that label is for a diff that publishes nothing from any released package.

Nothing was widened or reinterpreted beyond that.

Before / after, verbatim

BeforeAGENTS.md:1116-1117:

3. **Add a changeset for feature work.** When the change is a feature or functional improvement, run `pnpm changeset`
(or add a `.changeset/*.md` entry) describing it before committing. Pure bug fixes do **not** require a changeset.

AfterAGENTS.md:1116-1119:

3. **Add a changeset for anything that publishes.** Feature, functional improvement or fix — run `pnpm changeset`
(or add a `.changeset/*.md` entry) describing it before committing. A bug fix in a released package takes a
**`patch`** changeset — never none, and ⛔ never `skip-changeset`: that label is for a diff that publishes
nothing from any released package.

The instruction that survived unchanged is the middle clause — run pnpm changeset, or add a .changeset/*.md entry, describing it before committing. Only the final sentence was replaced, and the item's lead was re-aimed from "feature work" to "anything that publishes", since that is now what the item says.

The two dates that settle the "predates the gate" reading

The triage's reading is confirmed, and by a wider margin than the card assumed. Read from full history — the container's checkout is shallow, and both probes bottom out at the horizon commit until it is unshallowed, which is a trap worth naming: git log -S on a shallow clone reports the horizon commit as the introduction of text that is in fact much older.

WhenCommitState of the changeset check
2026-05-3043625fbd6cThe sentence lands. The step emits ::warning:: only and cannot fail — a zero-changeset bug fix is green by construction.
2026-06-11a1251e4737The step becomes blocking: ::error:: plus exit 1.
2026-07-218ff9210947The step starts counting changesets added by the PR rather than globbing the whole .changeset directory. This is the form that actually reds a zero-changeset bug fix.

The 2026-07-21 commit is explicit about why the earlier form could not bite, in its own inline comment: in pre-release mode changeset version retains every consumed .md file, so "the directory is permanently non-empty and the gate can never go red".

So on the day the sentence was written it was true — nothing forced a changeset for anything. It did not become wrong by being mis-worded; it became wrong when enforcement arrived under it, twelve days later for blocking and seven weeks later for the counting form. That is a refinement of the triage's gloss, not a contradiction of it: the sentence is stale relative to a gate that post-dates it, and correcting it to "a patch changeset" is repair rather than a policy change. Reported to the dispatching seat as such.

The payment

AGENTS.md is at its line ceiling — ratchet row ['AGENTS.md', 1162] at scripts/pm/check-skill-line-ratchet.mjs:529, headroom 0 — so the correction is paid by a same-file deletion. Nothing was re-wrapped; both edits are whole-line splices.

Deleted: the eight-line ADR-0087 rationale paragraph at AGENTS.md:1136-1143, replaced by a one-line citation in the file's own established idiom (compare :15, :916, :1012 — "its header is the authority on detail").

Why it is a restatement: the paragraph is a paraphrase of scripts/check-adr-0087-registration.mjs's own failure output — the report() block at :2976-2996, which prints to the author at exactly the moment they hit the gate. That is strictly better placed than prose in an instruction file the author may never re-read.

Deleted clauseSurviving single site
the ADR-0087 gates pin ledger ↔ artifact synchronycheck-adr-0087-registration.mjs:2980-2981
the artifacts are a pure projection of the registry:2982-2983
an entry never written leaves everything consistent, every gate green:2983-2984
a removal shipped that way, caught only by a human comparing by eye:2984-2985
ledger entries are the sole channel reaching an upgrader (objectstack migrate meta, spec-changes.json, the upgrade guide):2987-2990
for a surface with no spec schema there is no tombstone or schema rejection either:2988-2990
roughly 1 declared-breaking change in 7 needs an entry, so not-required is the ordinary answer and costs one line:2992-2994
no-migration-prescription is refused when the body carries a FROM → TO prescription:227, and :2633, also emitted output

Eight of eight. The four marker spellings themselves are untouched — the fenced block immediately above the deleted paragraph still lists all four, and the sentence naming pnpm check:adr-0087-registration and its CI step is untouched too, so the citation's antecedent is two lines up.

Line arithmetic

Lines
AGENTS.md before1,162
correction, :1116-1117 becomes :1116-1119+2
payment, :1136-1143 becomes one line−7
after1,157
ceiling (ratchet row)1,162
headroom5

Every edited line is ≤ 120 bytes in UTF-8 — 115 / 110 / 112 / 37 for the correction and 110 for the citation, measured in bytes rather than characters because the em dash and ⛔ are three bytes each. The widest-table-row pin is untouched at 1,081 bytes, and check:pm-skill-id-lint's population is respected: the new text carries no issue or PR numbers.

Edit-landed-on-disk proof

MeasurementBeforeAfter
wc -l AGENTS.md1,1621,157
grep -c 'Pure bug fixes do'10
grep -c 'sole channel that reaches an upgrader'10
grep -c 'skip-changeset'01
grep -c 'released package takes a'01
grep -c 'that output is the authority'01

git diff --stat: 1 file changed, 5 insertions, 10 deletions.

Gates — head 796501faa9

The union was re-derived after the last edit with node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands. It reported the list derived from this repo at 796501faa9, change set against merge base dee4dd4ba — one path, AGENTS.md. Every exit code was captured by redirect before any pipe.

CommandExitVerdict line
pnpm check:pm-skill-ratchet0✓ check-skill-line-ratchet: AGENTS.md is 1157 lines (ceiling 1162; headroom 5). and ✓ … AGENTS.md: widest table row is 1081 bytes (pin 1081; headroom 0).
pnpm check:pm-skill-ratchet --self-test0✓ check-skill-line-ratchet self-test: 111 cases pass.
pnpm check:pm-skill-id-lint0✓ check-skill-id-lint: 23 file(s) clean (pattern /#[0-9]{3,}/g).
pnpm check:pm-governed-prose0✓ check-governed-prose: 2 instruction surface(s) name all 5 registered governed surfaces … and claim no others.
pnpm check:nul-bytes0check-nul-bytes: OK (scanned 8063 text file(s) … no raw ASCII control bytes).
pnpm check:corpus-claim-drift0check-corpus-claim-drift: OK, no new claim sites beside a pinned spelling.
node scripts/check-required-contexts.mjs0✓ check-required-contexts: 6 required context name(s) pinned across 2 workflow(s) …
pnpm check:required-contexts0✓ check-required-contexts --self-test: 150 assertions …
pnpm check:agent-test-spelling0✓ check-agent-test-spelling: 0 violations — 430 file(s) …
pnpm check:docs-audit-scope0✓ docs-accuracy-audit scope is in sync with content/docs/: 190 hand-written doc(s) …
pnpm check:pm-governed-merges0✓ check-governed-merges --self-test: 243 assertions …

The baseline ratchet verdict before the edit, for comparison: ✓ check-skill-line-ratchet: AGENTS.md is 1162 lines (ceiling 1162; headroom 0). No gate answered a "PREREQUISITE NOT MET" or exit 3, so none is recorded NOT MEASURED. The derivation also noted nine further families that would apply once a changeset file exists — this PR deliberately has none, see below.

eslint

Not a narrowing — a measurement that the intersection is empty.

  • Population, read from eslint.config.mjs itself: every files: glob is **/*.{ts,tsx,mts,cts,js,jsx,mjs,cjs} or a narrowing of it. There is no .md or .mdx glob and no markdown processor or plugin anywhere in the config.
  • --format json reading for AGENTS.md:errorCount: 0, fatalErrorCount: 0, and the single message is "File ignored because no matching configuration was supplied."
  • Invariance: the diff touches exactly one file and that file is outside eslint's population by extension. No type-aware linting is in play for it, so this diff cannot move a lint verdict on any untouched file.

Changeset

skip-changeset applied. This diff publishes nothing from any released package: it touches exactly one file, AGENTS.md, a repo-root instruction surface that no package files list ships and that changeset version never bumps. Against scripts/check-empty-changeset.mjs's own enumeration, the alternative — an empty-frontmatter changeset — is precisely what that gate exists to reject: it "buys nothing the label does not, and uniquely carries the risk", being a real input to changesets/action that can stall a release while the run still goes green.

Merge path

Draft, and it stays draft — governed AGENTS.md, human merge is the review record. Auto-merge is not enabled and no reviewers were requested; requesting review is the dispatching seat's step.


Generated by Claude Code

…er none
AGENTS.md told authors "Pure bug fixes do not require a changeset", which
contradicts every enforced text: Check Changeset (pr-automation.yml) reds a PR
that adds zero changesets and carries no skip-changeset label, and that label
is for a diff publishing nothing from any released package. A bug fix in a
released package therefore had no green path if it followed the sentence.
The sentence predates enforcement. It landed 2026-05-30 (43625fb) when the
step only emitted ::warning:: and could not fail; the check became blocking on
2026-06-11 (a1251e4), and started counting changesets added BY THE PR on
2026-07-21 (8ff9210) -- the form that actually reds a zero-changeset bug fix.
Paid same-file, AGENTS.md being at its line ceiling: the ADR-0087 rationale
paragraph is re-derived from check-adr-0087-registration.mjs's own failure
output, so it collapses to a one-line citation in the file's established idiom.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationsize/sskip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

3 participants

@os-litant@os-zhuang@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

docs(agents): a released-package bug fix takes a patch changeset, never none - #14789

Merged
os-zhuang merged 1 commit into
mainfrom
claude/issue-14647-bugfix-changeset-sentence
Sep 3, 2026
Merged

docs(agents): a released-package bug fix takes a patch changeset, never none#14789
os-zhuang merged 1 commit into
mainfrom
claude/issue-14647-bugfix-changeset-sentence

Conversation

@os-litant

Copy link
Copy Markdown
Collaborator

Fixes#14647

AGENTS.md:1117 told authors 「Pure bug fixes do not require a changeset.」 Every enforced text disagrees, so a bug fix in a released package that followed the sentence literally had no green path through Check Changeset.

Ruled scope (triage comment 5514271473, adopted verbatim)

One sentence, saying two things:

  1. a bug fix in a released package takes a patch changeset;
  2. skip-changeset is never the answer for a released-package bug fix — that label is for a diff that publishes nothing from any released package.

Nothing was widened or reinterpreted beyond that.

Before / after, verbatim

BeforeAGENTS.md:1116-1117:

3. **Add a changeset for feature work.** When the change is a feature or functional improvement, run `pnpm changeset`
(or add a `.changeset/*.md` entry) describing it before committing. Pure bug fixes do **not** require a changeset.

AfterAGENTS.md:1116-1119:

3. **Add a changeset for anything that publishes.** Feature, functional improvement or fix — run `pnpm changeset`
(or add a `.changeset/*.md` entry) describing it before committing. A bug fix in a released package takes a
**`patch`** changeset — never none, and ⛔ never `skip-changeset`: that label is for a diff that publishes
nothing from any released package.

The instruction that survived unchanged is the middle clause — run pnpm changeset, or add a .changeset/*.md entry, describing it before committing. Only the final sentence was replaced, and the item's lead was re-aimed from "feature work" to "anything that publishes", since that is now what the item says.

The two dates that settle the "predates the gate" reading

The triage's reading is confirmed, and by a wider margin than the card assumed. Read from full history — the container's checkout is shallow, and both probes bottom out at the horizon commit until it is unshallowed, which is a trap worth naming: git log -S on a shallow clone reports the horizon commit as the introduction of text that is in fact much older.

WhenCommitState of the changeset check
2026-05-3043625fbd6cThe sentence lands. The step emits ::warning:: only and cannot fail — a zero-changeset bug fix is green by construction.
2026-06-11a1251e4737The step becomes blocking: ::error:: plus exit 1.
2026-07-218ff9210947The step starts counting changesets added by the PR rather than globbing the whole .changeset directory. This is the form that actually reds a zero-changeset bug fix.

The 2026-07-21 commit is explicit about why the earlier form could not bite, in its own inline comment: in pre-release mode changeset version retains every consumed .md file, so "the directory is permanently non-empty and the gate can never go red".

So on the day the sentence was written it was true — nothing forced a changeset for anything. It did not become wrong by being mis-worded; it became wrong when enforcement arrived under it, twelve days later for blocking and seven weeks later for the counting form. That is a refinement of the triage's gloss, not a contradiction of it: the sentence is stale relative to a gate that post-dates it, and correcting it to "a patch changeset" is repair rather than a policy change. Reported to the dispatching seat as such.

The payment

AGENTS.md is at its line ceiling — ratchet row ['AGENTS.md', 1162] at scripts/pm/check-skill-line-ratchet.mjs:529, headroom 0 — so the correction is paid by a same-file deletion. Nothing was re-wrapped; both edits are whole-line splices.

Deleted: the eight-line ADR-0087 rationale paragraph at AGENTS.md:1136-1143, replaced by a one-line citation in the file's own established idiom (compare :15, :916, :1012 — "its header is the authority on detail").

Why it is a restatement: the paragraph is a paraphrase of scripts/check-adr-0087-registration.mjs's own failure output — the report() block at :2976-2996, which prints to the author at exactly the moment they hit the gate. That is strictly better placed than prose in an instruction file the author may never re-read.

Deleted clauseSurviving single site
the ADR-0087 gates pin ledger ↔ artifact synchronycheck-adr-0087-registration.mjs:2980-2981
the artifacts are a pure projection of the registry:2982-2983
an entry never written leaves everything consistent, every gate green:2983-2984
a removal shipped that way, caught only by a human comparing by eye:2984-2985
ledger entries are the sole channel reaching an upgrader (objectstack migrate meta, spec-changes.json, the upgrade guide):2987-2990
for a surface with no spec schema there is no tombstone or schema rejection either:2988-2990
roughly 1 declared-breaking change in 7 needs an entry, so not-required is the ordinary answer and costs one line:2992-2994
no-migration-prescription is refused when the body carries a FROM → TO prescription:227, and :2633, also emitted output

Eight of eight. The four marker spellings themselves are untouched — the fenced block immediately above the deleted paragraph still lists all four, and the sentence naming pnpm check:adr-0087-registration and its CI step is untouched too, so the citation's antecedent is two lines up.

Line arithmetic

Lines
AGENTS.md before1,162
correction, :1116-1117 becomes :1116-1119+2
payment, :1136-1143 becomes one line−7
after1,157
ceiling (ratchet row)1,162
headroom5

Every edited line is ≤ 120 bytes in UTF-8 — 115 / 110 / 112 / 37 for the correction and 110 for the citation, measured in bytes rather than characters because the em dash and ⛔ are three bytes each. The widest-table-row pin is untouched at 1,081 bytes, and check:pm-skill-id-lint's population is respected: the new text carries no issue or PR numbers.

Edit-landed-on-disk proof

MeasurementBeforeAfter
wc -l AGENTS.md1,1621,157
grep -c 'Pure bug fixes do'10
grep -c 'sole channel that reaches an upgrader'10
grep -c 'skip-changeset'01
grep -c 'released package takes a'01
grep -c 'that output is the authority'01

git diff --stat: 1 file changed, 5 insertions, 10 deletions.

Gates — head 796501faa9

The union was re-derived after the last edit with node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands. It reported the list derived from this repo at 796501faa9, change set against merge base dee4dd4ba — one path, AGENTS.md. Every exit code was captured by redirect before any pipe.

CommandExitVerdict line
pnpm check:pm-skill-ratchet0✓ check-skill-line-ratchet: AGENTS.md is 1157 lines (ceiling 1162; headroom 5). and ✓ … AGENTS.md: widest table row is 1081 bytes (pin 1081; headroom 0).
pnpm check:pm-skill-ratchet --self-test0✓ check-skill-line-ratchet self-test: 111 cases pass.
pnpm check:pm-skill-id-lint0✓ check-skill-id-lint: 23 file(s) clean (pattern /#[0-9]{3,}/g).
pnpm check:pm-governed-prose0✓ check-governed-prose: 2 instruction surface(s) name all 5 registered governed surfaces … and claim no others.
pnpm check:nul-bytes0check-nul-bytes: OK (scanned 8063 text file(s) … no raw ASCII control bytes).
pnpm check:corpus-claim-drift0check-corpus-claim-drift: OK, no new claim sites beside a pinned spelling.
node scripts/check-required-contexts.mjs0✓ check-required-contexts: 6 required context name(s) pinned across 2 workflow(s) …
pnpm check:required-contexts0✓ check-required-contexts --self-test: 150 assertions …
pnpm check:agent-test-spelling0✓ check-agent-test-spelling: 0 violations — 430 file(s) …
pnpm check:docs-audit-scope0✓ docs-accuracy-audit scope is in sync with content/docs/: 190 hand-written doc(s) …
pnpm check:pm-governed-merges0✓ check-governed-merges --self-test: 243 assertions …

The baseline ratchet verdict before the edit, for comparison: ✓ check-skill-line-ratchet: AGENTS.md is 1162 lines (ceiling 1162; headroom 0). No gate answered a "PREREQUISITE NOT MET" or exit 3, so none is recorded NOT MEASURED. The derivation also noted nine further families that would apply once a changeset file exists — this PR deliberately has none, see below.

eslint

Not a narrowing — a measurement that the intersection is empty.

  • Population, read from eslint.config.mjs itself: every files: glob is **/*.{ts,tsx,mts,cts,js,jsx,mjs,cjs} or a narrowing of it. There is no .md or .mdx glob and no markdown processor or plugin anywhere in the config.
  • --format json reading for AGENTS.md:errorCount: 0, fatalErrorCount: 0, and the single message is "File ignored because no matching configuration was supplied."
  • Invariance: the diff touches exactly one file and that file is outside eslint's population by extension. No type-aware linting is in play for it, so this diff cannot move a lint verdict on any untouched file.

Changeset

skip-changeset applied. This diff publishes nothing from any released package: it touches exactly one file, AGENTS.md, a repo-root instruction surface that no package files list ships and that changeset version never bumps. Against scripts/check-empty-changeset.mjs's own enumeration, the alternative — an empty-frontmatter changeset — is precisely what that gate exists to reject: it "buys nothing the label does not, and uniquely carries the risk", being a real input to changesets/action that can stall a release while the run still goes green.

Merge path

Draft, and it stays draft — governed AGENTS.md, human merge is the review record. Auto-merge is not enabled and no reviewers were requested; requesting review is the dispatching seat's step.


Generated by Claude Code

…er none
AGENTS.md told authors "Pure bug fixes do not require a changeset", which
contradicts every enforced text: Check Changeset (pr-automation.yml) reds a PR
that adds zero changesets and carries no skip-changeset label, and that label
is for a diff publishing nothing from any released package. A bug fix in a
released package therefore had no green path if it followed the sentence.
The sentence predates enforcement. It landed 2026-05-30 (43625fb) when the
step only emitted ::warning:: and could not fail; the check became blocking on
2026-06-11 (a1251e4), and started counting changesets added BY THE PR on
2026-07-21 (8ff9210) -- the form that actually reds a zero-changeset bug fix.
Paid same-file, AGENTS.md being at its line ceiling: the ADR-0087 rationale
paragraph is re-derived from check-adr-0087-registration.mjs's own failure
output, so it collapses to a one-line citation in the file's established idiom.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationsize/sskip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

3 participants

@os-litant@os-zhuang@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

docs(agents): a released-package bug fix takes a patch changeset, never none - #14789

Merged
os-zhuang merged 1 commit into
mainfrom
claude/issue-14647-bugfix-changeset-sentence
Sep 3, 2026
Merged

docs(agents): a released-package bug fix takes a patch changeset, never none#14789
os-zhuang merged 1 commit into
mainfrom
claude/issue-14647-bugfix-changeset-sentence

Conversation

@os-litant

Copy link
Copy Markdown
Collaborator

Fixes#14647

AGENTS.md:1117 told authors 「Pure bug fixes do not require a changeset.」 Every enforced text disagrees, so a bug fix in a released package that followed the sentence literally had no green path through Check Changeset.

Ruled scope (triage comment 5514271473, adopted verbatim)

One sentence, saying two things:

  1. a bug fix in a released package takes a patch changeset;
  2. skip-changeset is never the answer for a released-package bug fix — that label is for a diff that publishes nothing from any released package.

Nothing was widened or reinterpreted beyond that.

Before / after, verbatim

BeforeAGENTS.md:1116-1117:

3. **Add a changeset for feature work.** When the change is a feature or functional improvement, run `pnpm changeset`
(or add a `.changeset/*.md` entry) describing it before committing. Pure bug fixes do **not** require a changeset.

AfterAGENTS.md:1116-1119:

3. **Add a changeset for anything that publishes.** Feature, functional improvement or fix — run `pnpm changeset`
(or add a `.changeset/*.md` entry) describing it before committing. A bug fix in a released package takes a
**`patch`** changeset — never none, and ⛔ never `skip-changeset`: that label is for a diff that publishes
nothing from any released package.

The instruction that survived unchanged is the middle clause — run pnpm changeset, or add a .changeset/*.md entry, describing it before committing. Only the final sentence was replaced, and the item's lead was re-aimed from "feature work" to "anything that publishes", since that is now what the item says.

The two dates that settle the "predates the gate" reading

The triage's reading is confirmed, and by a wider margin than the card assumed. Read from full history — the container's checkout is shallow, and both probes bottom out at the horizon commit until it is unshallowed, which is a trap worth naming: git log -S on a shallow clone reports the horizon commit as the introduction of text that is in fact much older.

WhenCommitState of the changeset check
2026-05-3043625fbd6cThe sentence lands. The step emits ::warning:: only and cannot fail — a zero-changeset bug fix is green by construction.
2026-06-11a1251e4737The step becomes blocking: ::error:: plus exit 1.
2026-07-218ff9210947The step starts counting changesets added by the PR rather than globbing the whole .changeset directory. This is the form that actually reds a zero-changeset bug fix.

The 2026-07-21 commit is explicit about why the earlier form could not bite, in its own inline comment: in pre-release mode changeset version retains every consumed .md file, so "the directory is permanently non-empty and the gate can never go red".

So on the day the sentence was written it was true — nothing forced a changeset for anything. It did not become wrong by being mis-worded; it became wrong when enforcement arrived under it, twelve days later for blocking and seven weeks later for the counting form. That is a refinement of the triage's gloss, not a contradiction of it: the sentence is stale relative to a gate that post-dates it, and correcting it to "a patch changeset" is repair rather than a policy change. Reported to the dispatching seat as such.

The payment

AGENTS.md is at its line ceiling — ratchet row ['AGENTS.md', 1162] at scripts/pm/check-skill-line-ratchet.mjs:529, headroom 0 — so the correction is paid by a same-file deletion. Nothing was re-wrapped; both edits are whole-line splices.

Deleted: the eight-line ADR-0087 rationale paragraph at AGENTS.md:1136-1143, replaced by a one-line citation in the file's own established idiom (compare :15, :916, :1012 — "its header is the authority on detail").

Why it is a restatement: the paragraph is a paraphrase of scripts/check-adr-0087-registration.mjs's own failure output — the report() block at :2976-2996, which prints to the author at exactly the moment they hit the gate. That is strictly better placed than prose in an instruction file the author may never re-read.

Deleted clauseSurviving single site
the ADR-0087 gates pin ledger ↔ artifact synchronycheck-adr-0087-registration.mjs:2980-2981
the artifacts are a pure projection of the registry:2982-2983
an entry never written leaves everything consistent, every gate green:2983-2984
a removal shipped that way, caught only by a human comparing by eye:2984-2985
ledger entries are the sole channel reaching an upgrader (objectstack migrate meta, spec-changes.json, the upgrade guide):2987-2990
for a surface with no spec schema there is no tombstone or schema rejection either:2988-2990
roughly 1 declared-breaking change in 7 needs an entry, so not-required is the ordinary answer and costs one line:2992-2994
no-migration-prescription is refused when the body carries a FROM → TO prescription:227, and :2633, also emitted output

Eight of eight. The four marker spellings themselves are untouched — the fenced block immediately above the deleted paragraph still lists all four, and the sentence naming pnpm check:adr-0087-registration and its CI step is untouched too, so the citation's antecedent is two lines up.

Line arithmetic

Lines
AGENTS.md before1,162
correction, :1116-1117 becomes :1116-1119+2
payment, :1136-1143 becomes one line−7
after1,157
ceiling (ratchet row)1,162
headroom5

Every edited line is ≤ 120 bytes in UTF-8 — 115 / 110 / 112 / 37 for the correction and 110 for the citation, measured in bytes rather than characters because the em dash and ⛔ are three bytes each. The widest-table-row pin is untouched at 1,081 bytes, and check:pm-skill-id-lint's population is respected: the new text carries no issue or PR numbers.

Edit-landed-on-disk proof

MeasurementBeforeAfter
wc -l AGENTS.md1,1621,157
grep -c 'Pure bug fixes do'10
grep -c 'sole channel that reaches an upgrader'10
grep -c 'skip-changeset'01
grep -c 'released package takes a'01
grep -c 'that output is the authority'01

git diff --stat: 1 file changed, 5 insertions, 10 deletions.

Gates — head 796501faa9

The union was re-derived after the last edit with node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands. It reported the list derived from this repo at 796501faa9, change set against merge base dee4dd4ba — one path, AGENTS.md. Every exit code was captured by redirect before any pipe.

CommandExitVerdict line
pnpm check:pm-skill-ratchet0✓ check-skill-line-ratchet: AGENTS.md is 1157 lines (ceiling 1162; headroom 5). and ✓ … AGENTS.md: widest table row is 1081 bytes (pin 1081; headroom 0).
pnpm check:pm-skill-ratchet --self-test0✓ check-skill-line-ratchet self-test: 111 cases pass.
pnpm check:pm-skill-id-lint0✓ check-skill-id-lint: 23 file(s) clean (pattern /#[0-9]{3,}/g).
pnpm check:pm-governed-prose0✓ check-governed-prose: 2 instruction surface(s) name all 5 registered governed surfaces … and claim no others.
pnpm check:nul-bytes0check-nul-bytes: OK (scanned 8063 text file(s) … no raw ASCII control bytes).
pnpm check:corpus-claim-drift0check-corpus-claim-drift: OK, no new claim sites beside a pinned spelling.
node scripts/check-required-contexts.mjs0✓ check-required-contexts: 6 required context name(s) pinned across 2 workflow(s) …
pnpm check:required-contexts0✓ check-required-contexts --self-test: 150 assertions …
pnpm check:agent-test-spelling0✓ check-agent-test-spelling: 0 violations — 430 file(s) …
pnpm check:docs-audit-scope0✓ docs-accuracy-audit scope is in sync with content/docs/: 190 hand-written doc(s) …
pnpm check:pm-governed-merges0✓ check-governed-merges --self-test: 243 assertions …

The baseline ratchet verdict before the edit, for comparison: ✓ check-skill-line-ratchet: AGENTS.md is 1162 lines (ceiling 1162; headroom 0). No gate answered a "PREREQUISITE NOT MET" or exit 3, so none is recorded NOT MEASURED. The derivation also noted nine further families that would apply once a changeset file exists — this PR deliberately has none, see below.

eslint

Not a narrowing — a measurement that the intersection is empty.

  • Population, read from eslint.config.mjs itself: every files: glob is **/*.{ts,tsx,mts,cts,js,jsx,mjs,cjs} or a narrowing of it. There is no .md or .mdx glob and no markdown processor or plugin anywhere in the config.
  • --format json reading for AGENTS.md:errorCount: 0, fatalErrorCount: 0, and the single message is "File ignored because no matching configuration was supplied."
  • Invariance: the diff touches exactly one file and that file is outside eslint's population by extension. No type-aware linting is in play for it, so this diff cannot move a lint verdict on any untouched file.

Changeset

skip-changeset applied. This diff publishes nothing from any released package: it touches exactly one file, AGENTS.md, a repo-root instruction surface that no package files list ships and that changeset version never bumps. Against scripts/check-empty-changeset.mjs's own enumeration, the alternative — an empty-frontmatter changeset — is precisely what that gate exists to reject: it "buys nothing the label does not, and uniquely carries the risk", being a real input to changesets/action that can stall a release while the run still goes green.

Merge path

Draft, and it stays draft — governed AGENTS.md, human merge is the review record. Auto-merge is not enabled and no reviewers were requested; requesting review is the dispatching seat's step.


Generated by Claude Code

…er none
AGENTS.md told authors "Pure bug fixes do not require a changeset", which
contradicts every enforced text: Check Changeset (pr-automation.yml) reds a PR
that adds zero changesets and carries no skip-changeset label, and that label
is for a diff publishing nothing from any released package. A bug fix in a
released package therefore had no green path if it followed the sentence.
The sentence predates enforcement. It landed 2026-05-30 (43625fb) when the
step only emitted ::warning:: and could not fail; the check became blocking on
2026-06-11 (a1251e4), and started counting changesets added BY THE PR on
2026-07-21 (8ff9210) -- the form that actually reds a zero-changeset bug fix.
Paid same-file, AGENTS.md being at its line ceiling: the ADR-0087 rationale
paragraph is re-derived from check-adr-0087-registration.mjs's own failure
output, so it collapses to a one-line citation in the file's established idiom.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationsize/sskip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

3 participants

@os-litant@os-zhuang@claude