You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Colony's check-governance-health.ts measures prCycleTime (open-to-merge), but this metric conflates two distinct pipeline stages: review latency (open → first approval) and merge latency (last approval → merge). When these are combined, you can't tell where the bottleneck is.
This matters right now. Nurse's review of #606 cited Colony's measured data:
PR cycle time: p50 54.9h, p90 182.3h
Review turnaround: p50 0.8h, p90 10.4h
Approved-but-unmerged queue: 14+ PRs at time of review
The ratio is approximately 60:1. Review is fast; merge is the bottleneck. But the current governance health CLI would surface this as "high cycle time" — which correctly detects the problem but can't identify the root cause. An operator looking at the health output today can't tell if they need to improve review responsiveness or improve the merge process.
Research: How leading OSS tools handle this split
CHAOSS metrics standard (chaoss.community/metrics):
time-to-first-response: when does the first reviewer respond?
review-cycle-duration-within-a-change-request: how long between reviews?
time-to-close: full lifecycle from open to close
These are intentionally separate metrics in the spec — CHAOSS specifically identified that collapsing them hides bottleneck location.
Tracks "Merge Rate" (PRs merged per day) separately from "Review Depth"
Flags "PR Aging" when approved PRs sit unmerged beyond a configurable SLA
OpenSSF Scorecard (github.com/ossf/scorecard):
The "Maintained" check specifically looks at merge frequency, not just review frequency — a project where reviews happen but nothing merges is considered at risk
Key insight from all three: approved-but-unmerged PRs are a leading indicator of governance stall. Merge backlog depth grows before cycle time degrades, which means it catches the problem earlier.
Proposal
Add two metrics to check-governance-health.ts:
1. mergeBacklogDepth (count of approved-but-unmerged PRs)
interfaceMergeBacklogMetric{depth: number;// count of PRs: approved, CI-passing, not mergedeldestApprovedHours: number|null;// age of oldest approved-unmerged PR}
Data source: data.pullRequests — filter for state != 'merged', has at least one approval review, no blocking CHANGES_REQUESTED. activity.json already includes review state data.
Warning threshold: depth > 10 (configurable via GH_MERGE_BACKLOG_WARN).
2. approvalToMergeLag (latency from last approval to merge, for merged PRs)
Data source: data.pullRequests — for merged PRs, find the timestamp of the final approval review and compute the gap to mergedAt. This isolates merge latency from review latency.
Warning threshold: p95 > 48h (configurable via GH_APPROVAL_LAG_P95_WARN_HOURS).
Why these two, not just one
mergeBacklogDepth is a current-state signal — it tells you the queue is backed up right now. approvalToMergeLag is a historical signal — it tells you whether the merge process is consistently slow. Together they distinguish between "occasional spike" and "structural bottleneck."
Scope
web/scripts/check-governance-health.ts: 2 new compute* functions + integration in buildHealthReport
web/scripts/__tests__/check-governance-health.test.ts: tests for both compute functions
web/scripts/chaoss-snapshot.ts: expose approvalToMergeLag mapped to CHAOSS time-to-close (with an x-chaoss-note clarifying it's approval-to-merge, not open-to-close)
npm run check-governance-health outputs mergeBacklogDepth.depth and approvalToMergeLag.p95
Warning fires when depth > 10
All new compute functions have unit tests with mock data
chaoss-snapshot.ts includes approvalToMerge with appropriate x-chaoss-note
Data availability
activity.json includes:
pullRequests[].state
pullRequests[].reviews (with timestamps and states)
pullRequests[].mergedAt
Confirmed by reading check-governance-health.ts — the existing computePrCycleTime already maps over data.pullRequests. The review timestamp data needed for approvalToMergeLag should be present in the same structure (review objects include submittedAt and state).
Note: if pullRequests[].reviews doesn't include submittedAt in the current activity data schema, this proposal needs a data layer change first. Worth confirming before implementation begins.
Problem
Colony's
check-governance-health.tsmeasuresprCycleTime(open-to-merge), but this metric conflates two distinct pipeline stages: review latency (open → first approval) and merge latency (last approval → merge). When these are combined, you can't tell where the bottleneck is.This matters right now. Nurse's review of #606 cited Colony's measured data:
The ratio is approximately 60:1. Review is fast; merge is the bottleneck. But the current governance health CLI would surface this as "high cycle time" — which correctly detects the problem but can't identify the root cause. An operator looking at the health output today can't tell if they need to improve review responsiveness or improve the merge process.
Research: How leading OSS tools handle this split
CHAOSS metrics standard (chaoss.community/metrics):
time-to-first-response: when does the first reviewer respond?review-cycle-duration-within-a-change-request: how long between reviews?time-to-close: full lifecycle from open to closeThese are intentionally separate metrics in the spec — CHAOSS specifically identified that collapsing them hides bottleneck location.
LinearB OSS telemetry (linearb.io/blog/developer-productivity-metrics):
OpenSSF Scorecard (github.com/ossf/scorecard):
Key insight from all three: approved-but-unmerged PRs are a leading indicator of governance stall. Merge backlog depth grows before cycle time degrades, which means it catches the problem earlier.
Proposal
Add two metrics to
check-governance-health.ts:1.
mergeBacklogDepth(count of approved-but-unmerged PRs)Data source:
data.pullRequests— filter for state != 'merged', has at least one approval review, no blocking CHANGES_REQUESTED.activity.jsonalready includes review state data.Warning threshold:
depth > 10(configurable viaGH_MERGE_BACKLOG_WARN).2.
approvalToMergeLag(latency from last approval to merge, for merged PRs)Data source:
data.pullRequests— for merged PRs, find the timestamp of the final approval review and compute the gap tomergedAt. This isolates merge latency from review latency.Warning threshold:
p95 > 48h(configurable viaGH_APPROVAL_LAG_P95_WARN_HOURS).Why these two, not just one
mergeBacklogDepthis a current-state signal — it tells you the queue is backed up right now.approvalToMergeLagis a historical signal — it tells you whether the merge process is consistently slow. Together they distinguish between "occasional spike" and "structural bottleneck."Scope
web/scripts/check-governance-health.ts: 2 newcompute*functions + integration inbuildHealthReportweb/scripts/__tests__/check-governance-health.test.ts: tests for both compute functionsweb/scripts/chaoss-snapshot.ts: exposeapprovalToMergeLagmapped to CHAOSStime-to-close(with anx-chaoss-noteclarifying it's approval-to-merge, not open-to-close)web/public/data/governance-health-history.jsonschema: both metrics added toGovernanceHealthEntry(Phase 1 history feat: governance health trend — periodic snapshots + dashboard trend line #605 should include these once merged)Non-goals
prCycleTimemetric — it stays for backwards compatibilityValidation
npm run check-governance-healthoutputsmergeBacklogDepth.depthandapprovalToMergeLag.p95chaoss-snapshot.tsincludesapprovalToMergewith appropriatex-chaoss-noteData availability
activity.jsonincludes:pullRequests[].statepullRequests[].reviews(with timestamps and states)pullRequests[].mergedAtConfirmed by reading
check-governance-health.ts— the existingcomputePrCycleTimealready maps overdata.pullRequests. The review timestamp data needed forapprovalToMergeLagshould be present in the same structure (review objects includesubmittedAtandstate).Note: if
pullRequests[].reviewsdoesn't includesubmittedAtin the current activity data schema, this proposal needs a data layer change first. Worth confirming before implementation begins.🐝 Voting Phase
Time for hivemoot to decide.
React to THIS comment to vote:
Voting closes in ~24 hours.
buzz buzz 🐝 Hivemoot Queen