원문: https://github.com/facebook/astryx/wiki/Night-Watch-Retrospective · 번역 기준: 2026-09-03

Purpose: Night Watch 코멘트가 가치를 제공하고 있는지 측정하고, 증거에 기반해 동작을 자동으로 조정합니다.


문제

PR에 달리는 agent 코멘트에는 비용이 있습니다. 사람의 주의력을 소모하기 때문입니다. 측정이 없으면 agent는 "누군가의 막힘을 풀어준 유용한 진단"과 "봇 코멘트를 무시하도록 사람들을 학습시킨 noise"를 구분할 수 없습니다. Retrospective Engine이 이 루프를 닫습니다.


동작 방식

1. 모든 outbound 코멘트 추적

Night Watch가 코멘트를 게시하면 state에 기록합니다:

{
  "commentId": 4009239925,
  "prNumber": 459,
  "prAuthor": "mellyeliu",
  "authorType": "external",
  "commentType": "ci_diagnosis",
  "postedAt": "2026-03-06T01:09:22Z",
  "shiftId": "2026-03-05-evening",
  "scored": false
}

2. shift 종료 시 코멘트 채점

각 shift가 끝날 때(업무 시간 전 마지막 QA 실행), 해당 shift 동안 게시한 모든 코멘트를 다시 확인하고 채점합니다:

긍정 신호 (코멘트가 유용했음)

신호 점수 탐지 방법
사람이 코멘트에 답글을 달았음 +3 우리 코멘트 이후에 게시된, 봇이 아닌 답글이 있는지 코멘트 스레드 확인
사람이 reaction을 남겼음 (👍, 🎉, ❤️, 🚀) +2 코멘트 reaction 확인, 봇 reaction 제외
PR author가 코멘트 후 4시간 이내에 fix를 push했음 +2 코멘트 타임스탬프와 PR의 다음 commit을 비교
코멘트 후 24시간 이내에 PR이 merge됨 +1 PR merge 상태와 타임스탬프 확인

부정 신호 (코멘트가 noise였음)

신호 점수 탐지 방법
maintainer 본인의 PR에 남긴 코멘트 (규칙 위반) -3 prAuthor를 maintainer 목록과 대조
24시간 후에도 사람의 engagement가 없음 -1 코멘트 이후 답글도, reaction도, commit도 없음
같은 PR에 남긴 이전 Night Watch 코멘트의 중복 -3 같은 에러 유형이 이번 shift에 이미 진단되었는지 확인
Night Watch가 닫은 뒤 PR이 다시 열림 -5 우리가 닫은 뒤 reopen이 있었는지 PR timeline 이벤트 확인
GitHub UI에서 이미 보이는 정보를 되풀이하는 코멘트 -1 휴리스틱: merge_conflict 유형은 항상 이 페널티를 받음

채점 구현

for comment in shift_comments:
  score = 0
  
  # Positive signals
  human_replies = gh api /repos/.../issues/{pr}/comments \
    | filter(created_after=comment.postedAt, user.type != "Bot")
  if human_replies: score += 3
  
  human_reactions = gh api /repos/.../issues/comments/{id}/reactions \
    | filter(user.type != "Bot")
  if human_reactions: score += 2
  
  fix_commits = gh api /repos/.../pulls/{pr}/commits \
    | filter(date > comment.postedAt, date < comment.postedAt + 4h)
  if fix_commits and comment.authorType == "external": score += 2
  
  pr = gh api /repos/.../pulls/{pr}
  if pr.merged and within_24h(pr.merged_at, comment.postedAt): score += 1
  
  # Negative signals
  if comment.authorType == "maintainer": score -= 3
  if comment.commentType == "merge_conflict": score -= 1
  if no_human_engagement_after_24h(comment): score -= 1
  
  comment.score = score

3. 집계와 적응

shift 전반에 걸쳐 rolling score를 추적합니다: