-
Notifications
You must be signed in to change notification settings - Fork 27
165 lines (150 loc) · 9.78 KB
/
Copy pathcheck_doc_quality.yml
File metadata and controls
165 lines (150 loc) · 9.78 KB
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
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
name: Check doc quality
on:
workflow_dispatch:
pull_request:
types:
- opened
- reopened
- synchronize
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.ref }}
cancel-in-progress: true
jobs:
check-doc-quality:
name: Check doc quality
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Wait using dead-reckoning for builds to finish, before running, to save AI cost, if someone pushes many commits in a row
run: sleep 1800
- name: Collect changed docs
id: changed
env:
BASE_REF: ${{ github.base_ref }}
run: |
MERGE_BASE=$(git merge-base "origin/$BASE_REF" HEAD)
# List of *.md files under docs/ that were added/modified/renamed (not deleted) in this PR.
# Vendored third-party docs under external/ are out of scope (pathspec is anchored at docs/).
# We check the ENTIRE current contents of each file, not just the diff, so we only need the
# file list here.
git diff --name-only --diff-filter=d "$MERGE_BASE...HEAD" -- 'docs/' \
| grep -E '\.md$' > /tmp/changed_docs.txt || true
if [ ! -s /tmp/changed_docs.txt ]; then
echo "skip=true" >> "$GITHUB_OUTPUT"
echo "No documentation (.md) files changed."
else
echo "skip=false" >> "$GITHUB_OUTPUT"
echo "Changed docs:"
cat /tmp/changed_docs.txt
fi
- name: Install Cursor CLI
if: steps.changed.outputs.skip != 'true'
run: |
curl https://cursor.com/install -fsS | bash
echo "$HOME/.cursor/bin" >> $GITHUB_PATH
- name: Check doc quality with Cursor agent
if: steps.changed.outputs.skip != 'true'
env:
CURSOR_API_KEY: ${{ secrets.CURSOR_KEY_HUGH }}
run: |
RESULT=$(agent -p "$(cat <<'PROMPT'
You are reviewing the documentation in this PR for end-user quality.
/tmp/changed_docs.txt contains a newline-separated list of Markdown (.md) doc files (paths
relative to the repo root) that were added or modified in this PR. For EACH file in that
list, read the FULL current contents of the file (not just the diff) and review it against
the three rules below.
Target audience: an *end user* of Quadrants. That is, someone who writes GPU programs in
Python using the Quadrants library (`@qd.kernel`, `@qd.func`, ndarrays, fields, etc.).
Assume the reader:
- is comfortable with Python and has general familiarity with everyday GPU programming
ideas (a GPU, threads, host vs device, global memory, launching work);
- is NOT a compiler engineer and does NOT know Quadrants' internal implementation — its IR,
codegen, RHI / backend C++ code, pass pipeline, SNode internals, build system, etc. —
unless the doc itself explains it.
Advanced / internal section (referenced by both rules below): a clearly delimited section
whose heading marks it as such — e.g. a heading containing "Advanced", "Under the hood",
"Internals", or "Implementation" — or a doc that is itself explicitly an advanced / internal
reference. Such a section is understood to be aimed at a more advanced / internal reader
rather than the typical end user.
RULE 1 — Undefined terms.
Scan each doc for terms a typical Quadrants user is unlikely to already know: Quadrants-
specific concepts and APIs, project-specific abbreviations, internal subsystem names, and
specialized GPU/compiler jargon that goes beyond the everyday GPU knowledge described above.
A term is considered DEFINED if, at its first occurrence in that file, it is explained
inline (a sentence or parenthetical that tells the reader what it means) OR linked to
another doc/section that defines it (a Markdown link). Plain Python / everyday GPU terms
that the target reader already knows do NOT need a definition.
The reader is also assumed to know Quadrants' basic/core public API — the surface
introduced in the getting-started guide and used in everyday kernel writing (e.g.
`@qd.kernel`, `@qd.func`, `qd.Template`, fields, ndarrays, scalar dtypes like `qd.i32`,
`qd.init`, `qd.sync`). These core, commonly-used APIs do NOT need a definition or link at
first use. Rule 1 targets terms BEYOND this core vocabulary: less-common or specialized
APIs, internal subsystem names, project-specific abbreviations, and specialized
GPU/compiler jargon.
Terms whose first occurrence is inside an advanced / internal section (defined above) do
NOT need to be defined: such sections are aimed at a more advanced / internal reader, so
internal jargon there is acceptable.
VIOLATION: a term the target reader probably does not know is used at its first occurrence
in the file (outside any advanced / internal section) without being defined there.
RULE 2 — End-user relevance.
A doc should only contain information that is useful to an end user. Internal /
implementation / contributor-only material (compiler internals, IR/codegen/backend
mechanics, "how it works inside", maintenance notes, etc.) is allowed ONLY if it is
confined to an advanced / internal section (defined above). Body text in such a section is
fine.
The following are NOT scope violations (they are useful to end users) even when they
appear outside an advanced / internal section:
- References to public, user-facing APIs. You do NOT need to independently work out
whether a symbol is public — rely on the author's signals: if the symbol is linked to
its documentation (a Markdown link) and/or explicitly presented as a public,
user-facing API, treat references to it, and descriptions of how user-facing features
build on or compose with it, as in scope rather than internal material. (An unlinked,
unexplained symbol that reads like an internal may still be an undefined term under
Rule 1.)
- Brief, optional, reader-directed suggestions that the reader could contribute upstream
or file an issue (e.g. "if you need X, consider opening a PR / contributing it / filing
an issue"). These are acceptable escape hatches for an open-source audience. This
carve-out covers the suggestion ITSELF ONLY; it does NOT extend to documenting how to
design, implement, or maintain quadrants internals (e.g. walking through how such a
contribution would work internally), which remains a violation.
- FIXME / TODO markers left inline in a doc (e.g. "(FIXME: add stream.md)"). These are
authoring notes; ignore them entirely — do not flag the marker or its contents.
VIOLATION: internal / non-end-user material (subject to the carve-outs above) appears
outside of an advanced / internal section.
RULE 3 — Reading order (no forward references).
Within a single doc, information should be ordered so a first-time reader can follow it
top-to-bottom in one pass, without jumping ahead. A FORWARD REFERENCE is when a passage
depends on a concept, parameter, behavior, code element, or result that is only introduced
LATER in the SAME file, such that the reader cannot understand the current passage without
first reading the later one.
The following are NOT order violations:
- A brief overview / roadmap near the top that previews upcoming sections ("this guide
covers A, then B") — signposting the structure, not a dependency: the reader does not
need to understand A or B yet to keep reading.
- Optional "for more detail, see <section> below" pointers, where the current passage is
fully understandable WITHOUT following them. The test is: MUST read ahead to understand
(violation) vs more depth merely available later (fine).
- Backward references (to something earlier in the same file) are always fine.
- References to OTHER docs/files; this rule is about ordering WITHIN a single file only.
- Conventional preamble ordering (e.g. Prerequisites -> Installation -> Usage).
VIOLATION: a passage cannot be understood by a first-time reader at the point they reach
it, because what it relies on is only introduced later in the same file.
Read each listed file in full before judging it. You may open any other file in the repo
(e.g. linked docs) to verify whether a term is defined elsewhere. Do NOT modify any files.
Be precise and conservative: only flag clear violations, not borderline cases. Judge each
file independently. Stop after finding 10 violations in total.
If there are NO violations, your final output must start with the word PASS.
If there ARE violations, your final output must start with the word FAIL, followed by a list
of violations (up to 10), one per line, in the format:
<filepath>: [term|scope|order]: <brief description>
where [term] is a Rule 1 violation, [scope] is a Rule 2 violation, and [order] is a Rule 3
violation (for [order], cite both line numbers — what is used at line N is only introduced
at line M).
PROMPT
)" --model claude-4.6-opus-high-thinking --mode ask --output-format text --trust)
echo "$RESULT"
if echo "$RESULT" | grep -qE "^FAIL([[:space:]]|$)"; then
exit 1
fi