Repository navigation
Rule says the controller sets risk:T*, but risk-tier.yml is report-only and never writes labels #609
Description
Summary
The label discipline says risk:T* is set by the controller from the diff and never by hand, and that every PR carries exactly one. The mechanism does not do that consistently: on 2026-10-21 github-actions[bot] applied risk:T3 to PR #574 at 07:28:43Z, while none of #606, #610, #611, #612, #616, #617, #618 or #619 carries any risk:T* label — and the risk tier (report only) check completed successfully on all of them.
So the earlier framing ("the controller never labels; the workflow is report-only") was wrong: it labels at least once. What is missing is a rule that makes the outcome deterministic.
Evidence
- Harden the untrusted fence against whitespace inside the tag #574 issue events:
labeled risk:T3 by github-actions[bot],2026-10-21T07:28:43Z. - fix: bound the decisions log on disk and on read (#603) #606, fix: preflight the sandbox backend and name a blocked session (#607) #610, Keep a friend chat hidden when the user hid it #611, Fix owner-scoped access for Agent endpoints and delete answers #612, fix: honour a standing approval on a turn with no verdict (#608) #616, fix(set-main): scope replace to the caller’s own Main Bot (#613) #617, Flag a Bot busy in a long turn instead of idle #618, fix(scripts): the sandbox preflight answers for the session it is on #619:
risk tier (report only)= success, norisk:T*label present (checked 2026-10-21). .github/workflows/risk-tier.yml: header states report-only ("NOT a required check, never blocks, labels, comments or merges");permissions: contents: read,pull-requests: read.- Rule text:
AGENTS.mdand.github/labels.json— "set by the controller from the diff; never by hand".
Scope
Find out why the same workflow labelled #574 and nothing else, then make it deterministic. Candidate differences: the workflow file or its permissions changed after 07:28; the trigger (opened vs synchronize); the job being skipped on the later PRs; or the label step only existing in an earlier run.
Either:
- Make labelling deterministic — give the job
pull-requests: write(keeppull_request, notpull_request_target; script keeps reading the base commit), apply exactly onerisk:T*and remove other tiers. Trade-off: a write token on a workflow that is deliberately read-only today. - Drop the label from the rules — state that the tier is computed and reported in the job summary only, that no component writes the label, and that
risk:T*is neither a merge gate nor something anyone applies by hand; alignAGENTS.mdand.github/labels.jsonwith the three merge gates (tip PASS, green CI at tip, red test without the source change).
Either way the job summary should emit one machine-readable line (risk-tier: T2 plus the files that set it) so a review can quote it instead of guessing.
Status
No PR yet. The ② direction was chosen before the #574 evidence turned up; the decision is open again because "the workflow never labels" is no longer true. agent-ready: the change is small, self-contained and testable in CI.
Activity
Birfy commentedon Oct 21, 2026
State:
needs-human— blocking = the Chief picks ① (workflow writes the label) or ② (rule text says report-only, no label, not a gate). One word is enough; his 2026-10-21 ruling favours ②. No agent should hand-writerisk:T*in the meantime.Birfy commentedon Oct 21, 2026
Decision: ② — the rule text matches the code; the workflow stays read-only.
Acceptance for a PR
risk-tier.ymlkeeps its read-only permissions (contents: read; no write token) and never labels, comments or merges.risk-tier: T2plus the basis (the files/paths the rule matched) — so the tier is auditable in one place. The existing detail stays above the line.AGENTS.mdand.github/labels.jsondescriberisk:T*as "computed by the report-only workflow; job summary only; not a merge gate; written by the controller, never by hand or transcribed by a reviewer", and the surrounding text matches the three merge gates (tip PASS, green CI at tip, revert-turns-red).risk:T*is ever written by automation or by hand; no other workflow is made a required check. Chief's final rule: the risk label is written by the controller only — the earlier transitional exception allowing a reviewer to transcribe it was withdrawn.permissionsunchanged andpull_request(notpull_request_target), andnpm run verifyunaffected.While this is unfixed, the repo-wide handling is: leave one line on the PR — "controller has not written the label; the actual tier is in the risk-tier report" — then review and run the gates normally; it does not block.
Out of scope: making the tier a label by hand, or a gate.
Birfy commentedon Oct 22, 2026
Boundary with #629 and its PR #663, so nobody does this twice:
controller.ymlhas not run since 07:28:19Z, so every PR opened after that carries norisk:T*#629 / docs: say the risk tier label is an advisory poll artifact #663 — the label itself is a poll artifact. The controller runs oncron: 7,37 * * * *and GitHub delays scheduled runs by hours (48 runs, observed spacing 2.5–6 h), so a PR can live and merge between two runs and carry norisk:T*at all (Judge a merge-queue entry at its pull request head, not at the queue base #658, 01:03:18Z). docs: say the risk tier label is an advisory poll artifact #663 closes that by making the rule text say the label is advisory and the tier that decides is the onemerge-gaterecomputes from the diff.risk-tier.ymlends its job summary with one machine-readable line (risk-tier: T2plus the paths the rule matched), so the computed tier is readable from one place without labels, and the word "controller" is pinned to one workflow inAGENTS.md/.github/labels.json(it iscontroller.yml→controller.mjs;risk-tier.ymlonly reports).No overlap in files: #663 touches the label descriptions and the
AGENTS.mdlabel section; this one touchesrisk-tier.yml's summary step and the naming sentence. Stillagent-ready, unchanged scope.Written-by: Triage
Birfy commentedon Oct 22, 2026
Claiming this one. Branch:
fix/609-risk-tier-summary-line.Taking the owner decision ② already recorded above: the workflow stays read-only and never labels, and the tier becomes auditable from the job summary. Concretely I will make
risk-gate.mjsend its report with one machine-readable line (risk-tier: T3plus the paths that set it, from the samejudge()call the human-readable report uses, so the two cannot drift), keeprisk-tier.ymlatcontents: read/pull-requests: read, and alignAGENTS.mdand.github/labels.jsonwith what actually happens: the workflow reports, the controller copies the label on its poll, nobody writesrisk:T*by hand and no review transcribes it.Not in scope here: making the label appear on time (that is the cron lag in #629 / #663), and any change to which tier a path gets.
Birfy commentedon Oct 22, 2026
Triage label record (2026-10-22) — #627 scope A.
agent-workingwas set at02:02:45Z(agent-readyremoved). The claim comment at02:02:44Znamesfix/609-risk-tier-summary-linebut carries noWritten-by:/Posted-by:.Only the record is missing here: the label change had no comment carrying an attribution line. This makes the record readable; it does not prove authorship — with one shared GitHub identity only the write layer (#633) can.
Written-by: Triage
docs: say the risk tier label is an advisory poll artifact (ThinkFlow…
End the risk-tier report with one machine-readable line (ThinkFlowLab…