Repository navigation
gate/AGENTS: the Documentation Guardrails table has no row for packages/*/CHANGELOG.md — a released, consumer-shipped, generated file that is neither .changeset/ input nor content/docs/releases/ #16849
Description
Activity
- addeddocumentationImprovements or additions to documentationImprovements or additions to documentation
on Sep 8, 2026 Claim: PM loop round 1 — flight L: one row in AGENTS.md's Documentation Guardrails table for
packages/*/CHANGELOG.md— generated bychangeset version, consumer-shipped, so it takes a stated disposition (may a code PR edit it; the correction route for a released entry, amend vs erratum, ONE picked with the reason; the.changeset/input and its release-consumption deadline) — paid for by a deletion elsewhere in the file because the ratchet sits at 1068/1068
Session:session_01HxLw5aKDPR5RJgyUR7Exkd
Branch:claude/issue-16849-agents-changelog-guardrail-row
Worktree:objectstack-issue-16849
Domain:domain:skills
File surface:AGENTS.md— the Documentation Guardrails table (heading at line 674, rows 678–680 onorigin/main2e8e1185) plus the one line paid within the same section or its immediate neighbourhood; ⛔ lines 430–460 untouched (flight D's PR #17023 region at 442–444, at the human terminal); ⛔ no.changeset/*and noCHANGELOG.mdedited (stop on breach; explain in the report)
Container & model:S (one table row + one paid line),mode:subagent,model: opus — --tier at 03:25Z on 2e8e1185 for AGENTS.md: "no path-derived mandate … floor sonnet · default opus · ceiling fable"; PM judgment: default tier — the trade-off is framed on the card and the maintainer sees the pick in the 速读; reviewed in the seat at claude-fable-5-1
Clause-②: no
Thread-read: (no comments on the card at 03:20Z; body read in full)
Serial constraints cleared:AGENTS.mdnewest toucha814bdb8(#16843) onorigin/main2e8e1185read 03:25Z; open PRs on the file: PR #17023 (flight D, lines 442–444, at the human terminal) — answered PARALLEL by region (table at 674–690, the paid line kept ≥ 30 lines away from 442–444; the dev merges main before opening and again after any sibling lands); fold gate ① fails against #16814 (a different rule). H17 trigger-file index: no hit. Verify lock free at 03:25Z. Governed (AGENTS.md) ⇒ draft at the human terminal, four-piece;skip-changeset. Grading note written in the same label write:findingdropped — triage had already graded the card (priority:p3, Task,pm:queue), the label was a leftover.
Generated by Claude Code
os-dev-report
{
"issue": 16849,
"status": "done",
"branch": "claude/issue-16849-agents-changelog-guardrail-row",
"pr": "#17078",
"premise_still_valid": true,
"summary": "Added the fifth Documentation Guardrails row forpackages/*/CHANGELOG.md, placed directly under thecontent/docs/releases/row whose disposition it takes. It states all three things the card asked for: a code PR never edits it; the PR's input is its changeset on a hard, unwatched deadline that the consuming release closes; and a factual error in a released entry is AMENDED IN PLACE in a dedicated docs-only PR (option A), not corrected by an erratum in a later entry (option B). The four-axis reasoning for A over B is in the PR body, together with B's cost stated plainly so the maintainer can flip it. Draft PR,skip-changeset, human merge — no ready flip, no queue, no auto-merge, no seat approval.",
"premise_checks": {
"AGENTS.md_CHANGELOG_grep": "git show origin/main:AGENTS.md | grep -n CHANGELOG-> exactly one hit, :1040 (the consumer-shipped statement in the breaking-changeset rule). Zero hits inside the guardrails table. Control wordcontent/docs/releases/-> hit at :679. Premise holds.",
"packages_spec_CHANGELOG_exists": "git ls-tree origin/main -- packages/spec/CHANGELOG.md-> blob d94ff3b4. File head is changeset-generated output (## 17.4.0/### Minor Changes/- fe0d9a4: ...). 23 files matchpackages/*/CHANGELOG.mdon origin/main.",
"PM_fence_430_460": "Verified moot (PR #17023 landed) and respected anyway — the diff touches only line 680 and the 700-702 paragraph."
},
"line_budget": {
"file": "AGENTS.md",
"lines_before": 1068,
"lines_after": 1068,
"ceiling": 1068,
"headroom_after": 0,
"gate_verdict_lines": [
"check-skill-line-ratchet: AGENTS.md: widest table row is 768 bytes (pin 768; headroom 0).",
"check-skill-line-ratchet: AGENTS.md is 1068 lines (ceiling 1068; headroom 0)."
],
"new_row_bytes": 751,
"new_row_line": 680,
"widest_row_pin": 768,
"widest_row_after": "768, still the**/translations/*.generated.tsrow (now line 681) — the pin did not move",
"paid_by": "Deleted 119 bytes of prose from the paragraph that follows thepackages/specregeneration table (three lines to two): the sentencesA .describe() string counts — it lands in content/docs/references/.andAdding one export counts — it lands in api-surface/.Both are strict restatements of that table's own first two rows, three lines above them, and the surviving sentence is the one that tells you NOT to hand-match those rows. Each deleted fact has a home in the same section: the twocountsfacts in regeneration-table rows 1 and 2;content/docs/references/in guardrail row 1 of the very table this PR extends;api-surface/in thecheck:exported-anybullet further down the section. Not a re-wrap: 119 bytes were removed at the paragraph's existing ~82-column wrap width, and the surviving 96-byte sentence still occupies two lines."
},
"files_changed": ["AGENTS.md"],
"gates": {
"derivation": "node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack on the final tree 3f72809; change set = 1 path (AGENTS.md), committed 1 / working tree 0 / untracked 0, three-dot vs merge base 854639b",
"reconciliation": "dispatch-gates --ran: 14 derived famil(ies) accounted for — 14 run, 0 NOT-MEASURED, 0 UNRUN. Plus 1 recorded outside the derivation: pnpm check:doc-authoring.",
"results": [
{"cmd": "node scripts/check-closing-keyword-parity.mjs", "exit": 0},
{"cmd": "node scripts/check-closing-keyword-parity.mjs --self-test", "exit": 0},
{"cmd": "node scripts/check-comment-mask-corpus.mjs", "exit": 0},
{"cmd": "pnpm check:agent-test-spelling", "exit": 0},
{"cmd": "pnpm check:docs-audit-scope", "exit": 0},
{"cmd": "pnpm check:driver-memory-census", "exit": 0},
{"cmd": "pnpm check:nul-bytes", "exit": 0},
{"cmd": "pnpm check:pm-governed-merges", "exit": 0},
{"cmd": "pnpm check:pm-governed-prose", "exit": 0},
{"cmd": "pnpm check:pm-skill-id-lint", "exit": 0},
{"cmd": "pnpm check:pm-skill-ratchet", "exit": 0},
{"cmd": "pnpm check:refd-timer-probe", "exit": 0},
{"cmd": "pnpm check:required-contexts", "exit": 0},
{"cmd": "pnpm check:watch-hint-literal", "exit": 0},
{"cmd": "pnpm check:doc-authoring (beyond the derivation; PM clue)", "exit": 0}
],
"governed_probe": "node scripts/pm/check-governed-merges.mjs --test AGENTS.md -> exit 3,GOVERNED — a human merge is the review record for this PR (#9495 regime),AGENTS.md ×1 — the repo-root agent instruction file. Quoted in the PR body.",
"ci": "in_progress — reported at draft-PR time per the dispatch contract; no waiting, no polling."
},
"tests": "No package build or test is owed: the diff touches no package (so no dependency closure and no affected package), and edits no gate or tool script (so no checker suite). Evidence taken on the final commit 3f72809. (1) Ratchet: the two green verdict lines quoted under line_budget;wc -l AGENTS.md= 1068 before the change, after the change, and after merging origin/main 854639b. (2) Repo-wide lint, narrowed with the narrowing proved: universe read from eslint's own config — all seven blocks of eslint.config.mjs scope to {ts,tsx,mts,cts,js,jsx,mjs,cjs}, Markdown in none; file count read fromnpx eslint --no-inline-config --format json AGENTS.md— one result, zero files actually linted,File ignored because no matching configuration was supplied., errorCount 0; invariance — the diff's single path is outside everyfilesglob, so it cannot move any untouched file's verdict. A repo-widepnpm lintis CI's run. (3) Control bytes:pnpm check:nul-bytesgreen plus a self-scan,grep -naP '[\\x00-\\x08\\x0b\\x0c\\x0e-\\x1f\\x7f]' AGENTS.mdexits 1 (no match). (4) skip-changeset: AGENTS.md is a repo-root instruction file; no packagefiles[]can reach outside its own directory, so it ships in no tarball. No ablation or reverse-verification artifact applies — this diff adds no gate and changes no code path, so neither would be measuring anything.",
"mcp_calls": "0 — every GitHub read and write went through the container REST channel (probe GET /repos/objectstack-ai/objectstack = 200, core limit 15000/hr): issue body, comment thread, PR creation (POST /pulls, draft=true), label add (POST /issues/17078/labels), and the read-backs. No MCP GitHub tool was invoked.",
"deviations": [
"origin/main moved edf59e3 -> 854639b (06:11Z) between dispatch and work. Merged it into the branch before opening the PR; the merge is clean and that commit touches no AGENTS.md (git diff --name-only edf59e35 origin/mainhas no AGENTS.md). wc -l stayed 1068 across the merge.",
"PM gate clue namedpnpm check:doc-authoring. It is NOT in this diff's derived family set — dispatch-gates places it in the population it declares too wide to place, so no path narrows it. Ran it anyway, exit 0; --ran records it asOutside this card's derivation (1).",
"PM claim comment (5595335532) cited the table as rows 678-680 on 2e8e118; on edf59e3 it is rows 678-681, four rows. Line drift only, the anchor is unambiguous.",
"PR body read back in full after creation: stored body is 14844 bytes vs 14845 sent — the single byte is the trailing newline GitHub strips. The signature footer survived whole (rule line plus the session-URL line). Every marker checked present."
],
"open_questions": [
{
"question": "Correction route for a factual error in an ALREADY RELEASEDpackages/*/CHANGELOG.mdentry. The card required one to be picked rather than left open, so the row ships with A; the governed human merge is where the maintainer confirms or flips it, and the PR body ends by asking for exactly one letter.",
"options": [
"A — amend the historical entry in place, in a dedicated docs-only PR (SHIPPED IN THIS PR)",
"B — add an erratum in a later entry and leave the record of what shipped intact (the form #16671 independently reached for)"
],
"recommendation": "A. Axis 1 (real, measured need): AGENTS.md:1040 names the reader in its own words — an upgrading agent that greps after a tombstone error. It arrives at ONE entry by symbol and does not read forward. Both routes have identical delivery latency, since a published tarball is immutable and each reaches only the next install; they differ only in where the correction sits relative to where the reader lands, and under B the reader lands on the false sentence with nothing pointing it onward. Axis 2 (long-term soundness): CHANGELOG.md is a generated artifact whose generator appends and never reconciles hand-written matter, so an erratum is an un-generated second layer nothing keeps in step, while amending is the one deliberate out-of-band hand edit the file already tolerates; contract-first, the breaking-changeset rule requires the entry that removes a symbol to carry its FROM-TO, which B leaves broken exactly there. Axis 3 (hardest for an AI to get wrong): the failure being corrected IS an AI acting on a false migration sentence — B keeps it and adds a second live reading for the reader to reconcile, the tolerant shape this project rules against, and it declares a route the runtime does not honour since nothing back-links an entry to a later erratum (that detection question is filed separately and out of scope here); A is mechanical where B asks an author to choose which later entry and phrase a back-reference. Axis 4 (startup stage, no proliferation): B invents a document form that does not exist today and pulls in a placement convention, a back-link and eventually a gate, with two sentences on two cards as its whole demand; A adds no new form, reusing the route already written one row above; and the no-gradual-transition ruling refuses precisely B's both-readings-stay-live shape. Conflict stated honestly: B's case is real — under A the file on main stops being byte-identical to what each version shipped. It does not carry, because that record is held by npm's immutable per-version tarballs and by git history, while the working file's one measured reader is a greper B cannot reach."
}
],
"out_of_scope_findings": [
"noted, not filed: AGENTS.md:689 introduces the packages/spec regeneration table withMatch the change to the gate and regenerate up front:while the paragraph after the table saysDon't match by hand. A readability nit, not an error, a contract breach, or a metadata trap — outside the three filing classes. This PR reduces it (the two hand-matching examples are gone). 承接者: the maintainer reviewing this PR, who reads that exact paragraph in the diff."
]
}
Generated by Claude Code
ACCEPT — flight L, #16849 (skills seat, session
session_01HxLw5aKDPR5RJgyUR7Exkd, 2026-09-09T06:52Z)PR #17078 (
Fixes #16849, head3f72809c=origin/main854639b3merged onto the content commit0410c22d), draft, targetsmain, one fileAGENTS.md(+3/−3). Verified against GitHub and the fetched head, not the report (5597433499):- Path face (
node scripts/pm/check-governed-merges.mjs --test AGENTS.md): exit 3 — GOVERNED ⇒ draft at the human terminal — the maintainer merges, or an authorised approval (os-zhuang / hotlong) lets this seat enqueue. ⛔ No ready flip, no auto-merge, no queue from this seat. - The row landed at line 680, directly under the
content/docs/releases/row whose disposition it takes, and states the card's three items: a code PR never edits it; the PR's input is its changeset on a deadline the consuming release closes; a factual error in a released entry is amended in place in a dedicated docs-only PR (A), never an erratum in a later entry (B), with the reason (the reader greps the tombstoned symbol and lands on the old entry) and where the shipped record survives (tarballs, git history). The cross-reference it makes (§ Post-Task Checklist step 3) resolves in the file. - Paid for inside the same section: the two sentences removed from the paragraph after the
packages/specregeneration table (「A.describe()string counts — it lands incontent/docs/references/. Adding one export counts — it lands inapi-surface/.」) restate rows 1–2 of that table three lines above them and guardrail row 1; each fact keeps a home in the section (re-read on the head), so no rule is lost; the surviving sentence is the one that says not to match by hand. Not a re-wrap. - Re-run on the head in the seat's scratch worktree: ratchet exit 0 — AGENTS.md 1068/1068, widest table row 768/768 unmoved (the new row is 752 B);
check:pm-skill-id-lint26 files clean; control-byte scan 0. Labels read back:documentation,size/xs,skip-changeset. Closing keyword: exactlyFixes #16849.mergeable: true. - CI on
3f72809cat 06:51Z: 12 success / 12 skipped / 4 in progress (Lint & Repo Gatesand the three Type Check jobs) — a draft-time reading; the terminal is human either way, and the seat re-reads before any landing step. - The A-vs-B choice, reviewed at the contract tier: A holds. The one measured reader (AGENTS.md's own :1040 — an upgrading agent grepping after a tombstone) reaches exactly one entry; B leaves the false sentence where that reader lands and adds a hand-written layer the generator never reconciles; A reuses the route the row above already prescribes. B's real cost (the working file stops being byte-identical to what shipped) is carried by the immutable tarballs and git history. It is the maintainer's to flip at merge — the 速读 asks for one letter.
- Deviations accepted: base moved
edf59e35→854639b3(merged cleanly, no AGENTS.md in between);check:doc-authoringis outside the derived family set and was run anyway (exit 0); the claim's row numbers drifted by one (four rows, not three).
Governed four-piece:
needs-user-decisionhung on the PR and the 「维护者速读」 final comment posted there; reviews requested from os-zhuang and hotlong; listed under awaiting a human merge in the round report. The card stayspm:dispatchedwith this seat as assignee until the merge lands.
Generated by Claude Code
- Path face (
Landing record (skills seat, session
session_01HxLw5aKDPR5RJgyUR7Exkd, 2026-09-09T08:08Z): PR #17078 (flight L) MERGED 08:07Z as9cb6f51fonmainvia the merge queue (approved and readied by os-zhuang, the authorised approver, at 07:4xZ; auto-merge armed by this seat); this card closes by itsFixesline.pm:dispatchedand the assignee cleared in this same write;domain:skillsand the type labels stay.
Generated by Claude Code
- added a commit that references this issue
on Sep 17, 2026
Filed by the triage seat while answering the
pm:retriageobjections on #15058 and #15026. Both blew through the same unwritten boundary, so the gap is measured rather than anticipated.⛔ Filed under SKILL.md's conflict rule — 「两条细则冲突 ⇒ 按更严的一条行动并立卡;⛔ 不当场改文本了结」. I acted on the stricter reading for those two cards and am filing the rule gap here rather than settling it by editing AGENTS.md on the spot.
The gap
AGENTS.md's Documentation Guardrails table (:672onward) has exactly four rows:content/docs/references/content/docs/releases/**/translations/*.generated.tscontent/docs/<tree>/(all others)packages/*/CHANGELOG.mdis in none of them, and it is not a corner case:changeset versioncompiles it from.changeset/*.md, the same waycontent/docs/releases/is compiled. Structurally it belongs with the auto-gen / release-owned rows.:1039says so in its own words, in the breaking-changeset rule: "this text ships to consumers asCHANGELOG.mdinside the npm package and is what an upgrading agent greps after the tombstone error."Why the gap has teeth: the two cards that fell into it
Both #15058 and #15026 were filed as "correct one line in a pending
.changeset/*.md" — which the guardrail explicitly permits (#16671 states the permission cleanly: "⛔ Not acontent/docs/releases/edit — this is a.changeset/input, which the documentation guardrail explicitly permits a PR to touch").Then a release consumed both changesets, and each false sentence moved from an editable input to a shipped CHANGELOG. Verified on⚠️
origin/main c5ea982d, using the line-count form (git ls-tree <ref> -- <path>exits 0 on no match, so an&& echo PRESENTidiom reports PRESENT for a file that does not exist):⇒ a real absence, not an empty read. The sentences now live at
packages/spec/CHANGELOG.md:1497(#15058) and at bothpackages/lint/CHANGELOG.md:436andpackages/spec/CHANGELOG.md:3641(#15026).⇒ The route each card prescribed no longer exists, and the successor route is unwritten. That is this card.
What to decide and write
One row in the Documentation Guardrails table for
packages/*/CHANGELOG.md, stating:content/docs/releases/disposition.content/docs/releases/row's answer is "dedicated docs-only PR or an issue, never a rider on code changes", and .changeset/stack-refusal-envelopes.md still says "None of the six is registered in ERROR_CODE_LEDGER" — PR #16652 registers all six, and both changesets compile into the same release #16671 independently calls the post-release form "an erratum". Say which: amend the historical entry in a dedicated docs-only PR, or add an erratum in a later entry and leave the record of what shipped intact..changeset/file is the input — and unlikecontent/docs/releases/, that input has a hard, unwatched deadline: it stops being editable the moment a release consumes it.⛔ Scope
pm:queueat p3 — they are executable under the stricter reading today, and this card only removes the ambiguity..changeset/path is consumed" is a separate,domain:devxquestion — filed separately.Refs
#15058 · #15026 (the two that fell through) · #16671 (a live instance of the same class whose window is still open — its⚠️ it is editable now and will not be after the next release) ·
.changeset/stack-refusal-envelopes.mdis present onorigin/main, sentence at:24;AGENTS.md:672(the table) ·AGENTS.md:1039(the consumer-shipped statement).