docs(agents): record how GitHub mangles agent-written bodies, and the per-query search control (#6970) - #7317

Merged
os-zhuang merged 2 commits into
mainfrom
claude/issue-6970-github-body-mangling-rules
Sep 2, 2026
Merged

docs(agents): record how GitHub mangles agent-written bodies, and the per-query search control (#6970)#7317
os-zhuang merged 2 commits into
mainfrom
claude/issue-6970-github-body-mangling-rules

Conversation

@yinlianghui

@yinlianghuiyinlianghui commented Sep 2, 2026

Copy link
Copy Markdown
Collaborator

Fixes#6970
Fixes#6452
Part of #7185 (option A only — the diagnosis half, option B, stays open on that card by its author's instruction; changed from a closing line by the PM seat after the dev flagged it)

One governed edit to AGENTS.md (46 added lines, no deletions), folding three devx cards that all land in the same instrument-discipline area of the file. One authoritative wording beats three riders.

What landed, and where

Two clauses, inserted between the existing control/measurement subsections and the governed-surface section:

  • #### 对照挂在通道上,不只挂在查询上 — AGENTS.md lines 401-414. The channel-control rule. The control belongs on the CHANNEL, not only on the query, and it is run PER query: a non-empty result is self-validating and needs no control, an empty one ALWAYS needs a known-must-hit control. Recorded with the measured asymmetry — a long, near-verbatim title query returned total_count: 0 for an issue that reads fine directly, while a short keyword query in the same container within the same hour returned 3 hits — so the rule reads "never trust an empty search without a control", not "never use search". The zero-quota web payload channel is recorded as the measured fallback, under the same control requirement and with the caveat that it is one day in one container, not a permanent answer.
  • ### GitHub 会改写你写进 issue/PR 正文的字节 — AGENTS.md lines 416-445. The mangling enumeration, one line per class, plus the four mitigations measured working, plus the placeholder clause described below.

Both sit inside section 9's measurement/instrument area, immediately before the governed-surface section.

The six classes, one line each

  1. Tag-shaped fragments stripped on save, including inside backticks and fences, and an HTML-comment marker alone on a comment's first line (first-line placement is not protection).
  2. PATCH downgrades the session-URL attribution footer to the bare form.
  3. PATCH appends a second footer unconditionally — measured at exactly +58 bytes, with the unified diff being only the appended lines, so this one adds rather than removes.
  4. issue_write create strips the attribution footer block entirely. Sentinel proof: tail kept, middle deleted, so it is a targeted strip and not a truncation — without the sentinel the only available conclusion points at length limits, which is the wrong direction.
  5. PR create normalises a bare footer to the session-URL form, so create-then-edit loses the session reference altogether; and the id carried there is the seat's, not the implementer's.
  6. The linked-issue parser ignores negation — a negated keyword sitting next to a card reference still acts at merge time. Recorded safe forms: Part of, Refs:, Related:, and the bare objectui prefix form, plus a pre-open grep of your own body for the three keyword stems near a hash.

Mitigations recorded as measured: generics and placeholders written in words, the session URL carried in prose as a backticked code span, attribution written as prose on issue bodies, and a read-back to the tail with an angle-bracket count after every publish.

The placeholder clause

Landed as the triage ruling asked: a SHORT objectui clause plus a pointer to the objectstack AGENTS.md wording rather than a copy of it, so there is one authoritative text and no duplicated prose to drift. It states explicitly that placeholders in ordinary prose and in fenced code are covered — the case that was actually measured — and it carries the load-bearing caveat verbatim:

A body reading short only through the API is probably intact — check the rendered page before "repairing" it; a rewrite destroys a correct card.

I did not judge the upstream wording to need widening, so no objectstack skills-lane card is filed. The pointer plus the explicit placeholder sentence covers the measured case without touching the upstream text.

Deliberately not built here

Named as options only, per the dispatch:

  • a shared publish helper that reads back and diffs automatically, making the check mechanical rather than remembered;
  • a check that scans recent agent-authored bodies for the tells (identical before/after columns, a doubled footer).

Also not attempted: the diagnosis of why the issue-search path goes blind. The clause records it as unresolved, naming both candidate causes and the point that only one of them self-heals. That diagnosis is the half of #7185 this PR does not close.

Governance

AGENTS.md is a governed surface. node scripts/check-governed-queue-guard.mjs --test AGENTS.md exits 3, which is the correct verdict for this PR:

One governed path governs the WHOLE pull request — proportion is not a question.

This PR therefore stays a DRAFT with hotlong and os-zhuang requested. Not flipped ready, not enqueued, no auto-merge.

Verification, all on head 3083d3e

gateverdict
pnpm check:control-bytesexit 0 — "OK (scanned 6014 tracked text file(s); skipped 85 binary)"
node scripts/check-shell-escape-residue.mjsexit 0 — "OK (4/4 root(s) resolved -- AGENTS.md: 1 file(s), 15 fence(s) ...)"
node scripts/check-governed-queue-guard.mjs --self-testexit 0 — "132 cases pass"
node scripts/check-governed-queue-guard.mjs --test AGENTS.mdexit 3 — expected, quoted above
node scripts/check-changeset-presence.mjsexit 0 — "No source or published contract of a released package changed in this range, so no changeset is owed."
pnpm docs:check-linksexit 0 — "Links are valid across 17 scan roots."
vitest, the 4 suites that read AGENTS.md from diskexit 0 — 4 files, 157 tests passed

The four suites are scripts/__tests__/check-doc-links.test.ts, check-governed-queue-guard.test.ts, check-shell-escape-residue.test.ts and site-next-agent-files-4160.test.ts, run from the repo root. A scan of scripts/ found no line ratchet or line budget over AGENTS.md; check-doc-links carries the file with the disk rule, and the file has no markdown links at all because its paths are code spans, which the checker blanks — the new text keeps that convention.

Merge-tree proofs, both exit 0, each producing a tree oid with no conflict block:

  • against origin/main
  • against PR 7242's head e362056bf, the other open claim on this file. It adds one line to a different section (the multi-agent discipline bullets under section 9); this edit is 130 lines below it.

Card 6325, listed as a possible placement constraint, is CLOSED (completed 2026-08-27) and constrains nothing here. origin/main was merged in, never rebased; the diff against main is still exactly the 46-line addition.

Session reference, carried here as prose because the footer form is not durable across a body edit: https://claude.ai/code/session_01BGMDbrVa8JjZcCQ7DWYH1b

🤖 Generated with Claude Code

https://claude.ai/code/session_01BGMDbrVa8JjZcCQ7DWYH1b

… per-query search control
Two clauses in the instrument-discipline area of AGENTS.md:
- a channel-level control rule: the control belongs on the CHANNEL, not only
on the query, and it is run per query. A non-empty result is self-validating;
an empty one always needs a known-must-hit control. The zero-quota web
payload channel is recorded as the measured fallback under the same rule.
- a new section enumerating the six measured ways GitHub rewrites an issue/PR
body after it is written, the four mitigations measured working, and a
pointer to the authoritative objectstack wording (carried verbatim only for
the read-back-before-repair caveat, which is load-bearing).
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BGMDbrVa8JjZcCQ7DWYH1b
@os-zhuang
os-zhuang marked this pull request as ready for review September 2, 2026 11:27
@os-zhuang
os-zhuang added this pull request to the merge queueSep 2, 2026
Merged via the queue into main with commit 2956d7aSep 2, 2026
28 checks passed
@os-zhuang
os-zhuang deleted the claude/issue-6970-github-body-mangling-rules branch September 2, 2026 11:42
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentation

Projects

None yet

3 participants

@yinlianghui@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): record how GitHub mangles agent-written bodies, and the per-query search control (#6970) - #7317

Merged
os-zhuang merged 2 commits into
mainfrom
claude/issue-6970-github-body-mangling-rules
Sep 2, 2026
Merged

docs(agents): record how GitHub mangles agent-written bodies, and the per-query search control (#6970)#7317
os-zhuang merged 2 commits into
mainfrom
claude/issue-6970-github-body-mangling-rules

Conversation

@yinlianghui

@yinlianghuiyinlianghui commented Sep 2, 2026

Copy link
Copy Markdown
Collaborator

Fixes#6970
Fixes#6452
Part of #7185 (option A only — the diagnosis half, option B, stays open on that card by its author's instruction; changed from a closing line by the PM seat after the dev flagged it)

One governed edit to AGENTS.md (46 added lines, no deletions), folding three devx cards that all land in the same instrument-discipline area of the file. One authoritative wording beats three riders.

What landed, and where

Two clauses, inserted between the existing control/measurement subsections and the governed-surface section:

  • #### 对照挂在通道上,不只挂在查询上 — AGENTS.md lines 401-414. The channel-control rule. The control belongs on the CHANNEL, not only on the query, and it is run PER query: a non-empty result is self-validating and needs no control, an empty one ALWAYS needs a known-must-hit control. Recorded with the measured asymmetry — a long, near-verbatim title query returned total_count: 0 for an issue that reads fine directly, while a short keyword query in the same container within the same hour returned 3 hits — so the rule reads "never trust an empty search without a control", not "never use search". The zero-quota web payload channel is recorded as the measured fallback, under the same control requirement and with the caveat that it is one day in one container, not a permanent answer.
  • ### GitHub 会改写你写进 issue/PR 正文的字节 — AGENTS.md lines 416-445. The mangling enumeration, one line per class, plus the four mitigations measured working, plus the placeholder clause described below.

Both sit inside section 9's measurement/instrument area, immediately before the governed-surface section.

The six classes, one line each

  1. Tag-shaped fragments stripped on save, including inside backticks and fences, and an HTML-comment marker alone on a comment's first line (first-line placement is not protection).
  2. PATCH downgrades the session-URL attribution footer to the bare form.
  3. PATCH appends a second footer unconditionally — measured at exactly +58 bytes, with the unified diff being only the appended lines, so this one adds rather than removes.
  4. issue_write create strips the attribution footer block entirely. Sentinel proof: tail kept, middle deleted, so it is a targeted strip and not a truncation — without the sentinel the only available conclusion points at length limits, which is the wrong direction.
  5. PR create normalises a bare footer to the session-URL form, so create-then-edit loses the session reference altogether; and the id carried there is the seat's, not the implementer's.
  6. The linked-issue parser ignores negation — a negated keyword sitting next to a card reference still acts at merge time. Recorded safe forms: Part of, Refs:, Related:, and the bare objectui prefix form, plus a pre-open grep of your own body for the three keyword stems near a hash.

Mitigations recorded as measured: generics and placeholders written in words, the session URL carried in prose as a backticked code span, attribution written as prose on issue bodies, and a read-back to the tail with an angle-bracket count after every publish.

The placeholder clause

Landed as the triage ruling asked: a SHORT objectui clause plus a pointer to the objectstack AGENTS.md wording rather than a copy of it, so there is one authoritative text and no duplicated prose to drift. It states explicitly that placeholders in ordinary prose and in fenced code are covered — the case that was actually measured — and it carries the load-bearing caveat verbatim:

A body reading short only through the API is probably intact — check the rendered page before "repairing" it; a rewrite destroys a correct card.

I did not judge the upstream wording to need widening, so no objectstack skills-lane card is filed. The pointer plus the explicit placeholder sentence covers the measured case without touching the upstream text.

Deliberately not built here

Named as options only, per the dispatch:

  • a shared publish helper that reads back and diffs automatically, making the check mechanical rather than remembered;
  • a check that scans recent agent-authored bodies for the tells (identical before/after columns, a doubled footer).

Also not attempted: the diagnosis of why the issue-search path goes blind. The clause records it as unresolved, naming both candidate causes and the point that only one of them self-heals. That diagnosis is the half of #7185 this PR does not close.

Governance

AGENTS.md is a governed surface. node scripts/check-governed-queue-guard.mjs --test AGENTS.md exits 3, which is the correct verdict for this PR:

One governed path governs the WHOLE pull request — proportion is not a question.

This PR therefore stays a DRAFT with hotlong and os-zhuang requested. Not flipped ready, not enqueued, no auto-merge.

Verification, all on head 3083d3e

gateverdict
pnpm check:control-bytesexit 0 — "OK (scanned 6014 tracked text file(s); skipped 85 binary)"
node scripts/check-shell-escape-residue.mjsexit 0 — "OK (4/4 root(s) resolved -- AGENTS.md: 1 file(s), 15 fence(s) ...)"
node scripts/check-governed-queue-guard.mjs --self-testexit 0 — "132 cases pass"
node scripts/check-governed-queue-guard.mjs --test AGENTS.mdexit 3 — expected, quoted above
node scripts/check-changeset-presence.mjsexit 0 — "No source or published contract of a released package changed in this range, so no changeset is owed."
pnpm docs:check-linksexit 0 — "Links are valid across 17 scan roots."
vitest, the 4 suites that read AGENTS.md from diskexit 0 — 4 files, 157 tests passed

The four suites are scripts/__tests__/check-doc-links.test.ts, check-governed-queue-guard.test.ts, check-shell-escape-residue.test.ts and site-next-agent-files-4160.test.ts, run from the repo root. A scan of scripts/ found no line ratchet or line budget over AGENTS.md; check-doc-links carries the file with the disk rule, and the file has no markdown links at all because its paths are code spans, which the checker blanks — the new text keeps that convention.

Merge-tree proofs, both exit 0, each producing a tree oid with no conflict block:

  • against origin/main
  • against PR 7242's head e362056bf, the other open claim on this file. It adds one line to a different section (the multi-agent discipline bullets under section 9); this edit is 130 lines below it.

Card 6325, listed as a possible placement constraint, is CLOSED (completed 2026-08-27) and constrains nothing here. origin/main was merged in, never rebased; the diff against main is still exactly the 46-line addition.

Session reference, carried here as prose because the footer form is not durable across a body edit: https://claude.ai/code/session_01BGMDbrVa8JjZcCQ7DWYH1b

🤖 Generated with Claude Code

https://claude.ai/code/session_01BGMDbrVa8JjZcCQ7DWYH1b

… per-query search control
Two clauses in the instrument-discipline area of AGENTS.md:
- a channel-level control rule: the control belongs on the CHANNEL, not only
on the query, and it is run per query. A non-empty result is self-validating;
an empty one always needs a known-must-hit control. The zero-quota web
payload channel is recorded as the measured fallback under the same rule.
- a new section enumerating the six measured ways GitHub rewrites an issue/PR
body after it is written, the four mitigations measured working, and a
pointer to the authoritative objectstack wording (carried verbatim only for
the read-back-before-repair caveat, which is load-bearing).
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BGMDbrVa8JjZcCQ7DWYH1b
@os-zhuang
os-zhuang marked this pull request as ready for review September 2, 2026 11:27
@os-zhuang
os-zhuang added this pull request to the merge queueSep 2, 2026
Merged via the queue into main with commit 2956d7aSep 2, 2026
28 checks passed
@os-zhuang
os-zhuang deleted the claude/issue-6970-github-body-mangling-rules branch September 2, 2026 11:42
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentation

Projects

None yet

3 participants

@yinlianghui@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): record how GitHub mangles agent-written bodies, and the per-query search control (#6970) - #7317

Merged
os-zhuang merged 2 commits into
mainfrom
claude/issue-6970-github-body-mangling-rules
Sep 2, 2026
Merged

docs(agents): record how GitHub mangles agent-written bodies, and the per-query search control (#6970)#7317
os-zhuang merged 2 commits into
mainfrom
claude/issue-6970-github-body-mangling-rules

Conversation

@yinlianghui

@yinlianghuiyinlianghui commented Sep 2, 2026

Copy link
Copy Markdown
Collaborator

Fixes#6970
Fixes#6452
Part of #7185 (option A only — the diagnosis half, option B, stays open on that card by its author's instruction; changed from a closing line by the PM seat after the dev flagged it)

One governed edit to AGENTS.md (46 added lines, no deletions), folding three devx cards that all land in the same instrument-discipline area of the file. One authoritative wording beats three riders.

What landed, and where

Two clauses, inserted between the existing control/measurement subsections and the governed-surface section:

  • #### 对照挂在通道上,不只挂在查询上 — AGENTS.md lines 401-414. The channel-control rule. The control belongs on the CHANNEL, not only on the query, and it is run PER query: a non-empty result is self-validating and needs no control, an empty one ALWAYS needs a known-must-hit control. Recorded with the measured asymmetry — a long, near-verbatim title query returned total_count: 0 for an issue that reads fine directly, while a short keyword query in the same container within the same hour returned 3 hits — so the rule reads "never trust an empty search without a control", not "never use search". The zero-quota web payload channel is recorded as the measured fallback, under the same control requirement and with the caveat that it is one day in one container, not a permanent answer.
  • ### GitHub 会改写你写进 issue/PR 正文的字节 — AGENTS.md lines 416-445. The mangling enumeration, one line per class, plus the four mitigations measured working, plus the placeholder clause described below.

Both sit inside section 9's measurement/instrument area, immediately before the governed-surface section.

The six classes, one line each

  1. Tag-shaped fragments stripped on save, including inside backticks and fences, and an HTML-comment marker alone on a comment's first line (first-line placement is not protection).
  2. PATCH downgrades the session-URL attribution footer to the bare form.
  3. PATCH appends a second footer unconditionally — measured at exactly +58 bytes, with the unified diff being only the appended lines, so this one adds rather than removes.
  4. issue_write create strips the attribution footer block entirely. Sentinel proof: tail kept, middle deleted, so it is a targeted strip and not a truncation — without the sentinel the only available conclusion points at length limits, which is the wrong direction.
  5. PR create normalises a bare footer to the session-URL form, so create-then-edit loses the session reference altogether; and the id carried there is the seat's, not the implementer's.
  6. The linked-issue parser ignores negation — a negated keyword sitting next to a card reference still acts at merge time. Recorded safe forms: Part of, Refs:, Related:, and the bare objectui prefix form, plus a pre-open grep of your own body for the three keyword stems near a hash.

Mitigations recorded as measured: generics and placeholders written in words, the session URL carried in prose as a backticked code span, attribution written as prose on issue bodies, and a read-back to the tail with an angle-bracket count after every publish.

The placeholder clause

Landed as the triage ruling asked: a SHORT objectui clause plus a pointer to the objectstack AGENTS.md wording rather than a copy of it, so there is one authoritative text and no duplicated prose to drift. It states explicitly that placeholders in ordinary prose and in fenced code are covered — the case that was actually measured — and it carries the load-bearing caveat verbatim:

A body reading short only through the API is probably intact — check the rendered page before "repairing" it; a rewrite destroys a correct card.

I did not judge the upstream wording to need widening, so no objectstack skills-lane card is filed. The pointer plus the explicit placeholder sentence covers the measured case without touching the upstream text.

Deliberately not built here

Named as options only, per the dispatch:

  • a shared publish helper that reads back and diffs automatically, making the check mechanical rather than remembered;
  • a check that scans recent agent-authored bodies for the tells (identical before/after columns, a doubled footer).

Also not attempted: the diagnosis of why the issue-search path goes blind. The clause records it as unresolved, naming both candidate causes and the point that only one of them self-heals. That diagnosis is the half of #7185 this PR does not close.

Governance

AGENTS.md is a governed surface. node scripts/check-governed-queue-guard.mjs --test AGENTS.md exits 3, which is the correct verdict for this PR:

One governed path governs the WHOLE pull request — proportion is not a question.

This PR therefore stays a DRAFT with hotlong and os-zhuang requested. Not flipped ready, not enqueued, no auto-merge.

Verification, all on head 3083d3e

gateverdict
pnpm check:control-bytesexit 0 — "OK (scanned 6014 tracked text file(s); skipped 85 binary)"
node scripts/check-shell-escape-residue.mjsexit 0 — "OK (4/4 root(s) resolved -- AGENTS.md: 1 file(s), 15 fence(s) ...)"
node scripts/check-governed-queue-guard.mjs --self-testexit 0 — "132 cases pass"
node scripts/check-governed-queue-guard.mjs --test AGENTS.mdexit 3 — expected, quoted above
node scripts/check-changeset-presence.mjsexit 0 — "No source or published contract of a released package changed in this range, so no changeset is owed."
pnpm docs:check-linksexit 0 — "Links are valid across 17 scan roots."
vitest, the 4 suites that read AGENTS.md from diskexit 0 — 4 files, 157 tests passed

The four suites are scripts/__tests__/check-doc-links.test.ts, check-governed-queue-guard.test.ts, check-shell-escape-residue.test.ts and site-next-agent-files-4160.test.ts, run from the repo root. A scan of scripts/ found no line ratchet or line budget over AGENTS.md; check-doc-links carries the file with the disk rule, and the file has no markdown links at all because its paths are code spans, which the checker blanks — the new text keeps that convention.

Merge-tree proofs, both exit 0, each producing a tree oid with no conflict block:

  • against origin/main
  • against PR 7242's head e362056bf, the other open claim on this file. It adds one line to a different section (the multi-agent discipline bullets under section 9); this edit is 130 lines below it.

Card 6325, listed as a possible placement constraint, is CLOSED (completed 2026-08-27) and constrains nothing here. origin/main was merged in, never rebased; the diff against main is still exactly the 46-line addition.

Session reference, carried here as prose because the footer form is not durable across a body edit: https://claude.ai/code/session_01BGMDbrVa8JjZcCQ7DWYH1b

🤖 Generated with Claude Code

https://claude.ai/code/session_01BGMDbrVa8JjZcCQ7DWYH1b

… per-query search control
Two clauses in the instrument-discipline area of AGENTS.md:
- a channel-level control rule: the control belongs on the CHANNEL, not only
on the query, and it is run per query. A non-empty result is self-validating;
an empty one always needs a known-must-hit control. The zero-quota web
payload channel is recorded as the measured fallback under the same rule.
- a new section enumerating the six measured ways GitHub rewrites an issue/PR
body after it is written, the four mitigations measured working, and a
pointer to the authoritative objectstack wording (carried verbatim only for
the read-back-before-repair caveat, which is load-bearing).
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BGMDbrVa8JjZcCQ7DWYH1b
@os-zhuang
os-zhuang marked this pull request as ready for review September 2, 2026 11:27
@os-zhuang
os-zhuang added this pull request to the merge queueSep 2, 2026
Merged via the queue into main with commit 2956d7aSep 2, 2026
28 checks passed
@os-zhuang
os-zhuang deleted the claude/issue-6970-github-body-mangling-rules branch September 2, 2026 11:42
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentation

Projects

None yet

3 participants

@yinlianghui@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): record how GitHub mangles agent-written bodies, and the per-query search control (#6970) - #7317

Merged
os-zhuang merged 2 commits into
mainfrom
claude/issue-6970-github-body-mangling-rules
Sep 2, 2026
Merged

docs(agents): record how GitHub mangles agent-written bodies, and the per-query search control (#6970)#7317
os-zhuang merged 2 commits into
mainfrom
claude/issue-6970-github-body-mangling-rules

Conversation

@yinlianghui

@yinlianghuiyinlianghui commented Sep 2, 2026

Copy link
Copy Markdown
Collaborator

Fixes#6970
Fixes#6452
Part of #7185 (option A only — the diagnosis half, option B, stays open on that card by its author's instruction; changed from a closing line by the PM seat after the dev flagged it)

One governed edit to AGENTS.md (46 added lines, no deletions), folding three devx cards that all land in the same instrument-discipline area of the file. One authoritative wording beats three riders.

What landed, and where

Two clauses, inserted between the existing control/measurement subsections and the governed-surface section:

  • #### 对照挂在通道上,不只挂在查询上 — AGENTS.md lines 401-414. The channel-control rule. The control belongs on the CHANNEL, not only on the query, and it is run PER query: a non-empty result is self-validating and needs no control, an empty one ALWAYS needs a known-must-hit control. Recorded with the measured asymmetry — a long, near-verbatim title query returned total_count: 0 for an issue that reads fine directly, while a short keyword query in the same container within the same hour returned 3 hits — so the rule reads "never trust an empty search without a control", not "never use search". The zero-quota web payload channel is recorded as the measured fallback, under the same control requirement and with the caveat that it is one day in one container, not a permanent answer.
  • ### GitHub 会改写你写进 issue/PR 正文的字节 — AGENTS.md lines 416-445. The mangling enumeration, one line per class, plus the four mitigations measured working, plus the placeholder clause described below.

Both sit inside section 9's measurement/instrument area, immediately before the governed-surface section.

The six classes, one line each

  1. Tag-shaped fragments stripped on save, including inside backticks and fences, and an HTML-comment marker alone on a comment's first line (first-line placement is not protection).
  2. PATCH downgrades the session-URL attribution footer to the bare form.
  3. PATCH appends a second footer unconditionally — measured at exactly +58 bytes, with the unified diff being only the appended lines, so this one adds rather than removes.
  4. issue_write create strips the attribution footer block entirely. Sentinel proof: tail kept, middle deleted, so it is a targeted strip and not a truncation — without the sentinel the only available conclusion points at length limits, which is the wrong direction.
  5. PR create normalises a bare footer to the session-URL form, so create-then-edit loses the session reference altogether; and the id carried there is the seat's, not the implementer's.
  6. The linked-issue parser ignores negation — a negated keyword sitting next to a card reference still acts at merge time. Recorded safe forms: Part of, Refs:, Related:, and the bare objectui prefix form, plus a pre-open grep of your own body for the three keyword stems near a hash.

Mitigations recorded as measured: generics and placeholders written in words, the session URL carried in prose as a backticked code span, attribution written as prose on issue bodies, and a read-back to the tail with an angle-bracket count after every publish.

The placeholder clause

Landed as the triage ruling asked: a SHORT objectui clause plus a pointer to the objectstack AGENTS.md wording rather than a copy of it, so there is one authoritative text and no duplicated prose to drift. It states explicitly that placeholders in ordinary prose and in fenced code are covered — the case that was actually measured — and it carries the load-bearing caveat verbatim:

A body reading short only through the API is probably intact — check the rendered page before "repairing" it; a rewrite destroys a correct card.

I did not judge the upstream wording to need widening, so no objectstack skills-lane card is filed. The pointer plus the explicit placeholder sentence covers the measured case without touching the upstream text.

Deliberately not built here

Named as options only, per the dispatch:

  • a shared publish helper that reads back and diffs automatically, making the check mechanical rather than remembered;
  • a check that scans recent agent-authored bodies for the tells (identical before/after columns, a doubled footer).

Also not attempted: the diagnosis of why the issue-search path goes blind. The clause records it as unresolved, naming both candidate causes and the point that only one of them self-heals. That diagnosis is the half of #7185 this PR does not close.

Governance

AGENTS.md is a governed surface. node scripts/check-governed-queue-guard.mjs --test AGENTS.md exits 3, which is the correct verdict for this PR:

One governed path governs the WHOLE pull request — proportion is not a question.

This PR therefore stays a DRAFT with hotlong and os-zhuang requested. Not flipped ready, not enqueued, no auto-merge.

Verification, all on head 3083d3e

gateverdict
pnpm check:control-bytesexit 0 — "OK (scanned 6014 tracked text file(s); skipped 85 binary)"
node scripts/check-shell-escape-residue.mjsexit 0 — "OK (4/4 root(s) resolved -- AGENTS.md: 1 file(s), 15 fence(s) ...)"
node scripts/check-governed-queue-guard.mjs --self-testexit 0 — "132 cases pass"
node scripts/check-governed-queue-guard.mjs --test AGENTS.mdexit 3 — expected, quoted above
node scripts/check-changeset-presence.mjsexit 0 — "No source or published contract of a released package changed in this range, so no changeset is owed."
pnpm docs:check-linksexit 0 — "Links are valid across 17 scan roots."
vitest, the 4 suites that read AGENTS.md from diskexit 0 — 4 files, 157 tests passed

The four suites are scripts/__tests__/check-doc-links.test.ts, check-governed-queue-guard.test.ts, check-shell-escape-residue.test.ts and site-next-agent-files-4160.test.ts, run from the repo root. A scan of scripts/ found no line ratchet or line budget over AGENTS.md; check-doc-links carries the file with the disk rule, and the file has no markdown links at all because its paths are code spans, which the checker blanks — the new text keeps that convention.

Merge-tree proofs, both exit 0, each producing a tree oid with no conflict block:

  • against origin/main
  • against PR 7242's head e362056bf, the other open claim on this file. It adds one line to a different section (the multi-agent discipline bullets under section 9); this edit is 130 lines below it.

Card 6325, listed as a possible placement constraint, is CLOSED (completed 2026-08-27) and constrains nothing here. origin/main was merged in, never rebased; the diff against main is still exactly the 46-line addition.

Session reference, carried here as prose because the footer form is not durable across a body edit: https://claude.ai/code/session_01BGMDbrVa8JjZcCQ7DWYH1b

🤖 Generated with Claude Code

https://claude.ai/code/session_01BGMDbrVa8JjZcCQ7DWYH1b

… per-query search control
Two clauses in the instrument-discipline area of AGENTS.md:
- a channel-level control rule: the control belongs on the CHANNEL, not only
on the query, and it is run per query. A non-empty result is self-validating;
an empty one always needs a known-must-hit control. The zero-quota web
payload channel is recorded as the measured fallback under the same rule.
- a new section enumerating the six measured ways GitHub rewrites an issue/PR
body after it is written, the four mitigations measured working, and a
pointer to the authoritative objectstack wording (carried verbatim only for
the read-back-before-repair caveat, which is load-bearing).
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BGMDbrVa8JjZcCQ7DWYH1b
@os-zhuang
os-zhuang marked this pull request as ready for review September 2, 2026 11:27
@os-zhuang
os-zhuang added this pull request to the merge queueSep 2, 2026
Merged via the queue into main with commit 2956d7aSep 2, 2026
28 checks passed
@os-zhuang
os-zhuang deleted the claude/issue-6970-github-body-mangling-rules branch September 2, 2026 11:42
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentation

Projects

None yet

3 participants

@yinlianghui@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): record how GitHub mangles agent-written bodies, and the per-query search control (#6970) - #7317

Merged
os-zhuang merged 2 commits into
mainfrom
claude/issue-6970-github-body-mangling-rules
Sep 2, 2026
Merged

docs(agents): record how GitHub mangles agent-written bodies, and the per-query search control (#6970)#7317
os-zhuang merged 2 commits into
mainfrom
claude/issue-6970-github-body-mangling-rules

Conversation

@yinlianghui

@yinlianghuiyinlianghui commented Sep 2, 2026

Copy link
Copy Markdown
Collaborator

Fixes#6970
Fixes#6452
Part of #7185 (option A only — the diagnosis half, option B, stays open on that card by its author's instruction; changed from a closing line by the PM seat after the dev flagged it)

One governed edit to AGENTS.md (46 added lines, no deletions), folding three devx cards that all land in the same instrument-discipline area of the file. One authoritative wording beats three riders.

What landed, and where

Two clauses, inserted between the existing control/measurement subsections and the governed-surface section:

  • #### 对照挂在通道上,不只挂在查询上 — AGENTS.md lines 401-414. The channel-control rule. The control belongs on the CHANNEL, not only on the query, and it is run PER query: a non-empty result is self-validating and needs no control, an empty one ALWAYS needs a known-must-hit control. Recorded with the measured asymmetry — a long, near-verbatim title query returned total_count: 0 for an issue that reads fine directly, while a short keyword query in the same container within the same hour returned 3 hits — so the rule reads "never trust an empty search without a control", not "never use search". The zero-quota web payload channel is recorded as the measured fallback, under the same control requirement and with the caveat that it is one day in one container, not a permanent answer.
  • ### GitHub 会改写你写进 issue/PR 正文的字节 — AGENTS.md lines 416-445. The mangling enumeration, one line per class, plus the four mitigations measured working, plus the placeholder clause described below.

Both sit inside section 9's measurement/instrument area, immediately before the governed-surface section.

The six classes, one line each

  1. Tag-shaped fragments stripped on save, including inside backticks and fences, and an HTML-comment marker alone on a comment's first line (first-line placement is not protection).
  2. PATCH downgrades the session-URL attribution footer to the bare form.
  3. PATCH appends a second footer unconditionally — measured at exactly +58 bytes, with the unified diff being only the appended lines, so this one adds rather than removes.
  4. issue_write create strips the attribution footer block entirely. Sentinel proof: tail kept, middle deleted, so it is a targeted strip and not a truncation — without the sentinel the only available conclusion points at length limits, which is the wrong direction.
  5. PR create normalises a bare footer to the session-URL form, so create-then-edit loses the session reference altogether; and the id carried there is the seat's, not the implementer's.
  6. The linked-issue parser ignores negation — a negated keyword sitting next to a card reference still acts at merge time. Recorded safe forms: Part of, Refs:, Related:, and the bare objectui prefix form, plus a pre-open grep of your own body for the three keyword stems near a hash.

Mitigations recorded as measured: generics and placeholders written in words, the session URL carried in prose as a backticked code span, attribution written as prose on issue bodies, and a read-back to the tail with an angle-bracket count after every publish.

The placeholder clause

Landed as the triage ruling asked: a SHORT objectui clause plus a pointer to the objectstack AGENTS.md wording rather than a copy of it, so there is one authoritative text and no duplicated prose to drift. It states explicitly that placeholders in ordinary prose and in fenced code are covered — the case that was actually measured — and it carries the load-bearing caveat verbatim:

A body reading short only through the API is probably intact — check the rendered page before "repairing" it; a rewrite destroys a correct card.

I did not judge the upstream wording to need widening, so no objectstack skills-lane card is filed. The pointer plus the explicit placeholder sentence covers the measured case without touching the upstream text.

Deliberately not built here

Named as options only, per the dispatch:

  • a shared publish helper that reads back and diffs automatically, making the check mechanical rather than remembered;
  • a check that scans recent agent-authored bodies for the tells (identical before/after columns, a doubled footer).

Also not attempted: the diagnosis of why the issue-search path goes blind. The clause records it as unresolved, naming both candidate causes and the point that only one of them self-heals. That diagnosis is the half of #7185 this PR does not close.

Governance

AGENTS.md is a governed surface. node scripts/check-governed-queue-guard.mjs --test AGENTS.md exits 3, which is the correct verdict for this PR:

One governed path governs the WHOLE pull request — proportion is not a question.

This PR therefore stays a DRAFT with hotlong and os-zhuang requested. Not flipped ready, not enqueued, no auto-merge.

Verification, all on head 3083d3e

gateverdict
pnpm check:control-bytesexit 0 — "OK (scanned 6014 tracked text file(s); skipped 85 binary)"
node scripts/check-shell-escape-residue.mjsexit 0 — "OK (4/4 root(s) resolved -- AGENTS.md: 1 file(s), 15 fence(s) ...)"
node scripts/check-governed-queue-guard.mjs --self-testexit 0 — "132 cases pass"
node scripts/check-governed-queue-guard.mjs --test AGENTS.mdexit 3 — expected, quoted above
node scripts/check-changeset-presence.mjsexit 0 — "No source or published contract of a released package changed in this range, so no changeset is owed."
pnpm docs:check-linksexit 0 — "Links are valid across 17 scan roots."
vitest, the 4 suites that read AGENTS.md from diskexit 0 — 4 files, 157 tests passed

The four suites are scripts/__tests__/check-doc-links.test.ts, check-governed-queue-guard.test.ts, check-shell-escape-residue.test.ts and site-next-agent-files-4160.test.ts, run from the repo root. A scan of scripts/ found no line ratchet or line budget over AGENTS.md; check-doc-links carries the file with the disk rule, and the file has no markdown links at all because its paths are code spans, which the checker blanks — the new text keeps that convention.

Merge-tree proofs, both exit 0, each producing a tree oid with no conflict block:

  • against origin/main
  • against PR 7242's head e362056bf, the other open claim on this file. It adds one line to a different section (the multi-agent discipline bullets under section 9); this edit is 130 lines below it.

Card 6325, listed as a possible placement constraint, is CLOSED (completed 2026-08-27) and constrains nothing here. origin/main was merged in, never rebased; the diff against main is still exactly the 46-line addition.

Session reference, carried here as prose because the footer form is not durable across a body edit: https://claude.ai/code/session_01BGMDbrVa8JjZcCQ7DWYH1b

🤖 Generated with Claude Code

https://claude.ai/code/session_01BGMDbrVa8JjZcCQ7DWYH1b

… per-query search control
Two clauses in the instrument-discipline area of AGENTS.md:
- a channel-level control rule: the control belongs on the CHANNEL, not only
on the query, and it is run per query. A non-empty result is self-validating;
an empty one always needs a known-must-hit control. The zero-quota web
payload channel is recorded as the measured fallback under the same rule.
- a new section enumerating the six measured ways GitHub rewrites an issue/PR
body after it is written, the four mitigations measured working, and a
pointer to the authoritative objectstack wording (carried verbatim only for
the read-back-before-repair caveat, which is load-bearing).
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BGMDbrVa8JjZcCQ7DWYH1b
@os-zhuang
os-zhuang marked this pull request as ready for review September 2, 2026 11:27
@os-zhuang
os-zhuang added this pull request to the merge queueSep 2, 2026
Merged via the queue into main with commit 2956d7aSep 2, 2026
28 checks passed
@os-zhuang
os-zhuang deleted the claude/issue-6970-github-body-mangling-rules branch September 2, 2026 11:42
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentation

Projects

None yet

3 participants

@yinlianghui@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): record how GitHub mangles agent-written bodies, and the per-query search control (#6970) - #7317

Merged
os-zhuang merged 2 commits into
mainfrom
claude/issue-6970-github-body-mangling-rules
Sep 2, 2026
Merged

docs(agents): record how GitHub mangles agent-written bodies, and the per-query search control (#6970)#7317
os-zhuang merged 2 commits into
mainfrom
claude/issue-6970-github-body-mangling-rules

Conversation

@yinlianghui

@yinlianghuiyinlianghui commented Sep 2, 2026

Copy link
Copy Markdown
Collaborator

Fixes#6970
Fixes#6452
Part of #7185 (option A only — the diagnosis half, option B, stays open on that card by its author's instruction; changed from a closing line by the PM seat after the dev flagged it)

One governed edit to AGENTS.md (46 added lines, no deletions), folding three devx cards that all land in the same instrument-discipline area of the file. One authoritative wording beats three riders.

What landed, and where

Two clauses, inserted between the existing control/measurement subsections and the governed-surface section:

  • #### 对照挂在通道上,不只挂在查询上 — AGENTS.md lines 401-414. The channel-control rule. The control belongs on the CHANNEL, not only on the query, and it is run PER query: a non-empty result is self-validating and needs no control, an empty one ALWAYS needs a known-must-hit control. Recorded with the measured asymmetry — a long, near-verbatim title query returned total_count: 0 for an issue that reads fine directly, while a short keyword query in the same container within the same hour returned 3 hits — so the rule reads "never trust an empty search without a control", not "never use search". The zero-quota web payload channel is recorded as the measured fallback, under the same control requirement and with the caveat that it is one day in one container, not a permanent answer.
  • ### GitHub 会改写你写进 issue/PR 正文的字节 — AGENTS.md lines 416-445. The mangling enumeration, one line per class, plus the four mitigations measured working, plus the placeholder clause described below.

Both sit inside section 9's measurement/instrument area, immediately before the governed-surface section.

The six classes, one line each

  1. Tag-shaped fragments stripped on save, including inside backticks and fences, and an HTML-comment marker alone on a comment's first line (first-line placement is not protection).
  2. PATCH downgrades the session-URL attribution footer to the bare form.
  3. PATCH appends a second footer unconditionally — measured at exactly +58 bytes, with the unified diff being only the appended lines, so this one adds rather than removes.
  4. issue_write create strips the attribution footer block entirely. Sentinel proof: tail kept, middle deleted, so it is a targeted strip and not a truncation — without the sentinel the only available conclusion points at length limits, which is the wrong direction.
  5. PR create normalises a bare footer to the session-URL form, so create-then-edit loses the session reference altogether; and the id carried there is the seat's, not the implementer's.
  6. The linked-issue parser ignores negation — a negated keyword sitting next to a card reference still acts at merge time. Recorded safe forms: Part of, Refs:, Related:, and the bare objectui prefix form, plus a pre-open grep of your own body for the three keyword stems near a hash.

Mitigations recorded as measured: generics and placeholders written in words, the session URL carried in prose as a backticked code span, attribution written as prose on issue bodies, and a read-back to the tail with an angle-bracket count after every publish.

The placeholder clause

Landed as the triage ruling asked: a SHORT objectui clause plus a pointer to the objectstack AGENTS.md wording rather than a copy of it, so there is one authoritative text and no duplicated prose to drift. It states explicitly that placeholders in ordinary prose and in fenced code are covered — the case that was actually measured — and it carries the load-bearing caveat verbatim:

A body reading short only through the API is probably intact — check the rendered page before "repairing" it; a rewrite destroys a correct card.

I did not judge the upstream wording to need widening, so no objectstack skills-lane card is filed. The pointer plus the explicit placeholder sentence covers the measured case without touching the upstream text.

Deliberately not built here

Named as options only, per the dispatch:

  • a shared publish helper that reads back and diffs automatically, making the check mechanical rather than remembered;
  • a check that scans recent agent-authored bodies for the tells (identical before/after columns, a doubled footer).

Also not attempted: the diagnosis of why the issue-search path goes blind. The clause records it as unresolved, naming both candidate causes and the point that only one of them self-heals. That diagnosis is the half of #7185 this PR does not close.

Governance

AGENTS.md is a governed surface. node scripts/check-governed-queue-guard.mjs --test AGENTS.md exits 3, which is the correct verdict for this PR:

One governed path governs the WHOLE pull request — proportion is not a question.

This PR therefore stays a DRAFT with hotlong and os-zhuang requested. Not flipped ready, not enqueued, no auto-merge.

Verification, all on head 3083d3e

gateverdict
pnpm check:control-bytesexit 0 — "OK (scanned 6014 tracked text file(s); skipped 85 binary)"
node scripts/check-shell-escape-residue.mjsexit 0 — "OK (4/4 root(s) resolved -- AGENTS.md: 1 file(s), 15 fence(s) ...)"
node scripts/check-governed-queue-guard.mjs --self-testexit 0 — "132 cases pass"
node scripts/check-governed-queue-guard.mjs --test AGENTS.mdexit 3 — expected, quoted above
node scripts/check-changeset-presence.mjsexit 0 — "No source or published contract of a released package changed in this range, so no changeset is owed."
pnpm docs:check-linksexit 0 — "Links are valid across 17 scan roots."
vitest, the 4 suites that read AGENTS.md from diskexit 0 — 4 files, 157 tests passed

The four suites are scripts/__tests__/check-doc-links.test.ts, check-governed-queue-guard.test.ts, check-shell-escape-residue.test.ts and site-next-agent-files-4160.test.ts, run from the repo root. A scan of scripts/ found no line ratchet or line budget over AGENTS.md; check-doc-links carries the file with the disk rule, and the file has no markdown links at all because its paths are code spans, which the checker blanks — the new text keeps that convention.

Merge-tree proofs, both exit 0, each producing a tree oid with no conflict block:

  • against origin/main
  • against PR 7242's head e362056bf, the other open claim on this file. It adds one line to a different section (the multi-agent discipline bullets under section 9); this edit is 130 lines below it.

Card 6325, listed as a possible placement constraint, is CLOSED (completed 2026-08-27) and constrains nothing here. origin/main was merged in, never rebased; the diff against main is still exactly the 46-line addition.

Session reference, carried here as prose because the footer form is not durable across a body edit: https://claude.ai/code/session_01BGMDbrVa8JjZcCQ7DWYH1b

🤖 Generated with Claude Code

https://claude.ai/code/session_01BGMDbrVa8JjZcCQ7DWYH1b

… per-query search control
Two clauses in the instrument-discipline area of AGENTS.md:
- a channel-level control rule: the control belongs on the CHANNEL, not only
on the query, and it is run per query. A non-empty result is self-validating;
an empty one always needs a known-must-hit control. The zero-quota web
payload channel is recorded as the measured fallback under the same rule.
- a new section enumerating the six measured ways GitHub rewrites an issue/PR
body after it is written, the four mitigations measured working, and a
pointer to the authoritative objectstack wording (carried verbatim only for
the read-back-before-repair caveat, which is load-bearing).
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BGMDbrVa8JjZcCQ7DWYH1b
@os-zhuang
os-zhuang marked this pull request as ready for review September 2, 2026 11:27
@os-zhuang
os-zhuang added this pull request to the merge queueSep 2, 2026
Merged via the queue into main with commit 2956d7aSep 2, 2026
28 checks passed
@os-zhuang
os-zhuang deleted the claude/issue-6970-github-body-mangling-rules branch September 2, 2026 11:42
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentation

Projects

None yet

3 participants

@yinlianghui@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): record how GitHub mangles agent-written bodies, and the per-query search control (#6970) - #7317

Merged
os-zhuang merged 2 commits into
mainfrom
claude/issue-6970-github-body-mangling-rules
Sep 2, 2026
Merged

docs(agents): record how GitHub mangles agent-written bodies, and the per-query search control (#6970)#7317
os-zhuang merged 2 commits into
mainfrom
claude/issue-6970-github-body-mangling-rules

Conversation

@yinlianghui

@yinlianghuiyinlianghui commented Sep 2, 2026

Copy link
Copy Markdown
Collaborator

Fixes#6970
Fixes#6452
Part of #7185 (option A only — the diagnosis half, option B, stays open on that card by its author's instruction; changed from a closing line by the PM seat after the dev flagged it)

One governed edit to AGENTS.md (46 added lines, no deletions), folding three devx cards that all land in the same instrument-discipline area of the file. One authoritative wording beats three riders.

What landed, and where

Two clauses, inserted between the existing control/measurement subsections and the governed-surface section:

  • #### 对照挂在通道上,不只挂在查询上 — AGENTS.md lines 401-414. The channel-control rule. The control belongs on the CHANNEL, not only on the query, and it is run PER query: a non-empty result is self-validating and needs no control, an empty one ALWAYS needs a known-must-hit control. Recorded with the measured asymmetry — a long, near-verbatim title query returned total_count: 0 for an issue that reads fine directly, while a short keyword query in the same container within the same hour returned 3 hits — so the rule reads "never trust an empty search without a control", not "never use search". The zero-quota web payload channel is recorded as the measured fallback, under the same control requirement and with the caveat that it is one day in one container, not a permanent answer.
  • ### GitHub 会改写你写进 issue/PR 正文的字节 — AGENTS.md lines 416-445. The mangling enumeration, one line per class, plus the four mitigations measured working, plus the placeholder clause described below.

Both sit inside section 9's measurement/instrument area, immediately before the governed-surface section.

The six classes, one line each

  1. Tag-shaped fragments stripped on save, including inside backticks and fences, and an HTML-comment marker alone on a comment's first line (first-line placement is not protection).
  2. PATCH downgrades the session-URL attribution footer to the bare form.
  3. PATCH appends a second footer unconditionally — measured at exactly +58 bytes, with the unified diff being only the appended lines, so this one adds rather than removes.
  4. issue_write create strips the attribution footer block entirely. Sentinel proof: tail kept, middle deleted, so it is a targeted strip and not a truncation — without the sentinel the only available conclusion points at length limits, which is the wrong direction.
  5. PR create normalises a bare footer to the session-URL form, so create-then-edit loses the session reference altogether; and the id carried there is the seat's, not the implementer's.
  6. The linked-issue parser ignores negation — a negated keyword sitting next to a card reference still acts at merge time. Recorded safe forms: Part of, Refs:, Related:, and the bare objectui prefix form, plus a pre-open grep of your own body for the three keyword stems near a hash.

Mitigations recorded as measured: generics and placeholders written in words, the session URL carried in prose as a backticked code span, attribution written as prose on issue bodies, and a read-back to the tail with an angle-bracket count after every publish.

The placeholder clause

Landed as the triage ruling asked: a SHORT objectui clause plus a pointer to the objectstack AGENTS.md wording rather than a copy of it, so there is one authoritative text and no duplicated prose to drift. It states explicitly that placeholders in ordinary prose and in fenced code are covered — the case that was actually measured — and it carries the load-bearing caveat verbatim:

A body reading short only through the API is probably intact — check the rendered page before "repairing" it; a rewrite destroys a correct card.

I did not judge the upstream wording to need widening, so no objectstack skills-lane card is filed. The pointer plus the explicit placeholder sentence covers the measured case without touching the upstream text.

Deliberately not built here

Named as options only, per the dispatch:

  • a shared publish helper that reads back and diffs automatically, making the check mechanical rather than remembered;
  • a check that scans recent agent-authored bodies for the tells (identical before/after columns, a doubled footer).

Also not attempted: the diagnosis of why the issue-search path goes blind. The clause records it as unresolved, naming both candidate causes and the point that only one of them self-heals. That diagnosis is the half of #7185 this PR does not close.

Governance

AGENTS.md is a governed surface. node scripts/check-governed-queue-guard.mjs --test AGENTS.md exits 3, which is the correct verdict for this PR:

One governed path governs the WHOLE pull request — proportion is not a question.

This PR therefore stays a DRAFT with hotlong and os-zhuang requested. Not flipped ready, not enqueued, no auto-merge.

Verification, all on head 3083d3e

gateverdict
pnpm check:control-bytesexit 0 — "OK (scanned 6014 tracked text file(s); skipped 85 binary)"
node scripts/check-shell-escape-residue.mjsexit 0 — "OK (4/4 root(s) resolved -- AGENTS.md: 1 file(s), 15 fence(s) ...)"
node scripts/check-governed-queue-guard.mjs --self-testexit 0 — "132 cases pass"
node scripts/check-governed-queue-guard.mjs --test AGENTS.mdexit 3 — expected, quoted above
node scripts/check-changeset-presence.mjsexit 0 — "No source or published contract of a released package changed in this range, so no changeset is owed."
pnpm docs:check-linksexit 0 — "Links are valid across 17 scan roots."
vitest, the 4 suites that read AGENTS.md from diskexit 0 — 4 files, 157 tests passed

The four suites are scripts/__tests__/check-doc-links.test.ts, check-governed-queue-guard.test.ts, check-shell-escape-residue.test.ts and site-next-agent-files-4160.test.ts, run from the repo root. A scan of scripts/ found no line ratchet or line budget over AGENTS.md; check-doc-links carries the file with the disk rule, and the file has no markdown links at all because its paths are code spans, which the checker blanks — the new text keeps that convention.

Merge-tree proofs, both exit 0, each producing a tree oid with no conflict block:

  • against origin/main
  • against PR 7242's head e362056bf, the other open claim on this file. It adds one line to a different section (the multi-agent discipline bullets under section 9); this edit is 130 lines below it.

Card 6325, listed as a possible placement constraint, is CLOSED (completed 2026-08-27) and constrains nothing here. origin/main was merged in, never rebased; the diff against main is still exactly the 46-line addition.

Session reference, carried here as prose because the footer form is not durable across a body edit: https://claude.ai/code/session_01BGMDbrVa8JjZcCQ7DWYH1b

🤖 Generated with Claude Code

https://claude.ai/code/session_01BGMDbrVa8JjZcCQ7DWYH1b

… per-query search control
Two clauses in the instrument-discipline area of AGENTS.md:
- a channel-level control rule: the control belongs on the CHANNEL, not only
on the query, and it is run per query. A non-empty result is self-validating;
an empty one always needs a known-must-hit control. The zero-quota web
payload channel is recorded as the measured fallback under the same rule.
- a new section enumerating the six measured ways GitHub rewrites an issue/PR
body after it is written, the four mitigations measured working, and a
pointer to the authoritative objectstack wording (carried verbatim only for
the read-back-before-repair caveat, which is load-bearing).
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BGMDbrVa8JjZcCQ7DWYH1b
@os-zhuang
os-zhuang marked this pull request as ready for review September 2, 2026 11:27
@os-zhuang
os-zhuang added this pull request to the merge queueSep 2, 2026
Merged via the queue into main with commit 2956d7aSep 2, 2026
28 checks passed
@os-zhuang
os-zhuang deleted the claude/issue-6970-github-body-mangling-rules branch September 2, 2026 11:42
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentation

Projects

None yet

3 participants

@yinlianghui@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): record how GitHub mangles agent-written bodies, and the per-query search control (#6970) - #7317

Merged
os-zhuang merged 2 commits into
mainfrom
claude/issue-6970-github-body-mangling-rules
Sep 2, 2026
Merged

docs(agents): record how GitHub mangles agent-written bodies, and the per-query search control (#6970)#7317
os-zhuang merged 2 commits into
mainfrom
claude/issue-6970-github-body-mangling-rules

Conversation

@yinlianghui

@yinlianghuiyinlianghui commented Sep 2, 2026

Copy link
Copy Markdown
Collaborator

Fixes#6970
Fixes#6452
Part of #7185 (option A only — the diagnosis half, option B, stays open on that card by its author's instruction; changed from a closing line by the PM seat after the dev flagged it)

One governed edit to AGENTS.md (46 added lines, no deletions), folding three devx cards that all land in the same instrument-discipline area of the file. One authoritative wording beats three riders.

What landed, and where

Two clauses, inserted between the existing control/measurement subsections and the governed-surface section:

  • #### 对照挂在通道上,不只挂在查询上 — AGENTS.md lines 401-414. The channel-control rule. The control belongs on the CHANNEL, not only on the query, and it is run PER query: a non-empty result is self-validating and needs no control, an empty one ALWAYS needs a known-must-hit control. Recorded with the measured asymmetry — a long, near-verbatim title query returned total_count: 0 for an issue that reads fine directly, while a short keyword query in the same container within the same hour returned 3 hits — so the rule reads "never trust an empty search without a control", not "never use search". The zero-quota web payload channel is recorded as the measured fallback, under the same control requirement and with the caveat that it is one day in one container, not a permanent answer.
  • ### GitHub 会改写你写进 issue/PR 正文的字节 — AGENTS.md lines 416-445. The mangling enumeration, one line per class, plus the four mitigations measured working, plus the placeholder clause described below.

Both sit inside section 9's measurement/instrument area, immediately before the governed-surface section.

The six classes, one line each

  1. Tag-shaped fragments stripped on save, including inside backticks and fences, and an HTML-comment marker alone on a comment's first line (first-line placement is not protection).
  2. PATCH downgrades the session-URL attribution footer to the bare form.
  3. PATCH appends a second footer unconditionally — measured at exactly +58 bytes, with the unified diff being only the appended lines, so this one adds rather than removes.
  4. issue_write create strips the attribution footer block entirely. Sentinel proof: tail kept, middle deleted, so it is a targeted strip and not a truncation — without the sentinel the only available conclusion points at length limits, which is the wrong direction.
  5. PR create normalises a bare footer to the session-URL form, so create-then-edit loses the session reference altogether; and the id carried there is the seat's, not the implementer's.
  6. The linked-issue parser ignores negation — a negated keyword sitting next to a card reference still acts at merge time. Recorded safe forms: Part of, Refs:, Related:, and the bare objectui prefix form, plus a pre-open grep of your own body for the three keyword stems near a hash.

Mitigations recorded as measured: generics and placeholders written in words, the session URL carried in prose as a backticked code span, attribution written as prose on issue bodies, and a read-back to the tail with an angle-bracket count after every publish.

The placeholder clause

Landed as the triage ruling asked: a SHORT objectui clause plus a pointer to the objectstack AGENTS.md wording rather than a copy of it, so there is one authoritative text and no duplicated prose to drift. It states explicitly that placeholders in ordinary prose and in fenced code are covered — the case that was actually measured — and it carries the load-bearing caveat verbatim:

A body reading short only through the API is probably intact — check the rendered page before "repairing" it; a rewrite destroys a correct card.

I did not judge the upstream wording to need widening, so no objectstack skills-lane card is filed. The pointer plus the explicit placeholder sentence covers the measured case without touching the upstream text.

Deliberately not built here

Named as options only, per the dispatch:

  • a shared publish helper that reads back and diffs automatically, making the check mechanical rather than remembered;
  • a check that scans recent agent-authored bodies for the tells (identical before/after columns, a doubled footer).

Also not attempted: the diagnosis of why the issue-search path goes blind. The clause records it as unresolved, naming both candidate causes and the point that only one of them self-heals. That diagnosis is the half of #7185 this PR does not close.

Governance

AGENTS.md is a governed surface. node scripts/check-governed-queue-guard.mjs --test AGENTS.md exits 3, which is the correct verdict for this PR:

One governed path governs the WHOLE pull request — proportion is not a question.

This PR therefore stays a DRAFT with hotlong and os-zhuang requested. Not flipped ready, not enqueued, no auto-merge.

Verification, all on head 3083d3e

gateverdict
pnpm check:control-bytesexit 0 — "OK (scanned 6014 tracked text file(s); skipped 85 binary)"
node scripts/check-shell-escape-residue.mjsexit 0 — "OK (4/4 root(s) resolved -- AGENTS.md: 1 file(s), 15 fence(s) ...)"
node scripts/check-governed-queue-guard.mjs --self-testexit 0 — "132 cases pass"
node scripts/check-governed-queue-guard.mjs --test AGENTS.mdexit 3 — expected, quoted above
node scripts/check-changeset-presence.mjsexit 0 — "No source or published contract of a released package changed in this range, so no changeset is owed."
pnpm docs:check-linksexit 0 — "Links are valid across 17 scan roots."
vitest, the 4 suites that read AGENTS.md from diskexit 0 — 4 files, 157 tests passed

The four suites are scripts/__tests__/check-doc-links.test.ts, check-governed-queue-guard.test.ts, check-shell-escape-residue.test.ts and site-next-agent-files-4160.test.ts, run from the repo root. A scan of scripts/ found no line ratchet or line budget over AGENTS.md; check-doc-links carries the file with the disk rule, and the file has no markdown links at all because its paths are code spans, which the checker blanks — the new text keeps that convention.

Merge-tree proofs, both exit 0, each producing a tree oid with no conflict block:

  • against origin/main
  • against PR 7242's head e362056bf, the other open claim on this file. It adds one line to a different section (the multi-agent discipline bullets under section 9); this edit is 130 lines below it.

Card 6325, listed as a possible placement constraint, is CLOSED (completed 2026-08-27) and constrains nothing here. origin/main was merged in, never rebased; the diff against main is still exactly the 46-line addition.

Session reference, carried here as prose because the footer form is not durable across a body edit: https://claude.ai/code/session_01BGMDbrVa8JjZcCQ7DWYH1b

🤖 Generated with Claude Code

https://claude.ai/code/session_01BGMDbrVa8JjZcCQ7DWYH1b

… per-query search control
Two clauses in the instrument-discipline area of AGENTS.md:
- a channel-level control rule: the control belongs on the CHANNEL, not only
on the query, and it is run per query. A non-empty result is self-validating;
an empty one always needs a known-must-hit control. The zero-quota web
payload channel is recorded as the measured fallback under the same rule.
- a new section enumerating the six measured ways GitHub rewrites an issue/PR
body after it is written, the four mitigations measured working, and a
pointer to the authoritative objectstack wording (carried verbatim only for
the read-back-before-repair caveat, which is load-bearing).
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BGMDbrVa8JjZcCQ7DWYH1b
@os-zhuang
os-zhuang marked this pull request as ready for review September 2, 2026 11:27
@os-zhuang
os-zhuang added this pull request to the merge queueSep 2, 2026
Merged via the queue into main with commit 2956d7aSep 2, 2026
28 checks passed
@os-zhuang
os-zhuang deleted the claude/issue-6970-github-body-mangling-rules branch September 2, 2026 11:42
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentation

Projects

None yet

3 participants

@yinlianghui@os-zhuang@claude