@@ -86,6 +86,143 @@ Do this in the same PR that closes the issue. A full sweep of the directory
8686should happen at the start of each sprint. Full convention and entry format
8787are in ` CONTRIBUTING.md ` under "Known Issues Sweep".
8888
89+ ## Post-push CI watcher (MANDATORY — even for one-line fix commits)
90+
91+ After ** every** ` git push ` that publishes new commits to a PR branch on
92+ this repo (including follow-up CodeRabbit-nitpick fixes), launch a
93+ background watcher per workflow run ** before** ending the turn. This is
94+ the project-level reinforcement of the global rule in
95+ ` ~/.claude/git-workflow.md ` §Post-push CI watcher — CUDly's pre-commit
96+ job alone takes 9–15 min and is silently broken by routine changes
97+ (missing CI tools, pre-existing markdownlint debt, git-secrets
98+ allowlist drift), so leaving a push unwatched routinely lets CI
99+ failures sit overnight.
100+
101+ Mechanics:
102+
103+ 1 . After ` git push ` , list the runs the push triggered:
104+
105+ ``` bash
106+ gh run list --repo LeanerCloud/CUDly --commit " $( git rev-parse HEAD) " \
107+ --limit 10 --json databaseId,workflowName,status
108+ ```
109+
110+ 2 . For each run still in ` queued ` /` in_progress ` , launch one background
111+ watcher script via ` Bash ` with ` run_in_background: true ` (do NOT use
112+ foreground polling — the main session must stay unblocked). The
113+ minimum viable watcher polls ` gh run view <ID> --json status,conclusion `
114+ every 30s and on completion either reports success or dumps the failed
115+ step digest. A reusable template lives at
116+ ` .claude/scripts/watch-ci-run.sh ` if present, or write a one-shot to
117+ ` /tmp/claude/watch-<sha>-<workflow>.sh ` .
118+
119+ 3 . If a watcher reports failure, the same session investigates and
120+ pushes a fix on the same branch (which fires a fresh watcher round).
121+ Decisions that need a human go to PR comments; everything else is
122+ autonomous per the global rule.
123+
124+ Forgetting this rule has been a recurring failure mode in this
125+ project. Before declaring a "pushed and done" turn complete, confirm
126+ at least one ` ci-watch-* ` background task is armed.
127+
128+ ## CodeRabbit loop — iterate to silence (MANDATORY)
129+
130+ CodeRabbit reviews this repo on every push to a PR branch. The full
131+ rules live in ` ~/.claude/git-workflow.md ` §"Post-PR review loop"
132+ (§§3, 3a) — read them. The minimum-viable loop for this project:
133+
134+ 1 . After every push, ping ` @coderabbitai review ` on the PR (CR doesn't
135+ always re-review automatically; the explicit ping makes it
136+ deterministic).
137+ 2 . Wait for the review (60–120s polling, soft-handle 429s).
138+ 3 . Triage every Actionable / Outside-diff / Nitpick finding into:
139+ actionable-fix-now, dismiss-with-justification-on-thread, or
140+ genuine-nitpick-batch-into-one-fix-commit.
141+ 4 . Push the fix(es), comment on the PR summarising what was addressed
142+ vs. dismissed (and why), end the comment with a fresh
143+ ` @coderabbitai review ` ping.
144+ 5 . ** Repeat until CR's most recent review has zero Actionable items
145+ AND every Nitpick is either fixed or has a justification reply.**
146+ "I fixed pass 1" is not loop-exit. CUDly PRs commonly run 3–6 CR
147+ passes before settling.
148+ 6 . If a fix push triggers conflicts (` mergeStateStatus: DIRTY ` ), resolve
149+ them per ` ~/.claude/git-workflow.md ` §3a — `git rebase
150+ origin/<base >` , atomic conflict resolution, ` git push
151+ --force-with-lease`, post a rebase note on the PR, then continue
152+ the CR loop.
153+
154+ Forgetting this rule leaves CR threads silently unresolved and pushes
155+ the triage burden onto the human reviewer.
156+
157+ ** When delegating PR work to a subagent** : the prompt MUST include the
158+ full CR loop, not stop at the first ` @coderabbitai review ` ping. A fork
159+ that pushes the PR, pings CR, then exits leaves the CR threads
160+ unresolved — same failure mode as forgetting the post-push CI watcher.
161+ The subagent's exit criteria must be: "CR's most recent review has zero
162+ Actionable items AND every Nitpick is either fixed or has a
163+ justification reply on the thread", not "PR opened and CR pinged". When
164+ in doubt, copy the iteration loop above (steps 2–6) into the fork
165+ prompt verbatim.
166+
167+ ## PR labeling — mirror closing-issue labels (MANDATORY)
168+
169+ Every PR opened in this repo must carry the ** same** triage labels as
170+ the issue it closes — ` priority/* ` , ` severity/* ` , ` urgency/* ` ,
171+ ` impact/* ` , ` effort/* ` , ` type/* ` , plus ` triaged ` if the issue carries
172+ it. Skipping this leaves PRs invisible to the same priority queries
173+ that surface the issues, so an unlabeled PR is effectively
174+ unreviewable in priority order.
175+
176+ Mechanics — fold into the ** same ` gh pr create ` round** , before pinging
177+ CodeRabbit:
178+
179+ ``` bash
180+ # Right after `gh pr create ...` returns the PR URL:
181+ # Derive PR_NUM from the current branch context (avoids brittle hand-copying).
182+ PR_NUM=$( gh pr view " $( git rev-parse --abbrev-ref HEAD) " --repo LeanerCloud/CUDly --json number --jq ' .number' )
183+ ISSUE_NUM=< the issue this PR closes>
184+
185+ LABELS=$( gh issue view " $ISSUE_NUM " --repo LeanerCloud/CUDly --json labels \
186+ --jq ' [.labels[].name | select(test("^(priority|severity|urgency|impact|effort|type)/")) ]
187+ + (if [.labels[].name] | any(. == "triaged") then ["triaged"] else [] end)
188+ | join(",")' )
189+
190+ # Guard against empty $LABELS — gh pr edit --add-label "" fails, which would
191+ # silently break this MANDATORY flow. If the closing issue has no triage
192+ # labels in the selected classes, surface the gap deterministically instead.
193+ if [ -n " $LABELS " ]; then
194+ gh pr edit " $PR_NUM " --repo LeanerCloud/CUDly --add-label " $LABELS "
195+ else
196+ echo " WARN: issue #$ISSUE_NUM has no priority/severity/urgency/impact/effort/type labels"
197+ echo " Triage the issue first, then re-run the label-mirror step."
198+ echo " Surface this gap in the PR body or as a comment on issue #$ISSUE_NUM ."
199+ fi
200+
201+ # Verify
202+ gh pr view " $PR_NUM " --repo LeanerCloud/CUDly --json labels \
203+ --jq ' [.labels[].name] | sort | join(",")'
204+ ```
205+
206+ If the closing issue lacks the ` triaged ` label, do NOT apply
207+ ` triaged ` to the PR — that would lie. Surface the gap in the PR body
208+ (or as a comment on the issue) so the human can triage.
209+
210+ If a label doesn't yet exist in the repo (rare — the label set is
211+ populated from the existing issue queue), ` gh label create ` it with
212+ the same color/description as a sibling label BEFORE applying.
213+
214+ For PRs that close more than one issue (e.g., a PR that closes
215+ ` #A ` and ` #B ` ): take the ** highest** ` priority/* ` and ` severity/* `
216+ across the issues; ` union ` the rest (` type/* ` , ` effort/* ` , ` impact/* ` ,
217+ etc.). The PR represents the work for both, so it should be
218+ discoverable under either filter.
219+
220+ Forgetting this rule has the same shape as forgetting the post-push
221+ CI watcher: it silently breaks priority-ordered review and triage.
222+ Before declaring a "PR opened and done" turn complete, confirm the
223+ label set on the PR matches the closing issue's set (or the merged
224+ set for multi-close PRs).
225+
89226## Security Rules
90227
91228- NEVER hardcode API keys, secrets, or credentials in source files
0 commit comments