Skip to content

Comments

feat: merge grammar and slop checks into unified blog-check workflow#4084

Merged
goranmoomin merged 3 commits intomainfrom
devin/1771475993-blog-slop-check
Feb 19, 2026
Merged

feat: merge grammar and slop checks into unified blog-check workflow#4084
goranmoomin merged 3 commits intomainfrom
devin/1771475993-blog-slop-check

Conversation

@devin-ai-integration
Copy link
Contributor

@devin-ai-integration devin-ai-integration bot commented Feb 19, 2026

feat: merge grammar and slop checks into unified blog-check workflow

Summary

Consolidates the blog post CI checks into a single workflow by renaming blog-grammar-check.ymlblog-check.yml and adding a new AI slop detection step alongside the existing grammar check. Both checks run sequentially and their results are combined into a single PR comment.

New file: .github/scripts/slop-check.mjs — an AI-powered proofreading pass that flags writing patterns technical readers would recognize as LLM-generated content. The system prompt aggressively assumes all text is LLM-generated by default and checks against a comprehensive ruleset compiled from:

Workflow changes:

  • Renamed job from grammar-checkblog-check
  • Added "Run slop check" step after grammar check
  • PR comment now contains both grammar and slop results separated by ---
  • Bot comment marker changed from <!-- grammar-check-bot --> to <!-- blog-check-bot -->
  • Trigger unchanged: PRs to main from blog/* branches touching apps/web/content/articles/**

Review & Testing Checklist for Human

  • slop-check.mjs is entirely untested — the generateObject call, Zod schema validation, and markdown output have never been executed. Run locally: ANTHROPIC_API_KEY=... CHANGED_FILES="apps/web/content/articles/some-post.mdx" node .github/scripts/slop-check.mjs against a real blog post to verify end-to-end
  • Bot comment marker changed — old <!-- grammar-check-bot --> comments on existing PRs will be orphaned (new comments will use <!-- blog-check-bot -->). If there are open blog PRs with existing grammar-check comments, they'll get a duplicate comment instead of an update
  • Model ID claude-haiku-4-5 — verify this is the correct Anthropic SDK model identifier. The OpenRouter equivalent is anthropic/claude-haiku-4.5 but the @ai-sdk/anthropic provider may use a different format
  • System prompt is ~250 lines — review for quality and check token cost per invocation on Haiku 4.5. The prompt includes the full stop-slop banned phrase list verbatim
  • Utility functions duplicated from grammar-check.mjs (extractContent, extractFrontmatter, getFrontmatterLineCount, addLineNumbers) — decide whether to extract into a shared module or accept the duplication

Test plan: Open a test PR from a blog/* branch that modifies a file in apps/web/content/articles/, confirm both grammar and slop check results appear in a single PR comment.

Notes

Co-Authored-By: Sungbin Jo <goranmoomin@daum.net>
@devin-ai-integration
Copy link
Contributor Author

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR that start with 'DevinAI' or '@devin'.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment and CI monitoring

@netlify
Copy link

netlify bot commented Feb 19, 2026

Deploy Preview for hyprnote ready!

Name Link
🔨 Latest commit fc8fdd0
🔍 Latest deploy log https://app.netlify.com/projects/hyprnote/deploys/6996b07b5e787f0008a32133
😎 Deploy Preview https://deploy-preview-4084--hyprnote.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@netlify
Copy link

netlify bot commented Feb 19, 2026

Deploy Preview for hyprnote-storybook canceled.

Name Link
🔨 Latest commit fc8fdd0
🔍 Latest deploy log https://app.netlify.com/projects/hyprnote-storybook/deploys/6996b07b4b4e1d0008b0fa75

Copy link
Contributor Author

@devin-ai-integration devin-ai-integration bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 3 potential issues.

View 3 additional findings in Devin Review.

Open in Devin Review

Comment on lines +385 to +388
if (result.error) {
markdown += `Error: ${result.error}\n\n`;
} else {
const { feedback, totalScore } = result;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Crash when error.message is falsy: null feedback accessed in else branch

When checkSlop throws an error with a falsy .message (e.g., new Error("")), the error result at lines 369-374 sets error: error.message (empty string) and feedback: null. In the rendering loop at line 385, if (result.error) evaluates to false for an empty string, so the code falls into the else branch at line 387. There, const { feedback, totalScore } = result; destructures feedback as null and totalScore as undefined. The code then crashes at feedback.score.directness (line 393) with a TypeError: Cannot read properties of null.

Root Cause

The error result object (lines 369-374) stores error: error.message which can be an empty string (falsy). The guard at line 385 uses if (result.error) which is a truthiness check, not an explicit check for the presence of the error property. When error.message is "", the truthiness check fails and the code proceeds to access feedback.score on a null value.

Additionally, the error result object is missing frontmatterLines and totalScore properties that the else branch expects, so even if totalScore were accessed, it would be undefined.

Impact: The script crashes with an unhandled TypeError, producing no useful output for any of the files. The outer .catch() handler would write a generic failure message, losing all results from files that were successfully processed before the crash.

Suggested change
if (result.error) {
markdown += `Error: ${result.error}\n\n`;
} else {
const { feedback, totalScore } = result;
if (result.feedback === null) {
markdown += `Error: ${result.error || 'Unknown error'}\n\n`;
} else {
const { feedback, totalScore } = result;
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: "20"
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚩 Node.js version mismatch with project engine requirement

The workflow specifies node-version: "20" at .github/workflows/blog-slop-check.yml:27, but the root package.json declares "engines": { "node": ">=22" }. While npm install only warns (not errors) about engine mismatches by default, this is an inconsistency. The script itself likely works on Node 20 since it uses standard ES module features, but if the project ever enables engine-strict or if a dependency requires Node 22+, this workflow would break silently.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.


- name: Install dependencies
if: steps.changed-files.outputs.has_files == 'true'
run: npm install ai @ai-sdk/anthropic zod
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚩 npm install in pnpm monorepo root may cause issues

The workflow runs npm install ai @ai-sdk/anthropic zod (line 42) in the repo root, which uses pnpm as its package manager ("packageManager": "pnpm@10.30.0" in root package.json). Running npm install in a pnpm workspace can create a node_modules directory alongside the existing pnpm structure, and may produce warnings or unexpected behavior. Since the script is run standalone with node .github/scripts/slop-check.mjs and doesn't depend on the monorepo's packages, it should resolve the three installed packages fine. But using npx or installing in a temp directory would be cleaner.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

…ml workflow

Co-Authored-By: Sungbin Jo <goranmoomin@daum.net>
@devin-ai-integration devin-ai-integration bot changed the title feat: add AI slop check workflow for blog posts feat: merge grammar and slop checks into unified blog-check workflow Feb 19, 2026
…rd lists

Co-Authored-By: Sungbin Jo <goranmoomin@daum.net>
@goranmoomin goranmoomin merged commit f46da72 into main Feb 19, 2026
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant