refactor(ai-review): give both reviewer paths one shared options type instead of a positional tail - #10260
Merged
Merged
Conversation
… instead of a positional tail runWorkersOpinion took 12 positional parameters ending in two adjacent, same-typed, identically-defaulted booleans (bodyTruncated, prHasTestEvidence), and runProviderReview carried the identical trailing sequence -- its own comments said 'same contract as runWorkersOpinion' on both. Both then ran the same demotion pair in the same order (demoteEvidenceAbsenceBlockers then demoteTestEvidenceAbsenceBlockers). Two places that must agree with nothing enforcing it. Transposing the booleans at any call site compiled and type-checked cleanly; doing it in only one of the two paths split Workers AI and BYOK demotion behaviour apart with no signal at all. Six call sites passed them positionally, each threading an undefined placeholder past images? -- a parameter no caller has ever supplied since #4111. One shared ReviewerDemotionContext, referenced by both signatures, makes the compiler enforce what the two comments only asserted. That is why no NAMED_TWIN_PAIRS entry (scripts/check-engine-parity.ts) is added: a drift check would be redundant against a type the compiler already checks, and a redundant guard is one more thing to keep true. Pure de-positionalisation. Every default is preserved by destructuring at the top of each function, so no body reference changed and no behaviour moved. images? is kept rather than deleted -- removing a deferred-but-designed parameter is a separate call from this one. Two test call sites used 'diagnostics as never', which let an ARRAY through where the options object now goes; the caller's array then stayed empty. Ten call sites carried that cast. Two failed loudly and are fixed. A third (line 3784) had been asserting diagnostics.some(...) === false against an array that could never be populated -- vacuously true. It now passes a real array and the assertion is genuine; verified by asserting the array is non-empty before restoring. Closes #10253
Contributor
|
Important 🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨 ⏳ LoopOver is waiting…LoopOver has seen this pull request and is waiting on CI checks to finish before reviewing it. This comment will update once the review runs. 🟩 Safe / merged · 🟦 Advisory · 🟨 Held for review · 🟥 Blocked / closed · 🟨 Waiting |
Contributor
|
Superagent didn't find any vulnerabilities or security issues in this PR. |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #10260 +/- ##
==========================================
- Coverage 92.28% 91.41% -0.87%
==========================================
Files 939 939
Lines 114746 114744 -2
Branches 27714 27712 -2
==========================================
- Hits 105889 104893 -996
- Misses 7555 8744 +1189
+ Partials 1302 1107 -195
Flags with carried forward coverage won't be shown. Click here to find out more.
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
runWorkersOpiniontook 12 positional parameters, ending in two adjacent, same-typed, identically-defaulted booleans.runProviderReviewcarried the identical trailing sequence — its own comments said so:Both then ran the same demotion pair in the same order —
demoteEvidenceAbsenceBlockersthendemoteTestEvidenceAbsenceBlockers(1739/1741 and 2204/2209).Two places that must agree, with nothing enforcing it. Transposing the two booleans at any call site compiled cleanly, type-checked cleanly, and silently armed the wrong demotion. Doing it in only one of the two paths split Workers AI and BYOK behaviour apart with no signal at all — strictly worse than getting it wrong in both. Six call sites passed them positionally, each threading an
undefinedplaceholder pastimages?, a parameter no caller has supplied since #4111:Approach
One shared
ReviewerDemotionContext, referenced by both signatures, so the compiler enforces what the two comments only asserted.That is deliberately chosen over registering the pair in
NAMED_TWIN_PAIRS(scripts/check-engine-parity.ts), the other option raised on the issue. A drift check would be redundant against a type the compiler already checks, and a redundant guard is one more thing that has to stay true. If the two ever need to diverge, the type is the thing you have to edit — which is the conversation you want to be forced into.env…maxTokensstay positional; those are the genuine arguments. Everything fromdiagnosticsonward was the accidental part.Pure de-positionalisation. Every default is preserved by destructuring at the top of each function, so no body reference changed and no behaviour moved.
images?is kept, not deleted — removing a deferred-but-designed parameter is a separate call from this one, and the issue flagged it rather than deciding it.What the refactor exposed
Two test call sites used
diagnostics as never. That cast let an array through where the options object now goes, sooptions.diagnosticswasundefinedand the caller's array silently stayed empty. Ten call sites carried that cast.expect(diagnostics.some((d) => d.status === "missing_assessment")).toBe(false)against an array that could never be populated — vacuously true, and passing for the wrong reason. It now receives a real array. I verified the assertion is genuine rather than still-vacuous by temporarily assertingdiagnostics.length > 0alongside it (passes), then restoring.No assertion was weakened or edited to make this pass; the call sites were fixed to match the new signature, which is the mechanical consequence of the refactor.
Closes #10253
Scope
type(scope): short summaryConventional Commit format, for examplefix(api): restore profile access checks.CONTRIBUTING.mdand does not reintroduce GitHub Pages, VitePress,site/, orCNAME.Closes #123) — a linked open issue is required for every contributor PR.Validation
git diff --checknpm run typechecknpm run test:coveragelocally;codecov/patchrequires ≥99% coverage of the lines AND branches you changednpm run actionlintnpm run test:workersnpm run build:mcpnpm run test:mcp-packnpm run ui:openapi:checknpm run ui:lintnpm run ui:typechecknpm run ui:buildnpm audit --audit-level=moderateDetail:
test/unit/ai-review.test.tsis 293 passed with no assertion edited.npm run typecheckgreen across root, packages and both UI workspaces — the refactor is enforced by the compiler at every call site, which is the point.npm auditreports only pre-existing advisories transitive underrelease-please; this PR changes no dependencies.Safety
UI Evidencesection below with JPG/JPEG or PNG screenshots arranged as organized, captioned, clickable thumbnails.No behaviour change: no signal added or removed, no prompt, demotion rule or verdict path touched. The demotion arming that these parameters control is bit-for-bit what it was — the only difference is that the two paths can no longer be armed inconsistently by a transposition.
UI Evidence
Not applicable — no visible UI, frontend, docs, or extension change.
Notes
Successor to #10210, and the same shape of fix. Found via an AST re-measurement of #10170's parameter-count figures, which were inflated by JSDoc commas: the real count is 177 functions at ≥6 params, not 267, and
persistDecisionRecord— the offender that issue named — has 6, not 13.runWorkersOpinionat 12 was the genuine worst. Details on #10170.