Per-repo signals derived from the outcome ledger, recomputed each daily run
so a corrected ledger entry corrects the score (no one-way latching):
avgResponseDays: MEDIAN days to first maintainer response (name kept for
the schema; median so one forgotten PR doesn't skew it). Unanswered PRs
are censored, not dropped, so a repo that ignores most PRs can't grade
fast off the one it answered. Each PR opened in the last 12 months gives:
answered: openedAt -> firstMaintainerResponseAt
merged with no recorded response: openedAt -> mergedAt (the merge was
the response; errs slow, since any earlier reply went unrecorded)
closed and confirmed unanswered under the current maintainer rule
(responseRule), except self-closes: openedAt -> closedAt, a lower bound
open and still waiting: createdAt -> now, a lower bound
Lower bounds count only from 14 days (CENSORED_MIN_DAYS): a PR opened
yesterday or closed within days says nothing yet and would grade fast.
Null below 3 samples.
hasHostileComments: any closed PR here has closeReason 'ai-policy'.
Repos with no ledger or open PR data are absent; callers treat absent as
{ avgResponseDays: null, hasHostileComments: false }.
Per-repo signals derived from the outcome ledger, recomputed each daily run so a corrected ledger entry corrects the score (no one-way latching):
Repos with no ledger or open PR data are absent; callers treat absent as
{ avgResponseDays: null, hasHostileComments: false }.