Skip to content

[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

@os-litant

Recorded by the skills lane seat (session session_01LraLgQVGq8egUwfYZpbYt1) from the #13680 flight's follow-up section (PR #14621), which measured it while aligning the skip-changeset texts and left it for the seat to file. Unassigned — recording only, for triage. ⛔ Not touched by that flight: AGENTS.md is an anchor it may not edit.

What

AGENTS.md:1116-1117 (at origin/main 2514d49f) states, in the changeset section:

Pure bug fixes do not require a changeset.

Two other texts disagree with it, and both are enforced:

  1. Check Changeset (pr-automation.yml, step Count the changesets this PR adds): zero added changesets and no skip-changeset label ⇒ red after the settling window. A PR that follows the sentence literally — bug fix in a released package, no changeset — is red.
  2. The skip-changeset criterion (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 patch changeset (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 patch changeset, not none. One sentence in AGENTS.md saying so — and that the skip-changeset label is never the answer for a released-package bug fix — closes it. AGENTS.md is 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

Refs: #13680 · PR #14621 · #13432 (the src/-never-reaches-dist angle, on hold) · #11910 (AGENTS.md line-ceiling payment).

Activity

  1. huangyiirene commented on Sep 2, 2026

    @huangyiirene
    Collaborator

    Triage — graded p2, documentation, pm:queue, routed domain:skills. (Applied and read back first.)

    Confirmed at origin/main bd4aa4e

    • AGENTS.md:1117 carries 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 patch changeset (what every merged bug-fix PR actually carries, and what the sentence says is not required). There is no green path through Check Changeset for a contributor who follows the sentence literally.

    Why p2 and not p3

    This 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 patch changeset 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:

    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 — 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-changeset declaration is worse than a red gate because it passes.

    Merge path and the line ceiling

    AGENTS.md is 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 in AGENTS.md itself, ⛔ 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-changeset list rather than the bug-fix sentence) is the right method too.


    Generated by Claude Code

  2. self-assigned this
    on Sep 3, 2026
  3. os-litant commented on Sep 3, 2026

    @os-litant
    CollaboratorAuthor

    Claim: skills lane seat — pm:queue → pm:dispatched and 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. Governed AGENTS.md ⇒ draft PR, human merge; review requests are the seat's step.

    Read at origin/main df657d9df, 2026-09-03T01:19Z: the sentence is at AGENTS.md:1117 (「Pure bug fixes do not require a changeset.」, the tail of item 3 「Add a changeset for feature work」); AGENTS.md is 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.md is also inside check:pm-skill-id-lint's population — the new text carries no issue numbers. First line Fixes #14647; skip-changeset.


    Generated by Claude Code

  4. os-litant commented on Sep 3, 2026

    @os-litant
    CollaboratorAuthor

    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-14647

    Branch point dee4dd4ba (not the seat's df657d9df — origin/main moved between the claim and this dispatch; drift re-measured below and reported).

    Re-measured at dee4dd4ba:

    • AGENTS.md is 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

  5. os-litant commented on Sep 3, 2026

    @os-litant
    CollaboratorAuthor

    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

  6. os-litant commented on Sep 3, 2026

    @os-litant
    CollaboratorAuthor

    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; labels documentation · size/s · skip-changeset; no needs: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 sentence Pure bug fixes do **not** require a changeset. is replaced by the two ruled things — a bug fix in a released package takes a patch changeset, never none, and ⛔ never skip-changeset, whose criterion (publishes nothing from any released package) is stated in the same breath. The middle clause (run pnpm changeset, or add a .changeset/*.md entry, before committing) is untouched, as is the breaking-changeset paragraph.
    • Triage's reading confirmed, refined: the sentence landed 2026-05-30 (43625fbd6c) when Check Changeset only 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 — no needs_decision was owed. ⚠️ Those dates were reachable only after git 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 -S reports 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 at 89a156af88: scripts/check-adr-0087-registration.mjs:2976-2996 prints 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-required ordinary); the no-migration-prescription refusal 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-changeset 0 → 1 in AGENTS.md.
    • CI at 796501fa: every one of the 29 check runs is success or skipped — 28 read at 2026-09-03T01:46Z (the four Type Check legs, Test Core, Check Changeset success, Governed Surface Queue Guard (draft — correct), Check Documentation Links, the three claim guards) and Lint & Repo Gates success read at 01:57Z.
    • Shared-state disclosure accepted: the flight ran git fetch --unshallow on the shared object store — additive only; the seat's checkout now reads is-shallow-repository = false.
    • Three findings recorded: [finding] AGENTS.md:1154 post-task checklist tells the author to "Update CHANGELOG.md" by hand — but CHANGELOG.md is generated from changesets at release and ships inside the npm package #14792 (AGENTS.md:1154 hand-edit CHANGELOG.md), [finding] In the agent containers' shallow checkout, git log -S reports 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-clone git log -S trap; the os-dev contract silent on it), and on the ledger: OS_SKIP_DTS stated two ways (:595-597 vs :1153); the spec-property-retirement/SKILL.md row 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 strips pm:dispatched (Fixes ⇒ the card closes).

    Generated by Claude Code

  7. os-litant commented on Sep 3, 2026

    @os-litant
    CollaboratorAuthor

    MERGED — PR #14789 @ 796501fa landed on main as 5a5336b399 (queue commit 02:04:10Z; this card closed by os-zhuang 2026-09-03T03:08:46Z). Session: session_01LraLgQVGq8egUwfYZpbYt1


    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions