{"id":"code-dev-js-review-four-line-comments","audience":"developers","category":"coding","track":"coding","technique":"format","title":"Review an Express handler as 4 labeled line comments","free":false,"task":"A teammate opened a pull request with the handler below. Your team's review format is exactly 4 numbered comments, each written as 'L<line> [blocker]: ...' or 'L<line> [nit]: ...', under 25 words each, with all blockers listed first. Security problems and wrong results are blockers; everything else is a nit. No code blocks, no praise, no summary.","materialLabel":"The new file in the pull request, with line numbers (attached to your prompt automatically)","material":" 1 | // routes/members.js  (Node 20, Express 4, pg)\n 2 | const express = require(\"express\");\n 3 | const db = require(\"../db\");\n 4 | const router = express.Router();\n 5 |\n 6 | const PAGE_SIZE = 20;\n 7 |\n 8 | router.get(\"/members\", async (req, res) => {\n 9 |   console.log(\"members request\", req.headers);\n10 |   const page = parseInt(req.query.page || \"1\", 10);   // pages start at 1\n11 |   const name = req.query.name || \"\";\n12 |   const started = Date.now();\n13 |\n14 |   const sql = \"SELECT id, name, email FROM members WHERE name ILIKE '%\" + name + \"%'\"\n15 |     + \" ORDER BY name\"\n16 |     + \" LIMIT \" + PAGE_SIZE\n17 |     + \" OFFSET \" + page * PAGE_SIZE;\n18 |\n19 |   try {\n20 |     const result = await db.query(sql);\n21 |     res.json({ page, members: result.rows });\n22 |   } catch (err) {\n23 |     res.status(500).json({ error: err.message });\n24 |   }\n25 | });\n26 |\n27 | module.exports = router;\n\nPR description (from Jonah): \"Adds member search + paging for the new\ndirectory page. Tested locally with page=1, looks good!\"\n\nNotes: req.headers includes the Authorization header with the user's\nsession token. The started variable is never read.","rules":[{"type":"numberedItems","count":4},{"type":"codeBlocks","count":0},{"type":"maxProseWords","max":130}],"mistakes":[{"title":"Getting a wall of feedback","why":"Asked to review, the AI lists every possible improvement plus praise and a summary.","fix":"Say: \"Exactly 4 numbered comments, under 25 words each. No praise, no summary.\"","checks":["numberedItems","maxProseWords"]},{"title":"No line numbers or severity","why":"Without your format, comments aren't tied to lines and nothing says what blocks the merge.","fix":"Show the shape: \"Format each like: 1. L14 [blocker]: ...\" and \"blockers first\".","checks":["r2"]},{"title":"Missing the paging bug","why":"The AI focuses on style and can miss that page 1 skips the first 20 rows.","fix":"Add: \"Pages start at 1; check the OFFSET math.\"","checks":["r1"]},{"title":"Rewriting the file","why":"The AI often pastes a corrected version of the whole handler, which the PR author didn't ask for.","fix":"Add: \"No code blocks; describe the fix in words.\"","checks":["codeBlocks","r0"]}],"promptHints":[{"label":"Sets the number of comments","patterns":["\\b(4|four)\\b.{0,20}comment","exactly \\d"]},{"label":"Shows the comment shape","patterns":["L\\d+","line number","\\[blocker\\]","\\[nit\\]"]},{"label":"Defines blocker vs nit","patterns":["blocker","severity","security"]},{"label":"Caps each comment","patterns":["\\d+\\s*words","short"]},{"label":"Rules out rewrites and praise","patterns":["no code","no praise","no summary","don't rewrite"]}],"hint":"Reviews are only useful in the shape your team reads. Tell the AI how many comments, what each line looks like, what counts as a blocker and what to leave out.","rubricLabels":["Flags the SQL built by string concatenation with req.query.name on line 14 as a [blocker] (SQL injection, use a parameterized query)","Flags the OFFSET on line 17 as a [blocker] because pages start at 1, so page 1 skips the first 20 members (offset should be (page - 1) * PAGE_SIZE)","Every comment starts with L and a line number followed by [blocker] or [nit], and no [nit] comes before a [blocker]"]}