Skip to content

Commit 6635fd1

Browse files
feat: add per-team Average Merge Cycle Time chart to team tabs
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent d6eaa25 commit 6635fd1

1 file changed

Lines changed: 28 additions & 0 deletions

File tree

reports/chart_data.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -465,6 +465,34 @@ def _extract_team(df: pd.DataFrame) -> List[Dict[str, Any]]:
465465
"series": series_30,
466466
})
467467

468+
# 19-T: Avg merge cycle time (by week) for this team
469+
if "created_at" in tdf.columns and "merged_at" in tdf.columns:
470+
ctdf = tdf.dropna(subset=["created_at", "merged_at"]).copy()
471+
ctdf["cycle_hours"] = (
472+
pd.to_datetime(ctdf["merged_at"], format="mixed", utc=False, errors="coerce")
473+
- pd.to_datetime(ctdf["created_at"], format="mixed", utc=False, errors="coerce")
474+
).dt.total_seconds() / 3600
475+
ctdf = ctdf[ctdf["cycle_hours"] >= 0]
476+
if not ctdf.empty:
477+
merged = pd.to_datetime(ctdf["merged_at"], format="mixed", utc=False, errors="coerce")
478+
if merged.dt.tz is not None:
479+
merged = merged.dt.tz_localize(None, ambiguous="infer")
480+
ctdf["week"] = merged.dt.to_period("W").dt.start_time
481+
weekly_cycle = ctdf.groupby("week")["cycle_hours"].mean()
482+
if not weekly_cycle.empty:
483+
labels = [d.strftime("%Y-%m-%d") for d in weekly_cycle.index]
484+
overall_avg = round(float(weekly_cycle.mean()), 1)
485+
charts.append({
486+
"id": f"19-{team}",
487+
"type": "line",
488+
"title": f"Average Merge Cycle Time — {team}",
489+
"subtitle": "created_at → merged_at in hours (by week)",
490+
"_subtab": team,
491+
"overall_avg": overall_avg,
492+
"x": labels,
493+
"y": [round(float(v), 1) for v in weekly_cycle.tolist()],
494+
})
495+
468496
# 06: Scatter
469497
agg = tdf.groupby("developer").agg(pr_count=("pr_url", "count"), total_complexity=("complexity", "sum"))
470498
if len(agg) >= 2:

0 commit comments

Comments
 (0)