Skip to content

controller.yml has not run since 07:28:19Z, so every PR opened after that carries no risk:T* #629

Closed

Description

@Birfy

Observed

risk-tier does not write the tier labels — it only reports. The label is written by the scheduled workflow .github/workflows/controller.yml (cron: 7,37 * * * *), which calls .github/scripts/controller.mjs:129.

That workflow last ran on 2026-10-21 at 07:28:19Z and has not run since (checked via GET /repos/ThinkFlowLab/FlyBot/actions/workflows/controller.yml/runs, run at ~12:10Z).

Evidence

Runs, newest first (successful schedule runs only):

created_at event conclusion head
2026-10-21T07:28:19Z schedule success dad73d63
2026-10-21T01:57:23Z schedule success 4f6a53d7
2026-10-20T23:21:09Z schedule success 7ebe0547
2026-10-20T20:28:07Z schedule success 7ebe0547
2026-10-20T16:49:50Z schedule success b8405ca0

44 runs in total for the whole history. The declared schedule is every 30 minutes (48 runs/day); the observed spacing is hours, and the gap after 07:28:19Z is the longest yet (no run in ~4.5 hours, across many pushes to main).

PRs opened after the last successful run, all with no risk:T* label:

#606, #610, #611, #612, #616, #617, #618, #619.

#574 is the only recent one that carries risk:T3, and it was opened inside the 07:28 window — which is also why it looked like the odd one out in earlier triage counts.

Consequence

The risk gate is vacuous for every PR opened after 07:28: there is no tier to read, so "no risk:T* label" tells a reviewer nothing about risk and everything about the workflow not having run. Anything that treats a missing tier as low risk fails open; anything that treats it as blocking stalls the queue. This is the same failure shape as #602 (the queue ignored hold) and #609 (the controller's labels were assumed to exist).

Second defect, independent of the schedule

Even with a correct schedule, a pull_request-triggered job cannot label a fork PR: the workflow gets a read-only GITHUB_TOKEN for pull_request runs from forks, so permissions: pull-requests: write does not help. The PRs missing a tier are precisely the external ones (#611, #619). Three options, none free:

  1. Same-repo branches only — label only what the event can label, and state the limitation in AGENTS.md instead of implying full coverage.
  2. pull_request_target with the diff read through the API, and never checkout or execute the head commit. pull_request_target running head code is a worse hole than a missing label; if this option is taken, the workflow must not touch head.sha at all.
  3. Keep schedule + add workflow_dispatch as the fallback, labelling by polling open PRs — which only works if the schedule itself is reliable (this issue).

Suggested fix

  • Add a freshness check rather than trusting the schedule: the merge gate should refuse to enqueue when the tier report is older than N minutes for the current head SHA, instead of reading whatever label happens to be present.
  • Add workflow_dispatch and a controller --dry-run path so a stalled schedule can be re-run by hand and the gap is visible in the run list.
  • Decide which of the three fork options above is policy, and write it into AGENTS.md next to the risk-tier rules (Rule says the controller sets risk:T*, but risk-tier.yml is report-only and never writes labels #609).

Acceptance

  • A PR opened while the controller has not run does not silently pass the risk gate: either the gate blocks with "no tier report for this SHA", or a manual re-run produces the label.
  • The workflow's staleness is observable without reading run history by hand (a status, a label, or a check).
  • The fork-PR policy is written down and matches what the workflow can actually do.

Recorded by: Chief (owner proxy), from the live Actions API. Defect found by Dev while implementing #609; the four evidence items are quoted from the implementation Lead's report.

Activity

  1. added
    bugSomething isn't working
    area:automationScheduled tasks and automation
    area:securityAuth, grants, approvals, secrets
    on Oct 21, 2026
  2. Birfy commented on Oct 22, 2026

    @Birfy
    CollaboratorAuthor

    Fresh evidence changes what this is — the workflow did not stay stopped, but the label is a poll, and the poll leaves a hole.

    Controller runs since the gap (GET /actions/workflows/controller.yml/runs): 13:09:48Z, 18:13:49Z, 21:56:47Z, 00:36:16Z — all schedule, all success. It wrote risk:T3 on #640 at 18:14:26Z and on #654, so the "no PR opened after 07:28:19Z carries a risk:T*" half of the report is no longer true and the 5h41m gap closed by itself.

    What is still true: the label only exists if the controller happens to run while the PR is open. #658 merged at 01:03:18Z with zero labels — not risk:T*, not agent-pr, not a type — because it was opened after the 00:36:16Z run and merged before the next one. Nothing at merge time required a tier.

    Since #640 and #658 the merge gate computes the tier itself from the diff (base copy of risk-gate.mjs + risk-rules.json; the label never exempts anything), so an absent label no longer changes a merge decision — it changes only what a person reading the PR sees. The thing to fix is therefore the rule, not the mechanism: AGENTS.md and the .github/labels.json description promise exactly one risk:T* per PR, which a 30-minute poll cannot guarantee.

    Scope (one PR, docs-first): state in AGENTS.md and in the risk:T* label descriptions that the label is advisory, may be absent until the next controller run, and that the authoritative tier is the one the gate computes from the diff at merge time; keep the existing test that the gate never reads risk:t0/t1 (added by #640) as the guard that this wording stays true.

    Alternative if a stale label is judged too costly: make controller.yml also run on pull_request. That is a larger change than the rule text and does not remove the window entirely (a PR can be opened and merged inside one run).

    Written-by: Triage

  3. added
    agent-readyMaintainer-approved spec: an agent may take it. Only maintainers set this; never in a template
    on Oct 22, 2026
  4. Birfy commented on Oct 22, 2026

    @Birfy
    CollaboratorAuthor

    Claiming: branch fix/629-controller-risk-labels.

    Boundary with #609: #609 is about what the controller's labels are allowed to mean (the rule set, and risk:T* as a policy statement). This one is about the label as a poll artifact — a 30-minute schedule cannot promise a tier label on every PR, and #629 is the observed consequence. This PR does not touch risk-gate.mjs, risk-rules.json, merge-gate.mjs or controller.mjs.

    Checked first, so the fix targets the right layer:

    Scope (one PR, docs-first): make the written promise match what a poll can deliver — AGENTS.md (labels section), the four risk:T* descriptions in .github/labels.json, and docs/controller.md (the PR row plus a Limits bullet with the observed spacing). Rule: a missing risk:T* means "the poll has not seen this PR yet", never T0/T1, and never a reason to block; the authoritative tier is the one merge-gate recomputes from the diff. Guarded by a new .github/scripts/risk-label-docs.test.mjs.

    Not in scope (follow-ups, not silently decided here): adding a pull_request/pull_request_target trigger to controller.yml so labels land at PR-open time. That is a policy choice among the three fork options in the issue (and a token-permission change), so it stays a separate decision rather than something this PR does.

  5. added
    agent-workingAn agent has claimed this issue (the claim comment names the branch)
    and removed
    agent-readyMaintainer-approved spec: an agent may take it. Only maintainers set this; never in a template
    on Oct 22, 2026
  6. self-assigned this
    on Oct 22, 2026
  7. removed
    agent-workingAn agent has claimed this issue (the claim comment names the branch)
    on Oct 22, 2026
  8. added 2 commits that reference this issue on Oct 23, 2026
    79f4742
    372b064
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

area:automationScheduled tasks and automationarea:docsDocumentationarea:securityAuth, grants, approvals, secretsbugSomething isn't working

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions