feat: expose quality_score on news_editor_review_signal (#604)#605
Conversation
agent-news#864 added an optional quality_score override to PATCH /api/signals/:id/review, but the MCP wrapper never exposed it, so editors working through MCP could not correct the auto-scorer. Pass the field through unmodified. The API already validates type and range; the zod schema mirrors the 0-100 integer constraint so agents get it right first time. Omitting the field leaves the existing no-override path unchanged.
Asserts the three payload cases: 15 -> 15, 0 -> 0, omitted -> absent. The 0 case is the one worth locking in. `if (quality_score)` looks like it matches the truthiness guards on the three fields above it, but it drops a score of 0 — the #810 fabricated-sources case — and turns the override into a silent no-op. Verified the test fails under that refactor while the other two cases keep passing. Points the guard's comment at the test.
arc0btc
left a comment
There was a problem hiding this comment.
Closes the #604 gap cleanly — agent-news#864 added quality_score override to the PATCH route, but the MCP wrapper never exposed it, so the lever was inert for editors going through MCP.
What works well:
quality_score !== undefinedinstead of a truthiness check is the right call, and you caught the actual failure mode instead of assuming it — the PR description shows the0-drops-silently trap reproduced and fixed, not just asserted.- Zod bounds (
.int().min(0).max(100)) mirror the API's own validation, so a bad value fails at the tool boundary instead of round-tripping to the server. - Test suite hits the case that matters:
quality_score: 0for the #810 fabricated-sources scenario is exactly the input a naive refactor would silently swallow. Good regression coverage against the exact bug this PR fixes. - Tool description addition (auto-scorer's per-signal blind spot) gives editors the why, not just the what — useful for anyone calling this tool without repo context.
- Omission-preserves-payload guarantee (byte-identical when
quality_scoreisn't passed) means zero blast radius for existing callers.
Code quality notes:
Nothing to flag — the explicit-undefined-check comment names the test that would catch a regression, which is the right amount of context for a subtle guard like this.
[question] The PR body mentions this is "the fourth instance of this drift" between agent-news route params and MCP wrapper schemas, and proposes a cross-repo CI contract check as out-of-scope follow-up. Worth filing that as a tracked issue now (even if unscheduled) so it doesn't require a fifth drift incident to resurface? Not blocking either way.
Approving — functionality, security (bounded input, no injection surface), performance (no hot-path impact), clean code, and fit all check out.
Fixes #604.
agent-news#864 added an optionalquality_scoreoverride toPATCH /api/signals/:id/review. Thenews_editor_review_signalwrapper was never updated, so the field was unreachable for editors working through MCP —agent-news#810read as fixed while the lever stayed inert.Change
quality_scoreto the wrapper's input schema (z.number().int().min(0).max(100)), mirroring the constraint the API enforces.The guard is
quality_score !== undefinedrather than a truthiness test, since0is a valid score and the neighbouringif (feedback)pattern would drop it.Omitting the field leaves the payload byte-identical to before, so callers that don't pass it are unaffected.
Tests
tests/tools/news-editor-review-signal.test.tsasserts the payload on the wire for three cases:quality_scoresentquality_score: 1515quality_score: 00(not dropped)The
0row is the one carrying weight.if (quality_score)reads as consistent with the three truthiness guards directly above it, so it's a plausible future cleanup — and it would silently drop a score of0, the #810 fabricated-sources case, turning an editor's most severe correction into a no-op.I checked the test fails for that reason rather than assuming it would. Applying the refactor:
0case fails (expected { …(3) } to have property "quality_score")15and omitted cases still pass — which is exactly why the trap is easy to walk intoRestored the guard, and the comment on it now names the test.
Full suite: 528 passing (525 + 3), build clean.
tools/liston the built server confirms the parameter astype: integer, minimum: 0, maximum: 100, and the payload matches whatsrc/routes/signal-review.tsdestructures and validates.Note on placement: the sibling convention
tests/scripts/test-news-file-signal.tsis a manual script — it needsTEST_WALLET_PASSWORDand a live endpoint, andvitest.config.tsonly collectstests/**/*.test.ts, so it never runs in CI. This went in as a collected test instead, since a script wouldn't fail on the refactor above.Not addressed
The issue also proposes a CI contract check diffing wrapper params against the
agent-newsroute handlers' accepted fields — worth doing given this is the fourth instance of this drift, but it spans both repos and is out of scope here.