js-rest-route-silent-noop-param
Done. I diagnosed the bug, built a runnable reproduction, applied the fix, and verified it.
~/js-rest-route-silent-noop-param/SOLUTION.md — the self-contained markdown write-up with title, root-cause analysis, exact fix, and verification.
PUT /api/keys/[id] destructured only isActive from the body, so name, description, expiresAt, and scopes were dropped before reaching the repo — which already supported them. The route returned 200 with the unchanged record. No validation meant blank values and {} were also silent no-ops.
Two related defects in the same tick:
- Log flooding: repeated identical warn messages in a poll loop logged every iteration.
- Dead branch: if (key.expiresAt || key.isActive) was placed before else if (key.isActive), making the specific branch unreachable.
lib/keys/validate.ts — strict validator: rejects non-objects, unknown fields, blank/whitespace name, wrong types, invalid expiresAt, and empty update sets.app/api/keys/[id]/route.ts — handlePut(req, ctx, repo) validates once, passes the full patch to the repo, returns 400 before touching the repo on invalid input, 404 when not found.lib/log/throttle.ts — createWarnThrottle logs the first occurrence + every Nth, resetting on message change.lib/keys/poller.ts — reordered so the specific isActive branch precedes the broader condition.node --test → # tests 14 # pass 14 # fail 0
This includes exactly 9 mocked route tests (covering the ignored name, multi-field pass-through, isActive, blank/whitespace/invalid inputs, empty body, and 404) plus throttle and branch-ordering tests. I also confirmed the original bug reproduces: the buggy/route.before.ts handler returns 200 while name stays "production".
# Evidence - Problem class: js-rest-route-silent-noop-param - Model: openrouter/deepseek/deepseek-v4.1-flash - Solved: 2026-09-11T00:13:09.617Z - Verification: solution produced by pi in sandbox; see signatures.json
{"description": "Next.js route handler ignored a documented input field (PUT /api/keys/[id] read only isActive) and returned 200 with no change. Fix: honor the field (pass through to the repo layer which already supports it), 400 on blank/invalid values and on bodies with no updatable field. Verified with 9 mocked route tests. Related class in the same tick: throttle repeated identical warn logs in a polling loop (first + every Nth) and un-deaden a branch ordered after a broader condition.", "environment": "", "language": "", "model": "openrouter/deepseek/deepseek-v4.1-flash", "problem_class": "js-rest-route-silent-noop-param", "provider": "openrouter", "solved_at": "2026-09-11T00:13:09.617Z", "version": ""}Done. I diagnosed the bug, built a runnable reproduction, applied the fix, and verified it.
~/js-rest-route-silent-noop-param/SOLUTION.md — the self-contained markdown write-up with title, root-cause analysis, exact fix, and verification.
PUT /api/keys/[id] destructured only isActive from the body, so name, description, expiresAt, and scopes were dropped before reaching the repo — which already supported them. The route returned 200 with the unchanged record. No validation meant blank values and {} were also silent no-ops.
Two related defects in the same tick:
- Log flooding: repeated identical warn messages in a poll loop logged every iteration.
- Dead branch: if (key.expiresAt || key.isActive) was placed before else if (key.isActive), making the specific branch unreachable.
lib/keys/validate.ts — strict validator: rejects non-objects, unknown fields, blank/whitespace name, wrong types, invalid expiresAt, and empty update sets.app/api/keys/[id]/route.ts — handlePut(req, ctx, repo) validates once, passes the full patch to the repo, returns 400 before touching the repo on invalid input, 404 when not found.lib/log/throttle.ts — createWarnThrottle logs the first occurrence + every Nth, resetting on message change.lib/keys/poller.ts — reordered so the specific isActive branch precedes the broader condition.node --test → # tests 14 # pass 14 # fail 0
This includes exactly 9 mocked route tests (covering the ignored name, multi-field pass-through, isActive, blank/whitespace/invalid inputs, empty body, and 404) plus throttle and branch-ordering tests. I also confirmed the original bug reproduces: the buggy/route.before.ts handler returns 200 while name stays "production".
# Evidence - Problem class: js-rest-route-silent-noop-param - Model: openrouter/deepseek/deepseek-v4.1-flash - Solved: 2026-09-11T00:13:09.617Z - Verification: solution produced by pi in sandbox; see signatures.json
{"description": "Next.js route handler ignored a documented input field (PUT /api/keys/[id] read only isActive) and returned 200 with no change. Fix: honor the field (pass through to the repo layer which already supports it), 400 on blank/invalid values and on bodies with no updatable field. Verified with 9 mocked route tests. Related class in the same tick: throttle repeated identical warn logs in a polling loop (first + every Nth) and un-deaden a branch ordered after a broader condition.", "environment": "", "language": "", "model": "openrouter/deepseek/deepseek-v4.1-flash", "problem_class": "js-rest-route-silent-noop-param", "provider": "openrouter", "solved_at": "2026-09-11T00:13:09.617Z", "version": ""}