fix(scoring): skip unmodeled-drift sync on garbage upstream constants bodies - #8972
Conversation
… bodies The fail-closed path freezes last-good when constants.py is garbage-but-200, but with no verified last-good the refresh still fell through and ran syncUnmodeledScoringConstantDrift on HTTP-ok alone — opening a spurious drift report from HTML/LFS junk. Gate the sync on constantsUsable instead. Closes JSONbored#8902
|
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 #8972 +/- ##
==========================================
+ Coverage 90.56% 90.57% +0.01%
==========================================
Files 96 97 +1
Lines 22490 22558 +68
Branches 3884 3908 +24
==========================================
+ Hits 20367 20433 +66
Misses 1945 1945
- Partials 178 180 +2
Flags with carried forward coverage won't be shown. Click here to find out more.
|
|
Warning ⏸️ LoopOver review result - manual review recommendedReview updated: 2026-07-26 15:20:47 UTC
Decision drivers
Context & advisory signals — never blocks the verdict
Linked issue satisfactionAddressed Review context
Contributor next steps
Signal definitions
🧪 Chat with LoopOverAsk LoopOver a question about this PR directly in a comment — grounded only in the same cached, public-safe facts shown above, never a new claim.
Full command reference: https://loopover.ai/docs/loopover-commands 🧪 Experimental — new and may change. Decision record
🟩 Safe / merged · 🟦 Advisory · 🟨 Held for review · 🟥 Blocked / closed 💰 Earn for open-source contributions like this. Gittensor lets GitHub contributors earn for the work they already do — register to start earning →. Checked by LoopOver, a quiet PR intelligence layer for OSS maintainers.
|
…nd name every silent AI-review skip (#9180) * fix(review): finalize CI-stuck silence, post a waiting placeholder, and name every silent AI-review skip #9011: prReadyForReview used to defer a missing-required-context PR forever past the 2-minute cap instead of falling through to the existing finalize-past-cap block; a required context that never appears keeps ciState pending (never "passed"), so finalizing here can never produce a would-merge disposition. A new stuckReason ("missing_required_context" vs "ci_running") is threaded through the audit/log calls so the two causes are distinguishable. #9042: the silent wait before a review runs (measured live: 8.3min median, 21.9min p90, up to 50.9min) now gets an immediate "waiting" panel comment (renderWaitingForCiPlaceholder) upserted through the same PR_PANEL_COMMENT_MARKER the final verdict replaces, instead of leaving the PR blank until CI settles. #9000: root-causes the #8972 incident where a forced ("Re-run LoopOver review") retrigger completed with none of the events a forced pass should emit anywhere in the audit trail. shouldStartAiReviewForAdvisory folds in shouldRequirePublicAiReviewForAdvisory's hard gate (aiReviewMode off, an ineligible author, no head SHA, an AI kill-switch off, no AI binding) - a forced retrigger does not bypass this gate, and every one of its branches previously returned false with zero audit trail. resolvePublicAiReviewGateSkipReason names the exact reason, and a new catch-all audit event fires whenever aiReviewWillRun ends up false for a cause none of the other (already-audited) paths cover. The two adjacent silent branches in the frozen/paused/one-shot reuse chain - a hold condition true but nothing published to actually reuse - get their own named "unavailable" events for the same reason. This only closes the exhaustive-auditing and root-cause portion of #9000; the receipt-feedback / lost-webhook-click recovery sweep it also asks for is not yet implemented. Closes #9011 Closes #9042 * fix(review): correct stale 'gittensory' brand reference in a comment #9173 introduced a comment referencing the deprecated pre-rename product name, which the branding-drift check on main was not catching -- breaking CI for every PR based on current main, including this one.
…erasing them (#9000) (#9584) The lost-click half of #9000, completing the issue (the skip-auditing half landed earlier; its enforcement went in as #9583). THE DEFECT. Three checkbox states looked identical to a maintainer: processed (panel republished, box reset), deferred for CI (box stays ticked, honored later via the #7626 pending marker), and DELIVERY LOST (box stays ticked, nothing recorded, nothing will ever happen -- three such losses observed live on #8972, 2026-07-26). Only the third is broken, and it is unrecoverable from our own state alone: the tick exists only in the live comment body, because the webhook that would have told us about it never became a job. Worse, the next panel republish -- whose renderer emits its checkboxes unticked unconditionally -- would OVERWRITE the ticked box, erasing the only evidence of the click on the exact pass best placed to honor it. THE FIX, at zero additional API cost. createOrUpdateIssueCommentWithMarker already fetches the existing comment for its marker search; it now returns that pre-overwrite body. Every panel republish (webhook pass, re-gate sweep, backlog convergence) doubles as the detector: a ticked rerun box in the body being replaced, with no recent processing and no pending marker, IS a lost click. Recovery then: - records github_app.pr_panel_retrigger_recovered (the named reason #9003 demands, and the loop guard against re-detection), - persists the #7626 pending marker, so the next review pass consumes it as forceAiReview exactly like a deferred click, and - enqueues an agent-regate-pr job immediately (with the #9499 prCreatedAt sort key) -- a PR with a lost click is precisely the PR that cannot count on a natural pass. No new sweep, no new persistence: the issue's "within one sweep interval" acceptance is bounded by the republish cadence that already exists. FALSE-POSITIVE PROOFING, the part that took the design care: - A pass that IS the retrigger (forceAiReview) skips detection -- overwriting its own tick is the receipt acknowledgement, not a loss. - A recently-processed retrigger (actor-agnostic audit lookup, new countAuditEventsForTargetSince -- hasAuditEventForDelivery is deliberately actor+delivery-keyed, the wrong shape when the delivery never existed) means the delivery raced the pass rather than being lost. - A DEFERRED click is guarded by ordering, not luck: the retrigger handler now marks the pending marker BEFORE its readiness check (consuming it right back on the immediate path), so the CI-wait placeholder inside that very pass sees the marker and stands down. A crash between mark and consume degrades to one extra forced review -- the safe direction for an explicit user click. The #7626 sibling test's "never creates a pending marker" assertion is updated to the invariant it documents ("no pending INTENT survives the immediate path") rather than its old mechanism (key absence), since consumption can leave the one-shot consumed sentinel behind on adapters without a real delete. TESTS. Eight in the new suite: the #8972 regression (natural pass recovers the tick: event + marker + job with the sort key), full end-to-end (the recovery job's pass consumes the marker, spends exactly one fresh AI review, and does not re-diagnose its own republish), the raced-delivery guard, the deferred-click guard (CI genuinely pending, marker untouched afterward), the no-head ghost PR (marker guard skipped, job omits the optional sort key), unticked and first-publish no-ops, and the empty event-type-list guard. Plus the three github-comments assertions extended to pin previousBody, including that it is the POSTED body, not the re-render, on the byte-identical skip path. Changed lines: 0 uncovered statements, 0 uncovered branches.
Problem
Closes #8902.
refreshScoringModelSnapshotcorrectly fails closed when a 200constants.pybody is semantically garbage and a verified last-good exists — but with no last-good (first run / prior fallback), execution continues and the drift-sync guard was onlyif (constantsResult.ok). That still ranfindUnmodeledUpstreamConstantsagainst HTML/LFS junk and could open a spuriousupstream_drift_reportsrow.Fix
Gate
syncUnmodeledScoringConstantDriftonconstantsUsable(the same recognized-count floor the fail-closed path already uses), not merely HTTP-ok.Tests
listUpstreamDriftReportsstays empty even when the junk body contains a parseable fake unmodeled constant name.Reverting the guard fails the empty-reports assertion.
git diff --checkclean.Scope
Validation
git diff --checkSafety