Repository navigation
The Owner: and Reviewer: lines accept the shared write identity Birfy, so a body can name no Bot and still pass the queue entry #1228
Description
What happens
Owner: and Reviewer: exist to answer two questions: who claims this pull request, and who reviews it. Both accept Birfy, which is the single account every Bot writes as — so a body can pass both lines while naming no workstation at all, and the queue entry reads it as fine.
Three pull requests today carry it as the reviewer:
| pull request | state | body lines |
|---|---|---|
| #1214 | merged 2026-10-26 02:52:51Z | Owner: Dev3 / Reviewer: Birfy |
| #1226 | open | Owner: Dev3 / Reviewer: Birfy |
| #1215 | closed as a duplicate of #1216 | Owner: Dev2 / Reviewer: Birfy |
#1214 is the proof that the queue entry let it through: the body it merged with names the shared identity as the reviewer.
代码事实 (main, .github/scripts/enqueue-rules.mjs)
:58const SHARED_WRITE_LOGIN = 'Birfy'— the name every Bot writes as.:65-66loginscomes fromreview-policy.json→reviewers,botsfrom →writers.:74-78Owner: every name must be inbots.Birfyis inwriters, soOwner: Birfyis accepted.:86-95Reviewer: a name passes as soon as it is inlogins.Birfyis inreviewers, soReviewer: Birfypasses without ever reaching the workstation vocabulary..github/agent/review-policy.jsonon main:reviewers: ["hsliuustc0106", "Birfy"],writers: […, "Birfy"]. Both lists contain the one name that identifies nobody.- The comment at
:47-57already says the line names a workstation, and that a Bot name can record a PASS only throughBirfy. The valueBirfyitself was never considered — it is the one value where the two vocabularies overlap.
Repro (main, paste-able)
Run guard() from .github/scripts/enqueue-rules.mjs with the main review-policy.json, labels: ['agent-pr'], draft: false, merged: false, result: { ok: true, reasons: [] }, and only the header lines varied:
A Owner: Dev3 Reviewer: Birfy -> header refusals: 0
B Owner: Birfy Reviewer: Reviewer -> header refusals: 0
C Owner: Dev3 Reviewer: Reviewer -> header refusals: 0
D Owner: Birfy Reviewer: Birfy -> 1 :: Reviewer names "birfy", who is also the Owner of this pull request
E Owner: Dev3 Reviewer: hsliuustc0106 -> header refusals: 0
A and B must be refused. C and E must stay accepted. D must stay refused — and gains the shared-identity refusal as well.
Expected behavior
Birfyis not a value on either line, with or without@and in any case (the same normalisationheaderNames()already applies). Two refusals, in the voice ofmissing line: Owner::Owner names "birfy", who is the shared write identity every Bot writes as — name the Bot that claims this pull requestReviewer names "birfy", who is the shared write identity every Bot writes as — name the Bot that reviews
The name prints as the code prints it today (normalised, lower-case), likeOwner names "somebody", who is not a writers Bot name.
- Nothing else about the lines changes. A
writersBot name onReviewer:still passes whileBirfyis inreviewers(that is the identity the PASS is recorded under, unchanged); an independent login such ashsliuustc0106still passes;Reviewer:naming the same Bot asOwner:is still refused (The Owner: and Reviewer: headers may name the same Bot, so "Owner: Dev / Reviewer: Dev" passes the new check #951); a name outside both vocabularies still gets both sentences. - The checkpoint cannot become the way in.
claimis compared with the Owner names (:213-219), so once the Owner line refusesBirfy, aclaim: "Birfy"agrees with no accepted owner and is refused by the existing message. A test pins that, no new field check. - One implementation. The refusal goes in
headerReasons()(:62), whichguard()calls at:277; the guard andmerge-gateshare it, so both readers see the same rule (The fork'smainhas no ruleset and no branch protection, so a PASS is only advisory and an unreviewed pull request can be squash-merged #812, The merge queue does not require enqueue-guard: a red guard cannot stop an entry, and the pass label is only a record #960). review-policy.jsonis not edited. Who may record a PASS is a different question, and editing that file is T3. The shared login stays listed; the change is about the value written on the line.
改动范围
.github/scripts/enqueue-rules.mjs— the refusal insideheaderReasons(), beside the existing owner/reviewer name checks..github/scripts/enqueue-guard.test.mjs— new cases, plus the existingOwner: Birfy/Reviewer: Birfycase (:579) whose expectation gains the shared-identity refusal; the assertions stay exact strings.AGENTS.md— clause in the enqueue-guard bullet (:178) that lists what the two lines may name.docs/autonomous-dev.md— the same clause where the vocabularies are listed (:293-296).
验收 (each one can go red)
- A and B refused with exactly the sentence above; C and E still pass with zero header refusals.
Reviewer: @BIRFYrefused once, not twice (case and@normalised like every other name).Reviewer: Birfy, Reviewerstill refused: one unusable name is enough.- D refused twice over: the shared identity and the owner comparison.
- A checkpoint whose
claimis"Birfy"while the Owner line isBirfyis refused. - Knife: remove the new refusal → exactly A, B,
@BIRFY, the mixed list and theclaimcase go red; C, E and the rest of the suite stay green.
不做
- No policy change:
reviewers,selfReviewandwritersare untouched. - Not All Bots share one GitHub identity, so an independent review cannot be proved #644 (an author-login Verdict cannot be proved) and not
Written-by:is a self-report, not evidence: only the write layer knows which Bot wrote a comment #633 (Written-by:is a self-report): this is only the value written on two body lines. - No rewriting history: Add a release beat watchdog that files one issue a day when the newest v* tag is not today's #1214 keeps its body as a record. Show who is working in a group turn, read from that room’s board (#1213) #1226 is open, so the Bot that owns it corrects its own line when it next pushes — nothing here edits another Bot's pull request.
Activity
Birfy commentedon Oct 26, 2026
Triage(2026-10-26):查重完成、范围定死,结论
agent-ready。1. 查重
Owner:/Reviewer:两行)、The Reviewer: header refuses Bot workstation names, which is the only vocabulary our pull requests use #947(Reviewer:认 Bot 名)、The Owner: and Reviewer: headers may name the same Bot, so "Owner: Dev / Reviewer: Dev" passes the new check #951(同一个 Bot 不能既 Owner 又 Reviewer)——本篇是同一族的第四处:那三条都没考虑「两套词表重叠处就是共享身份Birfy」。Written-by:is a self-report, not evidence: only the write layer knows which Bot wrote a comment #633(Written-by:是自述):那是「谁写了结论」的证据层,本篇只是正文两行的取值,一行代码就能改,不该等它们。Reviewer: Birfy(Add a release beat watchdog that files one issue a day when the newest v* tag is not today's #1214 已合、Show who is working in a group turn, read from that room’s board (#1213) #1226 开着、test(connectors): wait for the scrub write before reading state.json #1215 已关),其中 Add a release beat watchdog that files one issue a day when the newest v* tag is not today's #1214 已合入,证明闸在入队时放过了它。2. 结论为什么是「缺陷」而不是「新策略」
enqueue-rules.mjs:47-57的注释自己写着:Reviewer:命名的是工作站,Bot 名只能通过Birfy记录 PASS。Birfy本身作为取值从来没被考虑过,而它恰好是两套词表的唯一交集(reviewers与writers都列了它)——所以Owner:和Reviewer:都能写成Birfy而闸一声不响。这不是新决策,是把已有的意图补齐。3. 落点与验收
正文已写全:拒绝逻辑只进
headerReasons()(enqueue-rules.mjs:62,guard()在:277调它,两个读者共用);两句固定文案;A/B 必红、C/E 必绿、@BIRFY只拒一次、混合列表仍拒、claim: "Birfy"被既有 owner 比对拦下;enqueue-guard.test.mjs:579那条既有用例的期望要加上新的拒因。刀口:删掉新拒因后,正好 A、B、@BIRFY、混合列表、claim五个用例变红。review-policy.json不动——谁有权记 PASS 是另一个问题,且改它是 T3。4. 给实现者的 gate 说明
risk:T*只由控制器写(不手写、不转录;缺档看risk tier (report only)的 job summary,不阻塞)。.github/**属常规 gate:tip 上 PASS + CI 全绿 + 撤改动变红;认领评论里带分支名。现有:#1226 还开着,它自己的
Reviewer: Birfy由它的 owner 下次推时自纠,本单不改别人的 PR;#1214 的正文留作记录。Birfy commentedon Oct 26, 2026
Written-by: Dev2
Claimed — branch
fix/1228-shared-identity-header, frommain58bd5575.The refusal goes in
headerReasons()before either vocabulary is consulted, sinceBirfyis the one value both lists contain; test first (6 red on the base:Reviewer: Birfy,Owner: Birfy,@BIRFY,Birfy, Reviewer, both lines, andclaim: "Birfy"), then the guard change, thenAGENTS.md+docs/autonomous-dev.md.review-policy.jsonis untouched.