@@ -429,12 +429,14 @@ def fetch_pr_context(
429429
430430 # Last substantive event = last event whose body is non-empty OR whose
431431 # kind is not "review:COMMENTED" (state changes always count). Merge
432- # commits (≥2 parents — e.g. "Update branch" merging base into the PR)
433- # don't count as substantive: they don't move the conversation forward.
432+ # commits (≥2 parents) by someone *other* than the author — e.g. an
433+ # approver clicking "Update branch" — don't count as substantive: they
434+ # don't move the conversation forward and shouldn't be confused with
435+ # the author addressing feedback.
434436 def is_substantive (e : dict [str , Any ]) -> bool :
435437 if e ["kind" ].startswith ("review:" ) and e ["kind" ] != "review:COMMENTED" :
436438 return True
437- if e .get ("is_merge" ):
439+ if e .get ("is_merge" ) and ( e . get ( "login" ) or "" ). lower () != author . lower () :
438440 return False
439441 return bool ((e .get ("body" ) or "" ).strip ())
440442
@@ -443,16 +445,34 @@ def is_substantive(e: dict[str, Any]) -> bool:
443445
444446 # Commit summaries (subject only) for the brief table in the rendered
445447 # context. Full commit messages and diffs travel via timeline events.
448+ # Merge commits authored by someone other than the PR author (e.g. an
449+ # approver clicking "Update branch") are flagged so the model doesn't
450+ # treat them as the author addressing feedback.
446451 commit_rows = []
447452 for c in recent_commits :
448- sha = (c .get ("sha" ) or "" )[:7 ]
453+ sha_full = c .get ("sha" ) or ""
454+ sha = sha_full [:7 ]
449455 msg = (c .get ("commit" ) or {}).get ("message" , "" ).splitlines ()[0 ] if c .get ("commit" ) else ""
450456 a = c .get ("author" ) or {}
451457 commit_login = a .get ("login" ) or ((c .get ("commit" ) or {}).get ("author" ) or {}).get ("name" ) or "?"
452458 commit_date = ((c .get ("commit" ) or {}).get ("author" ) or {}).get ("date" ) or ""
453- commit_rows .append ({"sha" : sha , "msg" : msg , "author" : commit_login , "date" : commit_date })
459+ is_non_author_merge = (
460+ sha_full in merge_shas
461+ and (commit_login or "" ).lower () != author .lower ()
462+ )
463+ commit_rows .append ({
464+ "sha" : sha ,
465+ "msg" : msg ,
466+ "author" : commit_login ,
467+ "date" : commit_date ,
468+ "is_non_author_merge" : is_non_author_merge ,
469+ })
454470
455- last_commit_date = parse_ts (commit_rows [- 1 ]["date" ]) if commit_rows else None
471+ # "Last commit pushed" is meant to surface real author activity, so
472+ # skip non-author merge commits (e.g. approvers clicking "Update
473+ # branch") when picking the timestamp.
474+ real_rows = [r for r in commit_rows if not r ["is_non_author_merge" ]]
475+ last_commit_date = parse_ts (real_rows [- 1 ]["date" ]) if real_rows else None
456476
457477 # Checks summary.
458478 failing = [c for c in checks if (c .get ("state" ) or "" ).upper () in ("FAILURE" , "ERROR" )]
@@ -554,7 +574,8 @@ def render_context(ctx: dict[str, Any]) -> str:
554574 # Commits
555575 lines .append (f"Last { len (ctx ['commits' ])} commits (oldest first):" )
556576 for c in ctx ["commits" ]:
557- lines .append (f" { c ['sha' ]} { c ['date' ][:10 ]} @{ c ['author' ]} : { truncate (c ['msg' ], 120 )} " )
577+ suffix = " [merge from base by non-author — not substantive activity]" if c .get ("is_non_author_merge" ) else ""
578+ lines .append (f" { c ['sha' ]} { c ['date' ][:10 ]} @{ c ['author' ]} : { truncate (c ['msg' ], 120 )} { suffix } " )
558579 lines .append ("" )
559580
560581 # Last substantive event highlight
0 commit comments