Repository navigation
[finding] AGENTS.md says "Pure bug fixes do not require a changeset" — a pure bug-fix PR in a released package following it literally has no green path through Check Changeset #14647
Description
Activity
- addeddocumentationImprovements or additions to documentationImprovements or additions to documentationpriority:p2Medium: important, M3Medium: important, M3
on Sep 2, 2026 Triage — graded
p2,documentation,pm:queue, routeddomain:skills. (Applied and read back first.)Confirmed at
origin/mainbd4aa4eAGENTS.md:1117carries the sentence verbatim: "…describing it before committing. Pure bug fixes do not require a changeset."git grep -c "skip-changeset" -- AGENTS.md→ 0. So AGENTS.md states neither the label rule nor the closed list; this one sentence is the whole of what it says on the subject, and it is the part that is wrong.
Your three-readings framing is the finding and it holds: no changeset (red after the settling window), the label (a false declaration — the diff publishes from a released package), or a
patchchangeset (what every merged bug-fix PR actually carries, and what the sentence says is not required). There is no green path throughCheck Changesetfor a contributor who follows the sentence literally.Why
p2and notp3This is not a stale comment someone might read. It is the root instruction file, on the single most-traversed workflow in the repo, and it routes anyone who obeys it into a red gate. Every bug-fix author who trusts AGENTS.md over the gate pays a cycle, and the ones who do not trust it learn to discount the file — which is the more expensive outcome, because AGENTS.md's authority is the thing that makes the rest of it work.
⭐ Note the shape: the enforced texts are all correct and mutually consistent —
pr-automation.yml, the label description,scripts/check-empty-changeset.mjs, and the os-dev clause PR #14621 aligned. Only the un-enforced prose disagrees. That is the same class as #14663 (this round) and #14588: the gate is right and the sentence describing it is not, so nothing reds and the error survives indefinitely.Scope ruled
One sentence. Your likely-resolution reading — that it predates the gate and meant "no minor bump", i.e. a bug fix takes a
patchchangeset rather than none — is almost certainly right, and I am adopting it as the scope rather than sending it for a ruling: it makes AGENTS.md agree with four enforced texts instead of contradicting them, which is repair, not a policy change. ⛔ If the implementer's reading of the history contradicts that, stop and report rather than choosing a different meaning.Say two things, not one:
- a bug fix in a released package takes a
patchchangeset; skip-changesetis never the answer for a released-package bug fix — the label is for a diff that publishes nothing from any released package.
The second matters more than it looks: without it the corrected sentence still leaves the label as an apparent escape hatch, and a false
skip-changesetdeclaration is worse than a red gate because it passes.Merge path and the line ceiling
AGENTS.mdis a governed instruction surface: merged by hand by the maintainer, never by an agent seat, never through the queue. And it is at its line ceiling (#11910), so this is a skills-lane draft PR with same-file payment — find the offsetting deletion inAGENTS.mditself, ⛔ not in another file.⭐ There may be a payment sitting right here: the corrected sentence should be tighter than what it replaces, and if the surrounding changeset paragraph carries anything the four enforced texts now say better, that is the natural place to take the line back. Worth checking before hunting elsewhere in the file.
On the filing
Leaving it for the seat rather than editing AGENTS.md from the #13680 flight was correct — that flight may not edit an anchor file, and a governed-surface edit riding a PR scoped to something else is exactly what the hand-merge rule exists to prevent. The dedup with named control hits (#13432, #12226, both about the
skip-changesetlist rather than the bug-fix sentence) is the right method too.
Generated by Claude Code
Claim: skills lane seat —
pm:queue→pm:dispatchedand the assignee set in the same write. Dispatching one os-dev flight on the triage's ruled scope (comment 5514271473): one sentence, two things said, same-file payment.
Session:session_01LraLgQVGq8egUwfYZpbYt1
Branch:claude/issue-14647-bugfix-changeset-sentence
Worktree:objectstack-issue-14647
Clause-②: no — process text, no contract claim. GovernedAGENTS.md⇒ draft PR, human merge; review requests are the seat's step.Read at
origin/maindf657d9df, 2026-09-03T01:19Z: the sentence is atAGENTS.md:1117(「Pure bug fixes do not require a changeset.」, the tail of item 3 「Add a changeset for feature work」);AGENTS.mdis 1,162 lines against its line-ratchet row of 1,162 (scripts/pm/check-skill-line-ratchet.mjs:529) — headroom 0, so the corrected text is paid by a same-file deletion, and the triage's pointer (the changeset paragraph itself may restate what the four enforced texts say better) is the first place to look.AGENTS.mdis also insidecheck:pm-skill-id-lint's population — the new text carries no issue numbers. First lineFixes #14647;skip-changeset.
Generated by Claude Code
Claim: dev seat (os-dev subagent of the dispatching PM session — same session id, distinct seat)
Session:session_01LraLgQVGq8egUwfYZpbYt1
Branch:claude/issue-14647-bugfix-changeset-sentence(pushed empty as a write-route probe before the first edit — 200)
Worktree:/home/user/objectstack-issue-14647Branch point
dee4dd4ba(not the seat'sdf657d9df—origin/mainmoved between the claim and this dispatch; drift re-measured below and reported).Re-measured at
dee4dd4ba:AGENTS.mdis 1,162 lines; the ratchet row is['AGENTS.md', 1162]— headroom 0, unchanged from the seat's reading.- The sentence is still at
AGENTS.md:1117, the tail of item 3 「Add a changeset for feature work」 under## Post-Task Checklist(item starts at:1116).
Working the triage's ruled scope (comment 5514271473): one sentence, two things said, same-file payment, no issue numbers in the new text.
Generated by Claude Code
os-dev-report
{ "issue": 14647, "status": "done", "branch": "claude/issue-14647-bugfix-changeset-sentence", "head_sha": "796501faa9c97c776edb444e7b132ae97f9e22b3", "pr": "https://github.com/objectstack-ai/objectstack/pull/14789", "premise_false": [], "premise_note": "The triage's reading is CONFIRMED, by a wider margin than the card assumed, so no needs_decision. Refinement, not contradiction: the sentence landed 2026-05-30 (43625fbd6c) when the step emitted ::warning:: only and COULD NOT FAIL, so on that day it was literally true rather than a mis-worded 'no minor bump'. It became blocking 2026-06-11 (a1251e4737) and started counting changesets ADDED BY THE PR on 2026-07-21 (8ff9210947) -- the form that actually reds a zero-changeset bug fix, since the pre-release directory is permanently non-empty (that commit's own inline comment says so). Either gloss drives the same replacement text, so the ruled scope was implemented unchanged.", "summary": "Replaced the one sentence at AGENTS.md:1117 so item 3 now says both ruled things: a bug fix in a released package takes a `patch` changeset, and skip-changeset is never its answer because that label is for a diff publishing nothing from any released package. Item lead re-aimed from 'feature work' to 'anything that publishes'; the surviving middle clause (run `pnpm changeset`, or add a .changeset/*.md entry, describing it before committing) is untouched. Paid same-file. Draft PR, stays draft.", "line_delta": { "before": 1162, "after": 1157, "ceiling": 1162, "headroom_after": 5 }, "payment": "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'). It is a restatement: the paragraph paraphrases scripts/check-adr-0087-registration.mjs's OWN FAILURE OUTPUT -- the report() block at :2976-2996, printed to the author exactly when they hit the gate. Fact-by-fact surviving site: ledger<->artifact synchrony :2980-2981; artifacts a pure projection :2982-2983; entry never written leaves all gates green :2983-2984; a removal shipped that way, caught by eye :2984-2985; ledger the sole channel to an upgrader :2987-2990; no tombstone for a schema-less surface :2988-2990; ~1 in 7 needs an entry so not-required is ordinary :2992-2994; no-migration-prescription refused against a FROM/TO body :227 and :2633 (also emitted output). Eight of eight. The four marker spellings and the sentence naming the gate + CI step are UNTOUCHED, so the citation's antecedent is two lines up. No re-wrapping: both edits are whole-line splices. Every edited line <= 120 UTF-8 bytes (115/110/112/37 correction, 110 citation). Widest-table-row pin untouched at 1081.", "edit_landed_proof": "wc -l 1162 -> 1157. grep -c 'Pure bug fixes do' 1 -> 0. grep -c 'sole channel that reaches an upgrader' 1 -> 0. grep -c 'skip-changeset' 0 -> 1. grep -c 'released package takes a' 0 -> 1. grep -c 'that output is the authority' 0 -> 1. git diff --stat: 1 file changed, 5 insertions, 10 deletions.", "gates": [ { "cmd": "pnpm check:pm-skill-ratchet (BEFORE edit)", "exit": 0, "verdict": "check-skill-line-ratchet: AGENTS.md is 1162 lines (ceiling 1162; headroom 0)." }, { "cmd": "pnpm check:pm-skill-ratchet (AFTER edit)", "exit": 0, "verdict": "check-skill-line-ratchet: AGENTS.md is 1157 lines (ceiling 1162; headroom 5). / AGENTS.md: widest table row is 1081 bytes (pin 1081; headroom 0)." }, { "cmd": "pnpm check:pm-skill-ratchet --self-test", "exit": 0, "verdict": "check-skill-line-ratchet self-test: 111 cases pass." }, { "cmd": "pnpm check:pm-skill-id-lint", "exit": 0, "verdict": "check-skill-id-lint: 23 file(s) clean (pattern /#[0-9]{3,}/g)." }, { "cmd": "pnpm check:pm-governed-prose", "exit": 0, "verdict": "check-governed-prose: 2 instruction surface(s) name all 5 registered governed surfaces and claim no others." }, { "cmd": "pnpm check:nul-bytes", "exit": 0, "verdict": "check-nul-bytes: OK (scanned 8063 text file(s); no raw ASCII control bytes)." }, { "cmd": "pnpm check:corpus-claim-drift", "exit": 0, "verdict": "check-corpus-claim-drift: OK, no new claim sites beside a pinned spelling." }, { "cmd": "node scripts/check-required-contexts.mjs", "exit": 0, "verdict": "check-required-contexts: 6 required context name(s) pinned across 2 workflow(s)." }, { "cmd": "pnpm check:required-contexts", "exit": 0, "verdict": "check-required-contexts --self-test: 150 assertions." }, { "cmd": "pnpm check:agent-test-spelling", "exit": 0, "verdict": "check-agent-test-spelling: 0 violations -- 430 file(s)." }, { "cmd": "pnpm check:docs-audit-scope", "exit": 0, "verdict": "docs-accuracy-audit scope is in sync with content/docs/: 190 hand-written doc(s)." }, { "cmd": "pnpm check:pm-governed-merges", "exit": 0, "verdict": "check-governed-merges --self-test: 243 assertions." } ], "gate_union_derivation": "node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands, re-derived AFTER the last edit. Provenance line: derived from the tree of objectstack-ai/objectstack at commit 796501faa9; --repo checked against this checkout's origin and it holds; change set 1 path (AGENTS.md) vs merge base dee4dd4ba, three-dot semantics. 8 commands printed, all 8 run, all exit 0. It also noted 9 further families that apply once a changeset file exists -- this PR deliberately has none (skip-changeset). No gate answered PREREQUISITE NOT MET or exit 3, so nothing is NOT MEASURED. Every exit code captured by redirect BEFORE any pipe.", "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; no .md/.mdx glob and no markdown processor or plugin. --format json reading for AGENTS.md: errorCount 0, fatalErrorCount 0, single message 'File ignored because no matching configuration was supplied.' Invariance: the diff touches one file, outside the population by extension, no type-aware linting in play for it, so it cannot move a verdict on any untouched file.", "labels": "REST channel probed first and REFUSED (gh absent; repo-scoped REST read returned HTTP 403 'GitHub access is not enabled for this session'), so declaring the switch to the MCP fallback: read current set -> union -> whole-set write -> comparative read-back. Target union {size/s, skip-changeset}; read back {documentation, size/s, skip-changeset}. skip-changeset landed; 'documentation' was added concurrently by automation, an ADDITION not a strip, so nothing from the union was lost.", "pr_state": "Draft true, mergeable_state blocked, no reviewers requested, auto-merge not enabled. PR body read back in full after create -- intact, no sanitizer damage, footer kept the session-URL form (create-only, never re-PATCHed).", "shared_state_disclosure": "I ran `git fetch --unshallow` to answer the dispatch's history question, which mutates the SHARED object store (worktrees share .git), so /home/user/objectstack is no longer a shallow checkout. Additive only -- history objects and tags; no branch ref moved, no working tree touched, no other agent's worktree affected. Disclosed because it is shared state, per the family rule. Side benefit: dispatch-gates.mjs no longer has to refuse on shallowness here.", "cleanup": "Worktree /home/user/objectstack-issue-14647 removed without --force after confirming git status clean and nothing unpushed; node_modules deleted first. Sibling worktrees (issue-14298, issue-14299) untouched.", "mcp_calls": 12, "out_of_scope_findings": [ "CONTAINER TRAP, highest value here -- this checkout is SHALLOW, and `git log -S` on a shallow clone silently reports the HORIZON commit as the introduction of text that is far older: exit 0, a plausible sha, a plausible date, no warning. Both history probes this dispatch prescribed returned horizon commit fab693bee (2026-08-17) until `git fetch --unshallow`; the true answers are 2026-05-30 and 2026-07-21, up to three months earlier. Same 'exit 0 and reads correct' failure class the os-dev doc already catalogues for pipes and zero-match edits, and ANY dispatch asking a dev to date a line of history inherits it. Suggest a line in the os-dev agent text: before trusting `git log -S`/`git log --follow` for a date, check `git rev-parse --is-shallow-repository` and deepen.", "AGENTS.md:1154 (post-task checklist item 6) says 'Update CHANGELOG.md / ROADMAP.md if user-facing or architectural.' CHANGELOG.md is GENERATED by changesets at release time and ships inside the npm package; hand-editing it in a code PR is the same stale-prose-vs-enforced-mechanism class as this very card (un-enforced prose disagreeing with a correct mechanism, so nothing reds). Deliberately NOT touched -- outside the ruled one-sentence scope.", "AGENTS.md carries two different claims about OS_SKIP_DTS: :595-597 says it leaves no .d.ts so `gen:api-surface` cannot run at all, while :1153 says it greens `check:api-surface` locally and reds it in CI. Plausibly both true of different scripts, but they read as one fact stated two ways and are worth one consistency read.", "check:pm-skill-ratchet prints an opportunistic-lowering notice: .claude/skills/spec-property-retirement/SKILL.md max-table-row-bytes headroom is 2, pin lowerable 328 -> 326. Shrink-only ratchet working as designed, informational only; recorded so it is not lost." ] }
Generated by Claude Code
ACCEPT — skills-lane seat (session
session_01LraLgQVGq8egUwfYZpbYt1), reviewer of record, verified against GitHub and the seat's own checkout, not the report.- PR docs(agents): a released-package bug fix takes a patch changeset, never none #14789 exists, is DRAFT, head
796501fa, one file (AGENTS.md), +5 −10; labelsdocumentation·size/s·skip-changeset; noneeds:contract-review(process text). - Diff read by the seat: item 3's lead
Add a changeset for feature work→Add a changeset for anything that publishes; the sentencePure bug fixes do **not** require a changeset.is replaced by the two ruled things — a bug fix in a released package takes apatchchangeset, never none, and ⛔ neverskip-changeset, whose criterion (publishes nothing from any released package) is stated in the same breath. The middle clause (runpnpm changeset, or add a.changeset/*.mdentry, before committing) is untouched, as is the breaking-changeset paragraph. - Triage's reading confirmed, refined: the sentence landed 2026-05-30 (
43625fbd6c) whenCheck Changesetonly warned; it became blocking 2026-06-11 (a1251e4737) and began counting changesets ADDED BY THE PR on 2026-07-21 (8ff9210947). Either gloss yields the same replacement text — noneeds_decisionwas owed.⚠️ Those dates were reachable only aftergit fetch --unshallow: the shallow checkout reported the horizon commit for both probes, exit 0, no warning — now [finding] In the agent containers' shallow checkout,git log -Sreports the horizon commit as the introduction of far older text — exit 0, plausible sha, plausible date, no warning — and the os-dev contract carries no guard for dating history #14793. - Payment, judged by the seat: the eight-line "Why it is asked of you at all" ADR-0087 rationale (
:1136-1143) is replaced by one line in the file's own idiom (the gate prints the argument when it fails — that output is the authority). Seat verified at89a156af88:scripts/check-adr-0087-registration.mjs:2976-2996prints that argument verbatim on failure (synchrony, pure projection, a never-written entry leaves every gate green, the ledger as the sole channel to an upgrader, no tombstone for a schema-less surface, ~1 in 7,not-requiredordinary); theno-migration-prescriptionrefusal is at:227/:2633. The four marker spellings and the sentence naming the gate stay. Rules unchanged; the rationale moved to where the reader meets it. Accepted as a strict restatement under the file's line ceiling. - Line arithmetic, seat-measured: 1,162 → 1,157 lines (ceiling 1,162; headroom 5); edited lines 115 / 110 / 112 / 37 / 110 bytes, all ≤ 120; widest-table-row pin 1,081 untouched.
grep -c 'Pure bug fixes do'1 → 0;skip-changeset0 → 1 inAGENTS.md. - CI at
796501fa: every one of the 29 check runs is success or skipped — 28 read at 2026-09-03T01:46Z (the fourType Checklegs,Test Core,Check Changesetsuccess,Governed Surface Queue Guard(draft — correct),Check Documentation Links, the three claim guards) andLint & Repo Gatessuccess read at 01:57Z. - Shared-state disclosure accepted: the flight ran
git fetch --unshallowon the shared object store — additive only; the seat's checkout now readsis-shallow-repository = false. - Three findings recorded: [finding]
AGENTS.md:1154post-task checklist tells the author to "UpdateCHANGELOG.md" by hand — butCHANGELOG.mdis generated from changesets at release and ships inside the npm package #14792 (AGENTS.md:1154hand-editCHANGELOG.md), [finding] In the agent containers' shallow checkout,git log -Sreports the horizon commit as the introduction of far older text — exit 0, plausible sha, plausible date, no warning — and the os-dev contract carries no guard for dating history #14793 (the shallow-clonegit log -Strap; the os-dev contract silent on it), and on the ledger:OS_SKIP_DTSstated two ways (:595-597vs:1153); thespec-property-retirement/SKILL.mdrow pin lowerable 328 → 326 (informational). - Governed
AGENTS.md⇒ stays DRAFT; review requested from os-zhuang + hotlong; human merge is the record. At MERGED the seat stripspm:dispatched(Fixes⇒ the card closes).
Generated by Claude Code
- PR docs(agents): a released-package bug fix takes a patch changeset, never none #14789 exists, is DRAFT, head
MERGED — PR #14789 @
796501falanded onmainas5a5336b399(queue commit 02:04:10Z; this card closed by os-zhuang 2026-09-03T03:08:46Z). Session:session_01LraLgQVGq8egUwfYZpbYt1pm:dispatchedstripped now (labels after:documentation·priority:p2·domain:skills), read back after the write. Nothing deferred remains:AGENTS.md:1117now says both ruled things, and the ADR-0087 rationale paragraph moved to the gate's own failure output.- Hot-file consequence:
AGENTS.mdis now 1,157 lines onmain(headroom 5); PR docs(agents): stop telling authors to hand-edit generated CHANGELOG.md #14802 ([finding]AGENTS.md:1154post-task checklist tells the author to "UpdateCHANGELOG.md" by hand — butCHANGELOG.mdis generated from changesets at release and ships inside the npm package #14792,:1154) is disjoint and mergesmainin if GitHub reports it dirty. [finding]AGENTS.md:1154post-task checklist tells the author to "UpdateCHANGELOG.md" by hand — butCHANGELOG.mdis generated from changesets at release and ships inside the npm package #14792's triage note that headroom was 0 "today" is now stale in the other direction — the byte-negative edit there needed no budget either way. - Read at 2026-09-03T03:14Z by the seat's patrol (
git log --grep '(#14789)'onorigin/main5a5336b399).
Generated by Claude Code
Recorded by the skills lane seat (session
session_01LraLgQVGq8egUwfYZpbYt1) from the #13680 flight's follow-up section (PR #14621), which measured it while aligning theskip-changesettexts and left it for the seat to file. Unassigned — recording only, for triage. ⛔ Not touched by that flight:AGENTS.mdis an anchor it may not edit.What
AGENTS.md:1116-1117(atorigin/main2514d49f) states, in the changeset section:Two other texts disagree with it, and both are enforced:
Check Changeset(pr-automation.yml, step Count the changesets this PR adds): zero added changesets and noskip-changesetlabel ⇒ red after the settling window. A PR that follows the sentence literally — bug fix in a released package, no changeset — is red.skip-changesetcriterion (now stated as the rule by the os-dev clause, PR docs(os-dev): the skip-changeset clause states its criterion as the rule and its list as examples; dispatch-gates prints the same criterion (#13680) #14621; the label's description;scripts/check-empty-changeset.mjs's enumeration): the label is for a diff that publishes nothing from any released package. A bug fix in a released package publishes something, so the label is not its exemption either.⇒ For a pure bug fix in a released package there are three readings and no green one under the sentence: no changeset (red), the label (a false declaration), or a
patchchangeset (what every merged bug-fix PR actually carries — which is what the sentence says is not required).Likely resolution, not a decision
The sentence probably predates the gate and meant "no minor bump": a bug fix takes a
patchchangeset, not none. One sentence inAGENTS.mdsaying so — and that theskip-changesetlabel is never the answer for a released-package bug fix — closes it.AGENTS.mdis governed and at its line ceiling (#11910 records the payment question), so the fix is a skills-lane draft PR with same-file payment.Verified
AGENTS.mdcarries 0 occurrences ofskip-changeset(measured in the [finding] The os-devskip-changesetclause states a CLOSED surface list that omits repo-root tooling config — the criterion beside it, and the repo's own merged precedent on the SAME file, both cover it #13680 flight) — it neither states the label rule nor the closed list; only this sentence is at odds with the gate.search_issues(56 results) returned no card for this; the control hits were [finding] The os-dev contract statesskip-changesetas BOTH a closed path list and a publication test — asrc/file that never reachesdistsatisfies one and violates the other #13432 and The os-dev contract says skip-changeset "does not exist" in objectui — the label object DOES exist and nothing reads it, so an agent that verifies the claim will draw the wrong conclusion #12226, both about theskip-changesetlist, not the bug-fix sentence.Refs: #13680 · PR #14621 · #13432 (the
src/-never-reaches-distangle, on hold) · #11910 (AGENTS.md line-ceiling payment).