Skip to content

feat(miner-manage): invalidate/refresh the miner decision-pack on pr_outcome write, replacing the current ~6h debounce #4283

Description

@JSONbored

Re-homed from the stale pre-decomposition epic #1058 (its one live child was never re-filed elsewhere; the epic's other four children shipped via #1059, #1060/#1097, #1022, and #975/#976/#977/#1029).

The existing pull_request.closed webhook handler that backs pr_outcome is recordPrOutcome (src/review/outcomes-wire.ts:285-344), called from the main webhook-processing path in src/queue/processors.ts:5796. On every pull_request closed event it writes a pr_outcome row to review_audit (eventType: "pr_outcome", decision merged/closed) and to audit_events, and — already, right there — extracts the PR author's login (authorLogin, outcomes-wire.ts:297), currently used only for the self-close anti-poisoning guard (outcomes-wire.ts:299-310). That's the exact login whose decision pack should be refreshed; the function just doesn't currently do anything decision-pack-related.

The "~6h debounce" this item refers to is DECISION_PACK_MAX_AGE_MS = 6 * 60 * 60 * 1000 (src/services/decision-pack.ts:72). It's checked passively, only at serving time, inside loadContributorDecisionPackForServing (decision-pack.ts:352-388): stale = cached.stale || snapshotAgeMs(cached.generatedAt) > maxAgeMs (decision-pack.ts:374). A pack only gets rebuilt when it's next requested (e.g. via the gittensory_get_decision_pack MCP tool) and found older than 6h — a PR closing does not itself trigger anything. Separately, DECISION_PACK_REBUILD_DEBOUNCE_MS = 15 * 1000 (decision-pack.ts:81, 15 seconds — much shorter, easy to confuse with the 6h figure) already exists purely to stop tryEnqueueDecisionPackRebuild (decision-pack.ts:390-404) from double-enqueueing the same login's rebuild if it's already in flight; that function is exactly what this issue should call, just from a new trigger point instead of only from the passive serving-time check.

Deliverables

  • Call tryEnqueueDecisionPackRebuild(env, authorLogin) (src/services/decision-pack.ts:390) from within or right after recordPrOutcome (src/review/outcomes-wire.ts:285) once a pr_outcome row is written, using the authorLogin already extracted at outcomes-wire.ts:297 — so a decision pack rebuilds within seconds of a relevant PR closing instead of waiting up to 6h for the next passive read
  • Keep this best-effort and non-blocking, consistent with how recordPrOutcome is already called (processors.ts:5796 wraps it in .catch(...) so outcome recording never blocks the webhook) — a decision-pack enqueue failure must not affect pr_outcome recording itself
  • DECISION_PACK_MAX_AGE_MS (the 6h passive staleness window) stays as a fallback/ceiling for contributors whose PRs don't trigger this new path (e.g. pack requested before any PR has closed) — this issue adds a proactive trigger, it does not remove the passive check
  • Guard against enqueuing for logins with no meaningful decision pack impact if applicable (e.g., confirm authorLogin is non-empty per the existing check at outcomes-wire.ts:296-297 before calling)
  • Unit/integration tests asserting: closing a PR calls tryEnqueueDecisionPackRebuild for the PR author; a self-close (already suppressed by the existing anti-poisoning guard, outcomes-wire.ts:303-310) does NOT trigger a rebuild either, for consistency with what already doesn't get recorded as ground truth; and a rebuild-enqueue failure doesn't throw out of recordPrOutcome

References

  • src/review/outcomes-wire.ts:285-344 (recordPrOutcome — the existing pull_request.closed handler that backs pr_outcome; authorLogin already extracted at line 297)
  • src/queue/processors.ts:5788-5804 (the webhook-processing call site, showing the existing best-effort .catch() pattern to match)
  • src/services/decision-pack.ts:72,81,352-404 (DECISION_PACK_MAX_AGE_MS, DECISION_PACK_REBUILD_DEBOUNCE_MS, loadContributorDecisionPackForServing, tryEnqueueDecisionPackRebuild — the passive check and the exact function this issue wires up proactively)
  • Tracker #2353, re-homed from epic #1058

Metadata

Metadata

Assignees

No one assigned

    Labels

    gittensor:featureGittensor-scored feature linked to a feature issue — scores a 0.25x multiplier.gittensor:priorityMaintainer-selected Gittensor priority — scores a 1.5x multiplier.help wantedExtra attention is needed

    Projects

    Status
    Done

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions