@@ -144,7 +144,7 @@ type CalculateResponse struct {
144144type RepoSampleRequest struct {
145145 Owner string `json:"owner"`
146146 Repo string `json:"repo"`
147- SampleSize int `json:"sample_size,omitempty"` // Default: 50
147+ SampleSize int `json:"sample_size,omitempty"` // Default: 100
148148 Days int `json:"days,omitempty"` // Default: 60
149149 Config * cost.Config `json:"config,omitempty"`
150150}
@@ -154,7 +154,7 @@ type RepoSampleRequest struct {
154154//nolint:govet // fieldalignment: API struct field order optimized for readability
155155type OrgSampleRequest struct {
156156 Org string `json:"org"`
157- SampleSize int `json:"sample_size,omitempty"` // Default: 50
157+ SampleSize int `json:"sample_size,omitempty"` // Default: 100
158158 Days int `json:"days,omitempty"` // Default: 60
159159 Config * cost.Config `json:"config,omitempty"`
160160}
@@ -1478,18 +1478,18 @@ func (s *Server) parseRepoSampleRequest(ctx context.Context, r *http.Request) (*
14781478
14791479 // Set defaults
14801480 if req .SampleSize == 0 {
1481- req .SampleSize = 50
1481+ req .SampleSize = 100
14821482 }
14831483 if req .Days == 0 {
14841484 req .Days = 60
14851485 }
14861486
1487- // Validate reasonable limits (silently cap at 50 )
1487+ // Validate reasonable limits (silently cap at 100 )
14881488 if req .SampleSize < 1 {
14891489 return nil , errors .New ("sample_size must be at least 1" )
14901490 }
1491- if req .SampleSize > 50 {
1492- req .SampleSize = 50
1491+ if req .SampleSize > 100 {
1492+ req .SampleSize = 100
14931493 }
14941494 if req .Days < 1 || req .Days > 365 {
14951495 return nil , errors .New ("days must be between 1 and 365" )
@@ -1536,18 +1536,18 @@ func (s *Server) parseOrgSampleRequest(ctx context.Context, r *http.Request) (*O
15361536
15371537 // Set defaults
15381538 if req .SampleSize == 0 {
1539- req .SampleSize = 50
1539+ req .SampleSize = 100
15401540 }
15411541 if req .Days == 0 {
15421542 req .Days = 60
15431543 }
15441544
1545- // Validate reasonable limits (silently cap at 50 )
1545+ // Validate reasonable limits (silently cap at 100 )
15461546 if req .SampleSize < 1 {
15471547 return nil , errors .New ("sample_size must be at least 1" )
15481548 }
1549- if req .SampleSize > 50 {
1550- req .SampleSize = 50
1549+ if req .SampleSize > 100 {
1550+ req .SampleSize = 100
15511551 }
15521552 if req .Days < 1 || req .Days > 365 {
15531553 return nil , errors .New ("days must be between 1 and 365" )
@@ -1659,17 +1659,19 @@ func (s *Server) processRepoSample(ctx context.Context, req *RepoSampleRequest,
16591659 openPRCount = 0
16601660 }
16611661
1662- // Convert PRSummary to PRMergeStatus for merge rate calculation
1663- prStatuses := make ([]cost.PRMergeStatus , len (prs ))
1662+ // Convert PRSummary to PRSummaryInfo for extrapolation
1663+ prSummaryInfos := make ([]cost.PRSummaryInfo , len (prs ))
16641664 for i , pr := range prs {
1665- prStatuses [i ] = cost.PRMergeStatus {
1665+ prSummaryInfos [i ] = cost.PRSummaryInfo {
1666+ Owner : pr .Owner ,
1667+ Repo : pr .Repo ,
16661668 Merged : pr .Merged ,
16671669 State : pr .State ,
16681670 }
16691671 }
16701672
16711673 // Extrapolate costs from samples
1672- extrapolated := cost .ExtrapolateFromSamples (breakdowns , len (prs ), totalAuthors , openPRCount , actualDays , cfg , prStatuses )
1674+ extrapolated := cost .ExtrapolateFromSamples (breakdowns , len (prs ), totalAuthors , openPRCount , actualDays , cfg , prSummaryInfos , nil )
16731675
16741676 // Only include seconds_in_state if we have data (turnserver only)
16751677 var secondsInState map [string ]int
@@ -1721,6 +1723,23 @@ func (s *Server) processOrgSample(ctx context.Context, req *OrgSampleRequest, to
17211723 return nil , fmt .Errorf ("no PRs found in the last %d days" , req .Days )
17221724 }
17231725
1726+ // Fetch repository visibility for the organization (2x the time period for comprehensive coverage)
1727+ reposSince := time .Now ().AddDate (0 , 0 , - req .Days * 2 )
1728+ repoVisibilityData , err := github .FetchOrgRepositoriesWithActivity (ctx , req .Org , reposSince , token )
1729+ if err != nil {
1730+ s .logger .WarnContext (ctx , "Failed to fetch repository visibility, assuming all public" , "error" , err )
1731+ repoVisibilityData = nil
1732+ }
1733+
1734+ // Convert RepoVisibility map to bool map (repo name -> isPrivate)
1735+ var repoVisibility map [string ]bool
1736+ if repoVisibilityData != nil {
1737+ repoVisibility = make (map [string ]bool , len (repoVisibilityData ))
1738+ for name , visibility := range repoVisibilityData {
1739+ repoVisibility [name ] = visibility .IsPrivate
1740+ }
1741+ }
1742+
17241743 // Calculate actual time window (may be less than requested if we hit API limit)
17251744 actualDays , _ = github .CalculateActualTimeWindow (prs , req .Days )
17261745
@@ -1788,17 +1807,19 @@ func (s *Server) processOrgSample(ctx context.Context, req *OrgSampleRequest, to
17881807 }
17891808 s .logger .InfoContext (ctx , "Counted total open PRs across organization" , "org" , req .Org , "open_prs" , totalOpenPRs )
17901809
1791- // Convert PRSummary to PRMergeStatus for merge rate calculation
1792- prStatuses := make ([]cost.PRMergeStatus , len (prs ))
1810+ // Convert PRSummary to PRSummaryInfo for extrapolation
1811+ prSummaryInfos := make ([]cost.PRSummaryInfo , len (prs ))
17931812 for i , pr := range prs {
1794- prStatuses [i ] = cost.PRMergeStatus {
1813+ prSummaryInfos [i ] = cost.PRSummaryInfo {
1814+ Owner : pr .Owner ,
1815+ Repo : pr .Repo ,
17951816 Merged : pr .Merged ,
17961817 State : pr .State ,
17971818 }
17981819 }
17991820
18001821 // Extrapolate costs from samples
1801- extrapolated := cost .ExtrapolateFromSamples (breakdowns , len (prs ), totalAuthors , totalOpenPRs , actualDays , cfg , prStatuses )
1822+ extrapolated := cost .ExtrapolateFromSamples (breakdowns , len (prs ), totalAuthors , totalOpenPRs , actualDays , cfg , prSummaryInfos , repoVisibility )
18021823
18031824 // Only include seconds_in_state if we have data (turnserver only)
18041825 var secondsInState map [string ]int
@@ -2194,17 +2215,19 @@ func (s *Server) processRepoSampleWithProgress(ctx context.Context, req *RepoSam
21942215 openPRCount = 0
21952216 }
21962217
2197- // Convert PRSummary to PRMergeStatus for merge rate calculation
2198- prStatuses := make ([]cost.PRMergeStatus , len (prs ))
2218+ // Convert PRSummary to PRSummaryInfo for extrapolation
2219+ prSummaryInfos := make ([]cost.PRSummaryInfo , len (prs ))
21992220 for i , pr := range prs {
2200- prStatuses [i ] = cost.PRMergeStatus {
2221+ prSummaryInfos [i ] = cost.PRSummaryInfo {
2222+ Owner : pr .Owner ,
2223+ Repo : pr .Repo ,
22012224 Merged : pr .Merged ,
22022225 State : pr .State ,
22032226 }
22042227 }
22052228
22062229 // Extrapolate costs from samples
2207- extrapolated := cost .ExtrapolateFromSamples (breakdowns , len (prs ), totalAuthors , openPRCount , actualDays , cfg , prStatuses )
2230+ extrapolated := cost .ExtrapolateFromSamples (breakdowns , len (prs ), totalAuthors , openPRCount , actualDays , cfg , prSummaryInfos , nil )
22082231
22092232 // Only include seconds_in_state if we have data (turnserver only)
22102233 var secondsInState map [string ]int
@@ -2353,17 +2376,19 @@ func (s *Server) processOrgSampleWithProgress(ctx context.Context, req *OrgSampl
23532376 }
23542377 s .logger .InfoContext (ctx , "Counted total open PRs across organization" , "open_prs" , totalOpenPRs , "org" , req .Org )
23552378
2356- // Convert PRSummary to PRMergeStatus for merge rate calculation
2357- prStatuses := make ([]cost.PRMergeStatus , len (prs ))
2379+ // Convert PRSummary to PRSummaryInfo for extrapolation
2380+ prSummaryInfos := make ([]cost.PRSummaryInfo , len (prs ))
23582381 for i , pr := range prs {
2359- prStatuses [i ] = cost.PRMergeStatus {
2382+ prSummaryInfos [i ] = cost.PRSummaryInfo {
2383+ Owner : pr .Owner ,
2384+ Repo : pr .Repo ,
23602385 Merged : pr .Merged ,
23612386 State : pr .State ,
23622387 }
23632388 }
23642389
23652390 // Extrapolate costs from samples
2366- extrapolated := cost .ExtrapolateFromSamples (breakdowns , len (prs ), totalAuthors , totalOpenPRs , actualDays , cfg , prStatuses )
2391+ extrapolated := cost .ExtrapolateFromSamples (breakdowns , len (prs ), totalAuthors , totalOpenPRs , actualDays , cfg , prSummaryInfos , nil )
23672392
23682393 // Only include seconds_in_state if we have data (turnserver only)
23692394 var secondsInState map [string ]int
0 commit comments