ci: add Qwen3.6-Plus PR review (static + opencode)#445
Conversation
…lay) (#357) * feat(pagination): scaffold @platejs/pagination variant A (render-overlay) — refs #353 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * feat(template): add OpenNext deploy + pagination toolbar button placeholder Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(pagination): apply inspector + CR feedback — refs #357 - move base bundle (header, footer, page break) to BasePaginationPlugin.plugins (Slate base) - BasePaginationConfig key uses typeof KEYS.pagination - drop degenerate <_V> generic on BasePaginationOptions - add includeFootnoteSubPlugins option (default true) — opt-out for footnote coupling - usePretextMeasurer uses useState so future ready flip re-renders - drop @chenglou/pretext from dependencies until measurer lands Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(template): CR feedback — refs #365 - lint script: add explicit `eslint .` target - lint:fix: chain `eslint . --fix` after biome - pagination-toolbar-button: drop internal #357/#358 PR refs from user-facing toast Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * feat(pagination): implement variant A — paginate, measurer, overlay, footnotes — refs #353 #357 Replace TODO stubs with full variant A: - paginate(): bin-pack with manual page-break, oversized-block, header/footer/footnote-def exclusion - allocateFootnotes(): per-page allocation by reference walk - DOM-backed measurer with bounded LRU cache keyed by (nodeId, marksFingerprint, font, width) - usePageLayout, PageOverlay (afterEditable, pointer-events: none), PageFrame chrome - FootnotePortal hides in-flow definitions via injected CSS - Editor API: getPages, getPageOf, getFootnotes - Editor transforms: insertPageBreak, setHeader, setFooter - 9 unit tests passing Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * feat(template): wire real @platejs/pagination via vendored dist — refs #357 #365 Drop placeholder pagination kit. Vendor @platejs/pagination's built dist under templates/plate-playground-template/vendor/platejs-pagination so the template can consume the real plugin without npm publish: - pagination-kit: PaginationPlugin.configure({ A4, 96px margins, 48 header/footer, 96 footnote well }) - pagination-toolbar-button: clicks editor.tf.pagination.insertPageBreak() - vendor/.gitignore overrides repo **/dist so committed artifacts ship Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(pagination): visible page panel + resilient toolbar — refs #357 #365 PageOverlay: replace overlay-on-editor (z-index conflict, white-on-white) with a fixed top-right card showing "Pages: N" plus PageFrame thumbnails. Always visible regardless of editor theme. Toolbar button: try editor.tf.pagination.insertPageBreak() first; fall back to editor.tf.insertNodes({type:'pageBreak'}) so the action works even when the plugin's transforms aren't bound (e.g. during HMR or kit ordering). Drop the "plugin not loaded" toast. Refresh vendored dist. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(pagination): KEYS resolution + reactive overlay + toggle preview — refs #353 #357 #365 Two bugs uncovered via dogfooding the deploy: 1. Plugin silently dropped from editor: source referenced KEYS.pagination and KEYS.pageBreak; both undefined in published platejs@53.0.3 → key resolved to undefined → editor filtered the plugin out. Fixed by replacing with local PAGINATION_KEY / PAGE_BREAK_KEY / etc. constants in lib/internal/keys.ts. 2. Overlay never re-rendered on edits: useEditorRef + useMemo([editor.children]) misses Slate in-place mutations. Switched to useEditorValue + usePluginOption. Also: - previewVisible option + togglePreview() transform; toolbar button now toggles the side panel instead of inserting a break. - PageFrame now renders mini-content per block (h1-h6 / blockquote / code / paragraph) so the preview is content-aware, not just empty page chrome. - Refresh vendored dist + .gitignore dogfood-output. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * feat(pagination): page config + header/footer toggles + settings dropdown — refs #357 Adds the next layer per the CR plan + agreed roadmap: Plugin (lib): - PageSize: union of preset key | { width, height } literal — registry escape hatch - BasePaginationOptions: + headerVisible, footerVisible (defaults false) - BasePaginationTransforms: + setPageSize, setMargins, toggleHeader, toggleFooter - toggleHeader/toggleFooter inserts a top-level header/footer block at index 0 / N with placeholder text ("Header" / "Footer") and flips the visibility option; removeByType dedupes if normalization produced duplicates - resolvePageSize handles both preset and literal forms; resolvePageRect clamps contentHeight/contentWidth to >= 0 Overlay (react): - usePluginOption subscribes to pageSize, margins, headerVisible, footerVisible so the panel re-renders when any of them changes via toggle/setMargins/etc. Template: - pagination-toolbar-button: replaces the single click handler with a Radix DropdownMenu — sections for Display (preview/header/footer toggles), Page size (A4/Letter/Legal radio), Margins (narrow/default/wide presets) - vendor:pagination script — copies packages/pagination/dist into the template's vendored package; addresses CR's "Vendored dist refresh" follow-up Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * feat(pagination): apply CR/Gemini review — derived header/footer, normalizeNode, content cache, pt scaling — refs #357 Implements the agreed subset of the CR plan-conejo (comment 11) and the Gemini + CR review feedback: Architecture: - Move page-state.ts from react/internal/ to lib/internal/ so the base Slate plugin's API can read pages without depending on React. Keeps imports flowing lib → react, never the other way. Header/footer model: - Drop headerVisible / footerVisible options. Derive presence from the doc itself (editor.children.some(n => n.type === HEADER_KEY)). Removes the option-vs-Slate-history asymmetry CR risk-flagged: undo of a toggleHeader call now correctly restores the header without leaving a stale option flag. - Add api.pagination.hasHeader / hasFooter for consumers that don't want to walk children themselves. - Toolbar dropdown checkboxes derive state via useEditorValue + same scan. Invariants: - Add overrideEditor → normalizeNode that runs at root path: enforceHeaderFooterInvariants drops duplicate header/footer blocks and re-positions the survivor (header at [0], footer at last index). Defends against paste/undo producing duplicates. Measurement correctness: - MeasureCacheKey gains a contentHash field; usePretextMeasurer hashes type + plain text per node and feeds it in. Cache now invalidates on in-place edits (Gemini + CR concern). - collectPlainText stops inserting a space between adjacent leaves — bold-then-plain runs ("He" + "llo") were measured as "He llo", over- counting line breaks. Fixed. - scaleFont uses /(\d+)(px|pt)/ and re-emits the matched unit so pt-sized fonts scale correctly for headings. - resolvePageRect clamps contentWidth/Height to ≥ 0 (already in place, preserved when accepting the new PageSize union). UI: - PageOverlay's THUMB_SCALE is now computed via computeThumbScale(width) = min(0.18, 196/pageWidth) — scales custom landscape page sizes down to the panel width. - React keys for the page list use `page-${pageIndex}` (stable). Cleanup: - marks-fingerprint: rename `sorted` → `segments` (CR nitpick — name reflected traversal order, not sort). Tests: 11 pass (added contentHash + hashString cases). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * 📝 CodeRabbit Chat: Implement requested code changes * Update packages/pagination/src/static/page-break-element-static.tsx Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com> * refactor(pagination): split helpers into queries/transforms; KEYS via getType; plugin spec Apply footnote-plugin best practices to BasePaginationPlugin: - Extract queries (lib/queries) and transforms (lib/transforms) modules. - Move BasePaginationConfig/Api/Transforms types to lib/types. - Use editor.getType(KEYS.x) so consumer .configure({ node: { type } }) overrides flow through. - Fix enforceHeaderFooterInvariants stale-index bug (collect → sort desc → remove → re-scan → move). - Add base-pagination-plugins.spec covering plugin schema, API/transforms surface, toggle/set/insert behavior, and normalize invariants. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com>
* fix(markdown): respect resourceLink for bare autolinks (udecode#4972) * Version Packages (udecode#4975) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> * chore: update --------- Co-authored-by: Arnau Jiménez <arnau@ajb.cat> Co-authored-by: Ziad Beyens <ziad.beyens@gmail.com> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
* fix(markdown): respect resourceLink for bare autolinks (udecode#4972) * Version Packages (udecode#4975) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> * chore: update --------- Co-authored-by: Arnau Jiménez <arnau@ajb.cat> Co-authored-by: Ziad Beyens <ziad.beyens@gmail.com> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Supply-chain defense: packages must be 7+ days old before install. Adds [test] root="./packages" in monorepos. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Warning Review limit reached
More reviews will be available in 9 minutes and 34 seconds. Learn how PR review limits work. Your organization has run out of usage credits. Purchase more in the billing tab. ⌛ How to resolve this issue?After more reviews become available, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available. Please see our Fair Usage Limits Policy for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (2)
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
Code Review by Qodo
Context used✅ Compliance rules (platform):
300 rules 1. Static prompt in opencode
|
Reviewer's GuideAdds a new GitHub Actions workflow to run advisory-only static analysis (Python/TS/Rust) and an independent Qwen3.6 Plus LLM-based PR review via opencode/DashScope, plus the corresponding opencode provider configuration. Flow diagram for PR-triggered static and LLM review jobsflowchart LR
PR["PullRequest opened/sync/reopened/ready_for_review"]
STATIC["Job static\nruff / biome+tsc / cargo"]
OPC["Job opencode\nQwen3_6_Plus review"]
REPORT["Static analysis output\n(advisory-only)"]
COMMENT["PR review comment\n(grouped by severity)"]
PR --> STATIC
PR --> OPC
STATIC --> REPORT
OPC --> COMMENT
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
There was a problem hiding this comment.
Code Review
This pull request introduces a new configuration file opencode.json to set up the DashScope provider. A review comment correctly points out that the model identifier qwen3.6-plus is invalid and suggests updating it to qwen-plus to avoid API errors.
| "qwen3.6-plus": { | ||
| "name": "Qwen3.6 Plus" | ||
| } |
There was a problem hiding this comment.
The model identifier qwen3.6-plus is invalid. Alibaba Cloud DashScope / Bailian does not have a model named qwen3.6-plus. The correct identifier for the Qwen Plus model is qwen-plus. Please update it to avoid API errors during execution.
| "qwen3.6-plus": { | |
| "name": "Qwen3.6 Plus" | |
| } | |
| "qwen-plus": { | |
| "name": "Qwen Plus" | |
| } |
arthrod
left a comment
There was a problem hiding this comment.
Three issues found in the workflow, two blocking.
Blocking
actions/checkout@v6 doesn't exist — latest stable is v4. Both jobs will fail immediately on checkout. Change both occurrences to actions/checkout@v4.
bunx --bun typescript tsc --noEmit is wrong syntax. bunx resolves and runs the default binary of a package; the TypeScript package exposes tsc as that binary. Correct form: bunx tsc --noEmit. The current form passes tsc --noEmit as arguments to a non-existent typescript executable.
Should-fix
anomalyco/opencode/github@latest floats on a third-party action — supply chain risk. Pin to a specific release tag or commit SHA.
Generated by Claude Code
There was a problem hiding this comment.
Hey - I've left some high level feedback:
- The Rust static analysis step assumes
cargo/rustupare available on the runner, which isn’t guaranteed onubuntu-latest; consider adding an explicit Rust toolchain setup (e.g., actions-rs/toolchain) or guarding the Rust block with acommand -v cargo >/dev/nullcheck to avoid step failures when.rsfiles are present. - The
opencodejob relies onDASHSCOPE_API_KEYand a writableGITHUB_TOKEN, which won’t be available for PRs from forks; if you expect external contributions, you may want to gate this job to same-repo PRs (e.g., compare head repo togithub.repository) or otherwise handle the missing-secret case explicitly.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- The Rust static analysis step assumes `cargo`/`rustup` are available on the runner, which isn’t guaranteed on `ubuntu-latest`; consider adding an explicit Rust toolchain setup (e.g., actions-rs/toolchain) or guarding the Rust block with a `command -v cargo >/dev/null` check to avoid step failures when `.rs` files are present.
- The `opencode` job relies on `DASHSCOPE_API_KEY` and a writable `GITHUB_TOKEN`, which won’t be available for PRs from forks; if you expect external contributions, you may want to gate this job to same-repo PRs (e.g., compare head repo to `github.repository`) or otherwise handle the missing-secret case explicitly.Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
Qodo reviews are paused for this user.Troubleshooting steps vary by plan Learn more → On a Teams plan? Using GitHub Enterprise Server, GitLab Self-Managed, or Bitbucket Data Center? |
| - name: Run opencode | ||
| uses: anomalyco/opencode/github@latest | ||
| env: | ||
| DASHSCOPE_API_KEY: ${{ secrets.DASHSCOPE_API_KEY }} | ||
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} |
There was a problem hiding this comment.
1. Unpinned opencode action 🐞 Bug ⛨ Security
The workflow runs anomalyco/opencode/github@latest, so the code executed in CI can change without review and has access to DASHSCOPE_API_KEY plus PR write permissions. This creates a supply-chain risk where a compromised/changed upstream action could exfiltrate secrets and post arbitrary PR comments.
Agent Prompt
## Issue description
`anomalyco/opencode/github@latest` is an unpinned third-party GitHub Action. Because this job also receives `DASHSCOPE_API_KEY` and has `pull-requests: write`, any upstream change/compromise can immediately impact all PR runs.
## Issue Context
This workflow is intended to run automatically on PRs and post a review comment. That requires secrets and write permissions, which increases the blast radius of unpinned actions.
## Fix Focus Areas
- .github/workflows/qwen-review.yml[101-109]
## Suggested change
- Replace `anomalyco/opencode/github@latest` with a pinned immutable ref (prefer a full commit SHA; alternatively a specific, reviewed release tag).
- (Optional hardening) Move permissions to job-level and grant the minimum needed for `opencode` only (e.g., keep `pull-requests: write` there; keep `contents: read`; avoid granting other permissions to `static`).
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
|
Code review by qodo was updated up to the latest commit a47eb63 |
| prompt: | | ||
| Review this pull request as a senior engineer. Be concise and specific. | ||
| - Flag correctness bugs, security issues, and data-loss risks first. | ||
| - Note Python / TypeScript / Rust issues a linter would miss (logic, API misuse, races). | ||
| - Call out missing tests for changed behavior. | ||
| - Skip nitpicks already covered by formatters/linters. | ||
| Post a single review comment grouped by severity (Blocking / Should-fix / Nit). |
There was a problem hiding this comment.
1. Static prompt in opencode 📘 Rule violation ⌂ Architecture
The new GitHub Actions workflow configures an opencode LLM prompt as a hardcoded static string with no injected runtime state. This violates the requirement that system prompts be dynamically constructed with runtime application state, which can reduce review quality and cause context-missing outputs.
Agent Prompt
## Issue description
The `opencode` prompt is currently a static string and does not inject any runtime context (e.g., PR title/body, changed files, or other run-specific state).
## Issue Context
Compliance requires that system prompts include dynamically injected runtime application state rather than being purely static.
## Fix Focus Areas
- .github/workflows/qwen-review.yml[110-116]
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
| permissions: | ||
| contents: read | ||
| pull-requests: write | ||
| issues: read |
There was a problem hiding this comment.
2. Excess workflow permissions 🐞 Bug ⛨ Security
The workflow grants pull-requests: write (and issues: read) at the workflow level, so the static job inherits write-capable credentials it never uses, increasing impact if any step/tool is compromised. Only the opencode job appears to require PR write access for posting a review comment.
Agent Prompt
## Issue description
The workflow-level `permissions:` grants `pull-requests: write` and `issues: read` to *all* jobs. The `static` job does not need these permissions, so it should run with minimal read-only permissions and only the `opencode` job should be granted write access.
## Issue Context
- `static` runs checkout + local linters only.
- `opencode` posts a PR review comment (needs `pull-requests: write`).
## Fix Focus Areas
- .github/workflows/qwen-review.yml[13-16]
- .github/workflows/qwen-review.yml[28-86]
- .github/workflows/qwen-review.yml[91-109]
## Suggested change
- Reduce top-level permissions to the minimum (e.g. `contents: read`).
- Add job-level permissions:
- `static`: `contents: read`
- `opencode`: `contents: read`, `pull-requests: write` (and `issues: read` only if truly required by the action).
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
|
Code review by qodo was updated up to the latest commit a47eb63 |
Qodo reviews are paused for this user.Troubleshooting steps vary by plan Learn more → On a Teams plan? Using GitHub Enterprise Server, GitLab Self-Managed, or Bitbucket Data Center? |
Review: PR #445 — ci: add Qwen3.6-Plus PR review🔴 Blocking1. 2.
3. Model identifier 4. Rust toolchain not installed — 🟡 Should-fix5. Unpinned third-party action 6. Permissions are overly broad at the workflow level.
7. No fork/secret guard on the if: >-
${{
!github.event.pull_request.draft &&
github.event.pull_request.head.repo.full_name == github.repository &&
secrets.DASHSCOPE_API_KEY != ''
}}( 8. No 9. Prompt is fully static — no runtime context injection. 10. ⚪ Nit11. |
User description
Self-hosted PR reviewer (Qwen3.6 Plus via Bailian). static job is advisory; opencode job runs independently. 🤖 Generated with Claude Code
PR Type
Enhancement
Description
Add self-hosted PR review workflow using Qwen3.6 Plus LLM
Implement independent static analysis job (Python/TS/Rust)
Configure opencode integration with Alibaba Bailian API
Enable concurrent PR reviews with automatic cancellation
Diagram Walkthrough
File Walkthrough
qwen-review.yml
GitHub Actions workflow for Qwen3.6 PR review.github/workflows/qwen-review.yml
(cargo) checks with advisory-only reporting
structured prompt
PR
opencode.json
OpenCode provider configuration for DashScopeopencode.json
endpoint
Summary by Sourcery
Add a self-hosted pull request review workflow that runs advisory static analysis and an independent Qwen3.6 Plus LLM-based review via Alibaba Bailian through opencode.
Enhancements:
CI: