1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
name: issue-integrity
# Primarily a schedule, because what these three audit is the *existing* state of the issue tracker
# rather than the diff of any one commit -- a doc's claim about an issue goes stale when the
# **issue** moves, which is nobody's push. Failing a commit for that would punish the wrong person
# at the wrong time; failing a weekly run produces work, which is what this is. `workflow_dispatch`
# re-runs it on demand, e.g. right after closing a batch of issues.
#
# The `pull_request` trigger does not revisit that. It is the *converse* case: when a PR edits one
# of these scripts, or the file a script reads, the verdict becomes attributable to the diff again,
# and a gate that changes without ever running is a gate nobody has tested. Each job below is gated
# on its own inputs, so a PR only ever sees the check it could have broken -- and a change to
# `check-issue-triage.sh` now self-tests against the live tracker in the PR that makes it, instead
# of first executing days later on a Monday.
#
# Tracker drift alone still reaches only the schedule, which is the half of the original reasoning
# that was always right.
on:
schedule:
- cron: '17 6 * * 1'
workflow_dispatch:
pull_request:
permissions:
issues: read
contents: read
pull-requests: read
jobs:
# Same two rules as `main.yml`'s `changes` job: the filter lives in `if:` (a skipped job passes a
# required check, an `on.*.paths`-filtered workflow hangs one), and it only ever narrows a
# `pull_request` run -- `schedule` and `workflow_dispatch` always run everything, which is the
# audit this workflow exists for.
changes:
runs-on: ubuntu-latest
outputs:
shas: ${{ steps.filter.outputs.shas }}
claims: ${{ steps.filter.outputs.claims }}
rustdoc: ${{ steps.filter.outputs.rustdoc }}
triage: ${{ steps.filter.outputs.triage }}
decisions: ${{ steps.filter.outputs.decisions }}
steps:
- uses: actions/checkout@v4
# Pull-request-only, for the reason spelled out in `main.yml`'s `changes` job: a throw here
# would fail this job, skip every job that `needs:` it, and report green having audited
# nothing.
- uses: dorny/paths-filter@v3
id: filter
if: github.event_name == 'pull_request'
with:
filters: |
shas:
- 'scripts/check-closed-issue-shas.sh'
- '.github/workflows/issue-integrity.yml'
claims:
- 'scripts/check-doc-issue-claims.sh'
- '*.md'
- '.github/workflows/issue-integrity.yml'
rustdoc:
- 'scripts/check-closed-issue-rustdoc-refs.sh'
- 'scripts/lib-rustdoc-issue-refs.sh'
- '**/*.rs'
- '.github/workflows/issue-integrity.yml'
triage:
- 'scripts/check-issue-triage.sh'
- '.github/labels.tsv'
- '.github/workflows/issue-integrity.yml'
decisions:
- 'scripts/check-decision-issues-recorded.sh'
- 'ARCHITECTURE.md'
- 'AGENTS.md'
- '.github/labels.tsv'
- '.github/workflows/issue-integrity.yml'
closed-issue-shas:
needs: changes
if: github.event_name != 'pull_request' || needs.changes.outputs.shas == 'true'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
# Full history, not the default shallow clone: `check-closed-issue-shas.sh` needs every
# commit reachable, to tell "cited SHA never merged" apart from "cited SHA is just old".
fetch-depth: 0
- name: Closed issues must not cite commits that never reached main
env:
GH_TOKEN: ${{ github.token }}
run: ./scripts/check-closed-issue-shas.sh
# Checks only the annotated `[#N](…) (closed)` form -- see the script header for the measured
# reason free prose is out of scope. Its filter is root-level `*.md` and not `**/*.md` because
# that is precisely what the script scans (`grep -ronE … -- *.md`); widening the filter past the
# script's own reach would run it on changes it cannot see.
doc-issue-claims:
needs: changes
if: github.event_name != 'pull_request' || needs.changes.outputs.claims == 'true'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Documentation must not assert an issue state the tracker disagrees with
env:
GH_TOKEN: ${{ github.token }}
run: ./scripts/check-doc-issue-claims.sh
# The mirror image of `doc-issue-claims`: that one checks an annotated *claim* in `.md` files
# against reality, this one checks that rustdoc cites no closed issue at all -- `rustdoc` is
# published, third-party documentation (docs.rs), where a closed-issue citation is a vestige, not
# a claim; `.md` docs like ARCHITECTURE.md/SOTA.md are durable-reference records where citing a
# closed issue is the point. Same reason for widening the filter no further than the
# script's own reach: `check-closed-issue-rustdoc-refs.sh` reads `.rs` files via `git ls-files`.
closed-issue-rustdoc-refs:
needs: changes
if: github.event_name != 'pull_request' || needs.changes.outputs.rustdoc == 'true'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: rustdoc must not cite a closed issue
env:
GH_TOKEN: ${{ github.token }}
run: ./scripts/check-closed-issue-rustdoc-refs.sh
# Needs no history, hence the default shallow checkout.
open-issue-labels:
needs: changes
if: github.event_name != 'pull_request' || needs.changes.outputs.triage == 'true'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Open issues must satisfy .github/labels.tsv's invariants
env:
GH_TOKEN: ${{ github.token }}
# Unset for now: the backlog predates the taxonomy, so a deadline would fail the first
# run for reasons nobody chose. Set it once the backlog is labelled.
TRIAGE_SLA_DAYS: ''
run: ./scripts/check-issue-triage.sh
# Needs no history, hence the default shallow checkout.
decision-issues-recorded:
needs: changes
if: github.event_name != 'pull_request' || needs.changes.outputs.decisions == 'true'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Closed C-decision issues must be cited in ARCHITECTURE.md or AGENTS.md
env:
GH_TOKEN: ${{ github.token }}
run: ./scripts/check-decision-issues-recorded.sh