You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
feat(review): regenerate a public-safe summary when the narrative is withheld (#9956)
* feat(review): regenerate a public-safe summary when the narrative is withheld
Closes#9809.
When every sentence of a review's narrative trips the public-safety sanitizer --
routine for a PR touching this project's own scoring/gate code, where an honest
sentence says 'score' or 'ranking' -- the reader got a fixed placeholder rather
than a real summary. #9806 made that placeholder honest; this makes it a summary.
On the withheld branch only, the narrative is rewritten for a public audience in
one small completion and then held to the IDENTICAL sanitizer. The prompt is not
the boundary: a rewrite that still names forbidden vocabulary is discarded and
the fixed sentence stays the floor, so this can only improve the text a reader
sees and can never widen what is publishable. A prompt-injected or careless
rewrite fails closed, as does a provider error or the model's own
CANNOT_SUMMARIZE opt-out.
Scoped to the NO-BLOCKERS branch. The issue asks for a real summary every time
and that a withheld blocker never read as clean; for a withheld blocker those
conflict, and this resolves toward the safety property -- prose reading clean
over a blocker the model actually raised is the one outcome that could
green-light a PR. Blockers keep their fixed sentence, structurally, not by
trusting the prompt.
The provider call lives at the single caller rather than inside
composeAdvisoryNotes, which stays pure and synchronous: making the composer async
would push await through its call site and cost the testability that makes the
sanitizer's behaviour verifiable. narrativeWasWithheld() lets the caller decide
whether to spend the call before composing, computed the same way the composer
decides, so the two cannot drift.
The counter records both outcomes -- an all-fallback result must not look
identical to the feature never firing.
* test(review): unstub fetch after the regeneration cases
The provider-path cases stub global fetch and never restored it, so the stub
leaked into whatever file the worker ran next -- it took out
selfhost-metrics.test.ts in a full run while passing in isolation.
["loopover_ai_review_summary_regenerated_total",{help: "Public-safe summary regenerations on the withheld-narrative branch, by outcome (#9809): `published` when the rewrite survived the sanitizer, `fallback` when the fixed sentence was kept. Both are counted -- an all-fallback result must not look the same as the feature never firing.",type: "counter"}],
136
137
["loopover_ai_review_unpublishable_blocker_total",{help: "AI reviews where a reviewer named a real blocker whose title could not be published, so the verdict held instead of passing (#9460).",type: "counter"}],
/** The honest fixed sentence for a withheld narrative that raised BLOCKERS (#9806). Never replaced by a
2291
+
* regenerated summary: prose that could read as clean over a real blocker is the one wrong outcome here. */
2292
+
exportconstWITHHELD_NARRATIVE_WITH_BLOCKERS=
2293
+
"The AI review completed and raised blocking findings, but they were withheld from this public surface because they referenced non-public project internals. A maintainer should read the private review record before deciding this PR.";
2294
+
2295
+
/** The honest fixed sentence for a withheld narrative with no blockers (#9806). This is the floor #9809's
2296
+
* regenerated summary improves on -- and falls back to whenever the rewrite does not survive the sanitizer. */
2297
+
exportconstWITHHELD_NARRATIVE_CLEAN=
2298
+
"The AI review completed and found no blocking issues. Its narrative summary was withheld from this public surface because it referenced non-public project internals.";
2299
+
2300
+
/**
2301
+
* Would this review's narrative be withheld entirely, leaving only a fixed sentence? (#9809)
2302
+
*
2303
+
* Exported so the caller can decide whether to spend an LLM call BEFORE composing, without string-matching
2304
+
* the published output to find out. PURE, and deliberately the same computation `composeAdvisoryNotes` does
2305
+
* -- reproducing the sanitizer's decision by any other means would let the two drift, and a regeneration
2306
+
* that fires on a review whose narrative was actually published is wasted spend on every review.
2307
+
*
2308
+
* False when blockers are present: that branch keeps its fixed sentence, so a rewrite would be discarded.
// review's real verdict. The genuinely-empty case (no parsed review content at all) still returns null
2270
2351
// below, so a true provider failure keeps its accurate "unavailable" report.
2271
2352
if(!publicAssessment&&assessments.length>0){
2272
-
// Wording must track the review's REAL verdict: with raw blockers present (all withheld above), claiming
2273
-
// "no blocking issues" would be false and could green-light a PR the model actually flagged.
2353
+
// #9809: a REGENERATED summary, when the caller obtained one. It is a public-audience rewrite of this same
2354
+
// narrative that has already been through the identical sanitizer, so publishing it cannot leak anything
2355
+
// the per-sentence gate above would have withheld. Absent (no call made, or the rewrite tripped the
2356
+
// sanitizer too), the fixed sentence below stays the floor -- a real summary is the goal, never at the
2357
+
// cost of the never-echo guarantee.
2358
+
//
2359
+
// Blockers are the exception: a withheld BLOCKER must never be replaced by prose that could read as
2360
+
// clean, so that branch keeps its fixed sentence regardless of what the rewrite produced.
2274
2361
publicAssessment=
2275
2362
blockers.length>0
2276
-
? "The AI review completed and raised blocking findings, but they were withheld from this public surface because they referenced non-public project internals. A maintainer should read the private review record before deciding this PR."
2277
-
: "The AI review completed and found no blocking issues. Its narrative summary was withheld from this public surface because it referenced non-public project internals.";
// A publishable narrative needs no regeneration -- firing there would spend a completion on every review.
5678
+
expect(narrativeWasWithheld([modelReview({assessment: "The error branch is unhandled."})])).toBe(false);
5679
+
// Blockers keep the fixed sentence, so a rewrite would be discarded; do not pay for one.
5680
+
expect(narrativeWasWithheld([modelReview({blockers: ["The ranking weight is wrong"]})])).toBe(false);
5681
+
expect(narrativeWasWithheld([])).toBe(false);
5682
+
});
5683
+
5684
+
it("publishes a regenerated summary that survives the sanitizer",()=>{
5685
+
constnotes=composeAdvisoryNotes([modelReview()],{regeneratedAssessment: "The change updates how a value is computed and the tests cover both branches."});
5686
+
expect(notes).toContain("the tests cover both branches");
0 commit comments