Repository navigation
AGENTS.md §How a green PR lands says "arm auto-merge" and never names the merge queue — but this repo HAS one, and the ruling that said so was overruled on a mismeasurement #1815
Description
Activity
- addeddocumentationImprovements or additions to documentationImprovements or additions to documentationpm:queueReady for the PM dispatch loopReady for the PM dispatch loop
on Sep 9, 2026 - addedpm:dispatchedDispatched to a dev agent by /pm-dispatchDispatched to a dev agent by /pm-dispatchand removedpm:queueReady for the PM dispatch loopReady for the PM dispatch loop
on Sep 9, 2026 zhuangjianguo commented
on Sep 9, 2026 CollaboratorAuthorMore actionsClaim: PM loop round R58
Session:session_017FzrA1G4U89KEMf7wfLmqq
Branch:claude/issue-1815-agents-md-names-the-merge-queue
Worktree:hotcrm-issue-1815
Domain:repo:hotcrm(single-lane repo — ⛔ nodomain:*)
File surface:AGENTS.md,.changeset/(stop on breach; explain in the report)
Container & model:M,mode:subagent,model: default judgement tier— governed surface, and the card turns on a measurement that overturned a starred lane fact
Clause-②: no
Thread-read: none — this card carries no comment yet; its body is the whole record
Serial constraints cleared: ⭐AGENTS.mdis FREE. PR #1809 (#1686) MERGEDbd6a5a5, clearing the serial head. #1745 · #1620 · #1618 are queued behind you and none is dispatched — you hold the file. In flight beside you: #1812 (.github/tasks/) — ⛔ disjoint.⚠️ #1620's subject isAGENTS.md:348, a bullet PR #1809 just rewrote; it is ⛔ not dispatched and you ⛔ do not touch its sentence.Dispatched to a dev, who inherits this claim — ⛔ the dev posts no second claim and does not touch the assignee.
Read the card body first — it is the measurement, and it overturns a ⭐⭐ lane fact
This card exists because seat-post §5.1 ("hotcrm has NO MERGE QUEUE") is false, and PR #1798 wrote
AGENTS.md§How a green PR lands on that false premise. Both the seat and #1797's dev verified the queue independently before this was filed.Zone 1 — what is settled
AGENTS.md§How a green PR lands must name the merge queue as the landing route. The section currently says a seat "arms auto-merge" and deliberately never mentions a queue — PR docs(agents): state how a green PR lands, and the governed-surface exception #1798's body records that omission as intentional, on the false premise.- ⛔ The gesture does not change and nothing is being rolled back. Arming auto-merge enqueues the PR; every PR that landed this round landed correctly. This is a description defect. ⛔ Do not write a new procedure, do not add a gate, do not touch any workflow.
- ⛔ No other
AGENTS.mdsentence moves.AGENTS.mdFile Suffix Protocol is an inventory that drifted both ways: 4 of its 12 declared suffixes have zero instances insrc/, and 8 suffixes the app really authors are absent from it #1745,AGENTS.md:348counts the drift its own rule forbids as "four times", and the ledger at:353has not been incremented since #1620 and AGENTS.md rule 6 says "UI nouns take the zh-CN pack wording", but a pack-carried noun that is not a list view must stay English — and only an ablation reveals it #1618 own their own sentences in this file and are queued behind you.⚠️ In particular:348belongs toAGENTS.md:348counts the drift its own rule forbids as "four times", and the ledger at:353has not been incremented since #1620 — ⛔ hands off. - Governed surface ⇒ draft PR, ⛔ never marked ready, ⛔ never auto-merged, ⛔ never enqueued. The maintainer merges. Include a
## 维护者速读(草稿)(Chinese, business framing, 席位意见 left blank).
Zone 2 — PM mechanism assumptions (
⚠️ must be tested)- ⭐ Re-verify the queue at your own commit, both channels, before writing a word of prose. ⛔ Do not inherit my reading — that is precisely the mistake this card documents. Configuration:
GET /repos/objectstack-ai/hotcrm/rulesets, then the ruleset by id, and read itsmerge_queueparameters. Behaviour: read a recently-merged PR's timeline foradded_to_merge_queue/removed_from_merge_queuebygithub-merge-queue[bot](docs(guides): drop the Settings path form from the email-templates sketch #1810, chore(labels): adopt the fleet priority:p0..p3 axis, retire prio:* #1811, docs(contributing): §Getting Merged points at AGENTS.md for who lands a PR #1813 and docs(email-and-calendar): drop the last Settings path citation #1816 all merged today and all went through it).
⚠️ GET /branches/main/protectionreturns 403 — that is the endpoint R57 probed and the origin of the whole false belief. The rulesets API is the one that answers. - I assume the section needs only the landing-mechanism sentence corrected, ⛔ not a rewrite. Read the whole section at your commit and say if that is wrong.
- Decide and justify whether to record
min_entries_to_merge_wait_minutes: 5. ⭐ My reading is that it earns its place — a seat watching a green PR sit for five minutes otherwise reads it as stuck, and this lane already misattributed exactly that delay once (PR ci(labels): declare the 22 live-but-undeclared labels in the manifest #1795's "5m40s" was cited as evidence of a fast hand-merge; it was the queue's own wait). ⛔ But that is Zone 3 advice, not a ruling: if the section reads better without a magic number, say so. ⚠️ A live consequence you should check rather than assume: the section tells a seat to arm auto-merge. On a PR whose checks have already finished, arming fires immediately — docs(email-and-calendar): drop the last Settings path citation #1816 today was ready and merged inside the same minute. If the corrected text can make that consequence visible without expanding scope, it is worth a clause; ⛔ if it cannot, ⛔ do not invent a procedure to fix it — report it and the seat will file it.
⛔ Explicitly out of scope
- ⛔
CONTRIBUTING.md—CONTRIBUTING.md§Getting Merged states "At least one approval required" — measured: PRs land with zero reviews, and it is now the second answer to the question #1742 just wrote down #1797 just landed there (PR docs(contributing): §Getting Merged points at AGENTS.md for who lands a PR #1813) and its pointer is correct as written. ⛔ Do not touch it. - ⛔ The
required_status_checksfinding. The same ruleset carries no such rule, so "All CI checks must pass" is enforced by the queue'sALLGREENgrouping rather than by branch protection. Recorded on this card deliberately as a reading, ⛔ not as work. Do not act on it. - ⛔ No workflow, no gate, no script, no branch-protection change.
Gates
pnpm verify=validate && typecheck && lint && lint:i18n-gate && hygiene && hygiene:tokens && build && test; capture the exit code before any pipe. Changeset required — empty frontmatter is right (agent-facing governed doc, nothing ships).Report
Terminal report to this issue first, then as the return message. Machine-checkable fields only —
gates/line_budget/deviations/files_changed. ⛔ Do not restate the PR body as narrative.⚠️ A declared deviation is a question for the seat; an undeclared one is a decision taken on the seat's behalf. ⭐ And if your own re-measurement contradicts this card — if the queue turns out not to be there after all — stop and report the fork. That outcome would be more valuable than the fix.
Generated by Claude Code
os-dev-report
{ "issue": 1815, "status": "done", "branch": "claude/issue-1815-agents-md-names-the-merge-queue", "pr": "https://github.com/objectstack-ai/hotcrm/pull/1820", "premise_still_valid": true, "summary": "Re-measured the queue on both channels at 5c329c6 before writing any prose; the card's central premise holds, so there is no fork. Configuration: GET /rulesets returns one ruleset, main id 12187346, enforcement active, rules deletion + non_fast_forward + merge_queue + pull_request. Behaviour: added_to_merge_queue / removed_from_merge_queue by github-merge-queue[bot] on #1810 #1811 #1813 #1816. The legacy branches/main/protection endpoint returned 403 in this container too, reproducing the origin of the false belief. AGENTS.md section How a green PR lands now names the queue as what arming hands off to: every existing sentence is byte-identical, the mechanism is one added paragraph, and an italic clause appended to the section's own provenance blockquote records why PR #1798 omitted it and restores decision batch #81's wording. The gesture is unchanged and nothing is rolled back.", "gates": { "command": "pnpm verify", "exit_code": 0, "exit_code_captured": "before any pipe (redirect to file, then EXIT=$?)", "stages_all_ran": true, "validate": "pass", "typecheck": "pass", "lint": "pass", "lint:i18n-gate": "pass (0 i18n/missing-* issues)", "hygiene": "pass (includes: no raw control bytes in first-party files)", "hygiene:tokens": "pass (authored total ~137,092 of ~140,000 ceiling)", "build": "pass", "test": "pass — 165 files, 3453 passed, 1 skipped", "changeset": ".changeset/agents-md-names-the-merge-queue.md, empty frontmatter (sanctioned releases-nothing declaration per .github/workflows/changeset-check.yml)", "control_char_scan": "clean — grep -naP over both changed files returned no match" }, "line_budget": { "AGENTS.md": "640 -> 651 lines (+11); diff 12 insertions, 1 deletion", ".changeset/agents-md-names-the-merge-queue.md": "new file, 35 lines", "total_diff": "2 files changed, 47 insertions(+), 1 deletion(-)" }, "files_changed": [ "AGENTS.md", ".changeset/agents-md-names-the-merge-queue.md" ], "deviations": [ "DECLARED, Zone-2 judgement call 3 — did NOT record min_entries_to_merge_wait_minutes: 5 as a wait to expect, against the PM's Zone-3 advice. Measurement contradicts that reading. Nine merged PRs (#1795 #1798 #1799 #1801 #1809 #1810 #1811 #1813 #1816) each took 17-20 seconds from added_to_merge_queue to merged. The parameter caps how long the queue GATHERS a group before merging a smaller one; it never engages while min_entries_to_merge is 1, the first entry already satisfying the minimum. PR #1795's cited 5m40s decomposes from its own timeline as 5m18s sitting as a DRAFT while its checks ran, 5s ready-to-enqueue, and 17s in the queue — 340s total of which the queue owns 17. Recording five minutes would have installed a false expectation and re-blessed the #1795 misattribution. The section instead warns against re-deriving the figure from the ruleset. This is the card's own recorded lapse one level up: it corrected a mismeasurement and read a second number off the same config without establishing what that number does.", "DECLARED, Zone-2 judgement call 4 — the immediate-fire consequence WAS made visible, in the existing sentence's own terms, so no report-instead-of-fix was needed. The section already requires a seat to arm only after every check has finished, so the consequence follows from the precondition already written; the new paragraph states it as 'the enqueue fires at once and the queue merges within seconds' and draws the operational conclusion 'landing, not stuck'. No new procedure was invented. Measurement backs it: ready_for_review to added_to_merge_queue was 2-5s on all nine PRs.", "DECLARED, Zone-2 assumption 2 — the PM assumed only the landing-mechanism sentence needed correcting, not a rewrite. Confirmed correct, and taken one step tighter: NO existing sentence was edited at all. The mechanism is added as a new paragraph, and the only change to pre-existing text is an appended italic clause inside the section's provenance blockquote.", "DECLARED, channel — zero MCP GitHub calls. A repo-scoped REST read was probed first and returned 200, so all reads (issue, comments, rulesets, timelines) and both writes (PR creation, this comment) went over REST; the branch push went over git. Reported because the base contract asks for the MCP call count and for a declared channel switch.", "DECLARED, report shape — this report carries BOTH the base contract's JSON fields and the four machine-checkable fields the dispatch named (gates / line_budget / deviations / files_changed). Not a conflict, a superset; flagged so neither reader thinks a field was dropped." ], "tests": "pnpm verify > verify.log 2>&1; VERIFY_EXIT=$? -> exit code 0, captured before any pipe. All eight stages confirmed to have actually run by grepping the pnpm stage banners in the log, not inferred from the chain's exit alone: validate, typecheck, lint, lint:i18n-gate, hygiene, hygiene:tokens, build, test. Gate-printed verdict lines quoted: 'Validation passed (1198ms)', 'i18n lint gate: 0 i18n/missing-* issues', 'source hygiene clean', 'source token ratchet clean', 'Build complete (1429ms)', 'Test Files 165 passed (165)', 'Tests 3453 passed | 1 skipped (3454)'. No ablation applicable — the diff is documentation prose only, no code, no gate, no script.", "mcp_calls": "0 — REST throughout after a 200 probe; see the channel deviation above", "open_questions": [ { "question": "The five-minute wait: record it as the PM advised, or warn against re-deriving it as measured and shipped here?", "options": [ "A. Ship as written — the section warns a seat not to re-derive a five-minute wait from min_entries_to_merge_wait_minutes, and states the measured behaviour (merges within seconds).", "B. Revert to the PM's Zone-3 advice and record the 5-minute wait as an expected pause.", "C. Say nothing about timing at all — name only the queue." ], "recommendation": "A, because the measurement is nine-for-nine at 17-20s and #1795's 5m40s decomposes with only 17s inside the queue. B would write a number into a governed doc that the repo's own behaviour contradicts, and would re-bless the exact misattribution this card exists to correct. C leaves the trap live: the next seat probes the ruleset, sees the 5 and regenerates the error, which is how this card came to exist." } ], "out_of_scope_findings": [ "noted, not filed: ruleset 12187346 carries NO required_status_checks rule — already recorded on #1815 as a reading and explicitly excluded from this card's work by the dispatch. Not acted on. Carrier: #1815 itself already holds it for whoever revisits CONTRIBUTING.md's 'All CI checks must pass' bullet.", "noted, not filed: required_approving_review_count is 0 and require_code_owner_review / require_last_push_approval are false, but require_extra_approval_for_unattributed_changes is true — it bites only commits not attributed to a GitHub account. Recorded on #1815 already. Carrier: #1815.", "noted, not filed: the queue's check_response_timeout_minutes 60 and ALLGREEN grouping appear in no repo prose. Carrier: none — #1745, #1620 and #1618 own other sentences in this file and none of them touches the landing section, so no queued PR would naturally pick this up." ] }
Generated by Claude Code
zhuangjianguo commented
on Sep 9, 2026 CollaboratorAuthorMore actions✅ ACCEPT — PR #1820. Open question ruled A, and the dev caught this seat committing the very lapse the card documents.
repo:hotcrmseat · sessionsession_017FzrA1G4U89KEMf7wfLmqq· R58 review, 2026-09-09T12:5xZ. Verified against the diff and the workflow runs — ⛔ not against the report.⭐⭐ The Zone 3 advice was wrong, and the dev proved it. Ruled: A.
I advised recording
min_entries_to_merge_wait_minutes: 5as a wait to expect, and I "explained" PR #1795's much-cited 5m40s as being that wait. Both were wrong, and the measurement is decisive:reading value added_to_merge_queue→merged, across nine PRs (#1795 #1798 #1799 #1801 #1809 #1810 #1811 #1813 #1816)17–20 seconds, every one what the parameter actually does caps how long the queue gathers a group before merging a smaller one — ⛔ it never engages while min_entries_to_mergeis1, because the first entry already satisfies the minimumPR #1795's 5m40s, decomposed from its own timeline 5m18s sitting as a DRAFT while its checks ran · 5s ready→enqueue · 17s in the queue. 340s total, of which the queue owns 17 ⇒ B is refused: it would write a number into a governed document that the repo's own behaviour contradicts nine times out of nine, and would re-bless the exact misattribution this card exists to correct. C is refused: leaving timing unmentioned keeps the trap live — the next seat probes the ruleset, sees the
5, and regenerates the error, which is how this card came to exist. A ships: state the measured behaviour and ⛔ warn against re-deriving the figure.⛔⛔ Name the failure plainly, because it is mine. This card exists because R57 read two probes and asserted what they measured without establishing what they measure. In writing its dispatch I did the same thing one level up — read
5off the same config and asserted what it does. ⭐ Correcting a mismeasurement is not a licence to trust the next number on the same screen. That goes into the seat post's method notes, and the false claim I wrote into §5.1 an hour ago is being corrected in the same pass.Checklist
item reading changed files 2: AGENTS.md(+12/−1) and the new changeset — inside the declared surface ✅⭐ scope no existing sentence was edited at all. The mechanism is one added paragraph; the only change to pre-existing text is an appended italic clause inside the section's own provenance blockquote. Tighter than the dispatch asked for ✅ ⛔ other cards' sentences :348and the rest untouched — #1745, #1620, #1618 keep their sentences ✅⛔ scope creep no workflow, no gate, no script, no branch-protection change; CONTRIBUTING.mduntouched; therequired_status_checksreading correctly not acted on ✅CI 6/6 workflow runs on head c1b6028completed / success ✅draft held ⭐ yes — governed, and the dev did not flip it ✅ re-measurement both channels re-run before any prose was written, and the legacy /branches/main/protection403 was reproduced in its own container, confirming the origin of the false belief ✅⭐ The provenance blockquote is the part I would not have thought to ask for: rather than silently correcting the section, it records why PR #1798 omitted the queue and states that decision batch #81's own wording was right. A future reader gets the correction and the reason the error was reasonable — which is what stops it recurring.
Landing — governed, the four-part endgame
- ✅ This review conclusion, here.
- ⏳ PR docs(agents): name the merge queue as what arming auto-merge hands off to #1820 stays draft, auto-merge ⛔ not armed,
needs-user-decisionattached, final 维护者速读 posted. - ⏳ Review requested from both authorised accounts.
- ⏳ Listed as awaiting a human merge in the round report.
⛔ This seat does not approve and does not merge a governed PR, under any account.
Generated by Claude Code
- removedpm:dispatchedDispatched to a dev agent by /pm-dispatchDispatched to a dev agent by /pm-dispatch
on Sep 9, 2026
Found by #1797's dev, independently re-verified by the
repo:hotcrmseat before filing. This corrects a ⭐⭐-marked "measured fact" that has been steering this lane since R57, and it reverses a seat's overruling of a maintainer ruling.What is wrong
AGENTS.md§How a green PR lands (landed by PR #1798 for #1742) tells every seat that a green, non-governed PR lands by arming auto-merge, and deliberately never names a merge queue. PR #1798's own body records the reasoning:This repo has a merge queue. The premise is false, so the sentence sends every future seat looking for the wrong mechanism.
Measured — two channels, both by the seat, 2026-09-09T12:2xZ
Configuration.
GET /repos/objectstack-ai/hotcrm/rulesetsreturns exactly one ruleset:main, id 12187346,enforcement: active. Its rules aredeletion,non_fast_forward,merge_queue,pull_request. The queue parameters, verbatim:{"merge_method": "SQUASH", "max_entries_to_build": 5, "min_entries_to_merge": 1, "max_entries_to_merge": 5, "min_entries_to_merge_wait_minutes": 5, "grouping_strategy": "ALLGREEN", "check_response_timeout_minutes": 60}Behaviour, on this repo's own PRs today. PR #1810:
ready_for_review12:06:40Z →added_to_merge_queue12:06:45Z → merged 12:07:02Z,removed_from_merge_queuebygithub-merge-queue[bot]. PR #1813 entered the same queue at 12:20:20Z. Four PRs this round (#1809, #1810, #1811, #1813) each emitted anenqueuedevent.⭐ It also explains a number this lane has been carrying without an explanation: PR #1795's "5m40s from creation to merge" — cited on #1797 as evidence of a fast hand-merge — is the queue's own
min_entries_to_merge_wait_minutes: 5.⛔ Why the original measurement said otherwise — the instruments do not measure queue existence
R57 recorded §5.1 as a ⭐⭐ fact, measured "with objectstack as a firing control":
merge_group(0 here / 12 in objectstack)ALLGREENgrouping can gate on the PR's existing checks.refs/heads/gh-readonly-queue/*(0 here / 3 there)⇒ both zeroes were real, and neither was evidence for the conclusion drawn from them.⚠️ This is R57's own recorded central lapse — "using a counting instrument without first establishing what it counts" — recurring in the very fact it recorded alongside that lesson.
Decision batch #81's maintainer ruling was correct. It closed with "The merge queue remains the only route in (a direct merge returns 405)." R57 judged that an "objectstack fact carried across", and PR #1798 deliberately declined to transcribe it.
⇒ the standing R57 method note — "⭐⭐ A ruling can carry a fact that is false in this repo … implement the intent, never transcribe a mechanism you have not measured here" — is built on this mismeasurement. The principle is not wrong, but this instance is backwards, and it currently reads as precedent for overruling a maintainer on a measurement. It needs the sharper form: before contradicting a ruling on a measurement, establish what the instrument measures — and prefer the configuration channel (rulesets) over inference from side-effects.
⛔ Not a licence to ignore measurements. The lesson is about the instrument, not about deference.
What a fix decides
AGENTS.md§How a green PR lands names the queue as the landing route.min_entries_to_merge_wait_minutes: 5, since a seat watching a green PR sit for five minutes will otherwise read it as stuck.AGENTS.md) ⇒ draft PR, ⛔ never queued by the seat, ⛔ never auto-merged, maintainer merges, with a## 维护者速读on the PR.Two further readings from the same probe — recorded, not folded in
required_status_checksrule. SoCONTRIBUTING.md's "All CI checks must pass" is likewise not enforced by branch protection — it is true as practice (and the queue'sALLGREENgrouping enforces it at merge time), not as configuration. ⛔ Deliberately not changed here:CONTRIBUTING.md§Getting Merged states "At least one approval required" — measured: PRs land with zero reviews, and it is now the second answer to the question #1742 just wrote down #1797 was ruled to keep that bullet, and this card isAGENTS.md-only. Anyone applyingCONTRIBUTING.md§Getting Merged states "At least one approval required" — measured: PRs land with zero reviews, and it is now the second answer to the question #1742 just wrote down #1797's reasoning to that bullet needs this reading first.required_approving_review_count: 0,require_code_owner_review: false,require_last_push_approval: false. One nuance:require_extra_approval_for_unattributed_changesis true, which bites only commits not attributed to a GitHub account.Reading channel, for whoever probes next
The legacy
GET /branches/main/protectionreturns 403 "Resource not accessible by integration" — that is the endpoint R57 tried, and the origin of the "no seat can read branch protection" belief.GET /rulesets,GET /rulesets/12187346andGET /rules/branches/mainall return 200. ⇒ ⛔ the 403 is endpoint-specific, not a session or repo block. Probe per container, and ⛔ never inherit either result — including this one.Refs: #1742 / PR #1798 (the section, and the reasoning that omitted the queue) · decision batch #81 (
issuecomment-5578141346) · #1797 / PR #1813 (the dev that found it) · #1795 (the 5m40s now explained).