github: add LLM review workflow and project rules
authorHauke Mehrtens <redacted>
Wed, 27 May 2026 23:45:44 +0000 (01:45 +0200)
committerHauke Mehrtens <redacted>
Thu, 28 May 2026 18:23:37 +0000 (20:23 +0200)
Add a nightly LLM-driven PR review for the LuCI repo, calling the
reusable workflow in actions-shared-workflows. The extra_repos list
pre-clones LuCI's typical backends (rpcd, netifd, firewall4, ucode,
uhttpd, packages, openwrt) so the routine can verify cross-repo
references without re-cloning per PR.

Also add .github/llm-review-rules.md with two project-specific rules
the system prompt does not cover: redirecting PRs that touch
out-of-tree luci-app-* packages, and checking that new UCI options
have a backend consumer.

Co-Authored-By: Claude Opus 4.7 (1M context) <redacted>
Signed-off-by: Hauke Mehrtens <redacted>
.github/llm-review-rules.md [new file with mode: 0644]
.github/workflows/llm-review.yml [new file with mode: 0644]

diff --git a/.github/llm-review-rules.md b/.github/llm-review-rules.md
new file mode 100644 (file)
index 0000000..a543b90
--- /dev/null
@@ -0,0 +1,41 @@
+# LLM review rules — openwrt/luci
+
+LuCI-specific patterns to flag. The review routine reads this at
+session start. General contribution rules (commit subject prefix,
+Signed-off-by, real-name author, line length) live in
+[`CONTRIBUTING.md`](../CONTRIBUTING.md) and are already enforced by
+the formality CI bot — don't duplicate those checks.
+
+## Out-of-tree luci apps
+
+A few `luci-app-*` packages are maintained in their own repositories,
+not in `openwrt/luci`. PRs that re-introduce or modify these in-tree
+should be redirected upstream rather than reviewed line by line
+(recurring example: PRs #8462 and #8625 against
+`luci-app-https-dns-proxy`):
+
+- `luci-app-https-dns-proxy` --> https://github.com/mossdef-org/luci-app-https-dns-proxy
+
+When a PR's diff matches one of these package paths, flag it and link
+the upstream repo.
+
+## Backend coupling across repos
+
+A new UCI option or service interaction in LuCI is only useful if a
+backend actually reads it. Recurring failure mode (PRs #8498, #8533,
+#8590): the LuCI frontend exposes an option whose name does not appear
+in any backend, so the setting silently does nothing.
+
+When a PR adds a UCI field or RPC call, check that a consumer exists:
+
+- `luci-mod-network`, `luci-proto-*` --> `netifd` (and its proto
+  handler scripts under `/lib/netifd/proto/`)
+- `luci-app-firewall` --> `firewall4` (`/usr/share/firewall4/`)
+- `luci-app-<pkg>` --> the `<pkg>` package itself, usually in
+  `feeds/packages` or `feeds/routing`
+
+If the option name does not appear in any consumer (grep the relevant
+`~/extra/<repo>-<ref>` tree), flag as "frontend-only with no backend
+consumer" and ask which daemon or script reads it. When the change
+depends on a not-yet-merged PR in another repo, that dependency should
+be called out in the PR description.
diff --git a/.github/workflows/llm-review.yml b/.github/workflows/llm-review.yml
new file mode 100644 (file)
index 0000000..3e60aff
--- /dev/null
@@ -0,0 +1,34 @@
+name: LLM Review
+
+on:
+  schedule:
+    - cron: '0 4,16 * * *'
+  workflow_dispatch:
+    inputs:
+      max_prs:
+        description: 'Max PRs to review in this nightly run'
+        required: false
+        type: number
+        default: 16
+
+permissions: {}
+
+concurrency:
+  group: ${{ github.workflow }}-nightly
+  cancel-in-progress: false
+
+jobs:
+  nightly:
+    if: (github.event_name == 'schedule' || github.event_name == 'workflow_dispatch') && github.repository_owner == 'openwrt'
+    permissions:
+      pull-requests: read
+    uses: openwrt/actions-shared-workflows/.github/workflows/reusable_llm-nightly-digest.yml@main
+    with:
+      routine_id: ${{ vars.LLM_ROUTINE_ID_NIGHTLY }}
+      # LuCI PRs frequently touch backends served via rpcd/ubus, ucode
+      # handlers, fw4/netifd config surfaces, and packages from feeds.
+      # The routine clones each entry only when the diff calls for it.
+      extra_repos: openwrt/openwrt:main,openwrt/rpcd:master,openwrt/netifd:master,openwrt/firewall4:master,openwrt/uhttpd:master,jow-/ucode:master,openwrt/packages:master
+      max_prs: ${{ fromJSON(inputs.max_prs || '16') }}
+    secrets:
+      llm_routine_token: ${{ secrets.LLM_ROUTINE_TOKEN_NIGHTLY }}
git clone https://git.99rst.org/PROJECT