@@ -1273,6 +1273,14 @@ function normalizeOptionalPositiveInteger(value: JsonValue | undefined, field: s
12731273 return null ;
12741274}
12751275
1276+ const MAX_CONTRIBUTOR_OPEN_ITEM_CAP = 100 ;
1277+
1278+ function normalizeOptionalContributorOpenItemCap ( value : JsonValue | undefined , field : string , warnings : string [ ] ) : number | null {
1279+ const parsed = normalizeOptionalPositiveInteger ( value , field , warnings ) ;
1280+ if ( parsed === null ) return null ;
1281+ return Math . min ( parsed , MAX_CONTRIBUTOR_OPEN_ITEM_CAP ) ;
1282+ }
1283+
12761284const REVIEW_VISUAL_MAX_ROUTES_LIMIT = 5 ;
12771285
12781286function normalizeOptionalVisualMaxRoutes ( value : JsonValue | undefined , warnings : string [ ] ) : number | null {
@@ -1664,8 +1672,9 @@ function parseSettingsOverride(value: JsonValue | undefined, warnings: string[])
16641672 if ( entries . length > 0 ) out . contributorBlacklist = entries ;
16651673 }
16661674 // Per-contributor open PR/issue caps (#2270): discrete counts, not scores — reuse the same positive-integer
1667- // normalizer as contentLane.maxAppendedEntries so a fractional/non-positive typo is dropped with a warning
1668- // instead of configuring a nonsensical cap. UNLIKE contributorBlacklist above, an explicit yml `null` here is
1675+ // shape as contentLane.maxAppendedEntries so a fractional/non-positive typo is dropped with a warning
1676+ // instead of configuring a nonsensical cap. Valid counts clamp to the fixed live-verification budget. UNLIKE
1677+ // contributorBlacklist above, an explicit yml `null` here is
16691678 // load-bearing (not the same as omitting the key): the documented `yml > DB > null` precedence means a
16701679 // maintainer must be able to force a DB-configured cap back to "no cap" via `.gittensory.yml` without deleting
16711680 // the DB row. `normalizeOptionalPositiveInteger` collapses "absent" and "null" to the same silent `null`
@@ -1675,13 +1684,13 @@ function parseSettingsOverride(value: JsonValue | undefined, warnings: string[])
16751684 if ( r . contributorOpenPrCap === null ) {
16761685 out . contributorOpenPrCap = null ;
16771686 } else {
1678- const contributorOpenPrCap = normalizeOptionalPositiveInteger ( r . contributorOpenPrCap , "settings.contributorOpenPrCap" , warnings ) ;
1687+ const contributorOpenPrCap = normalizeOptionalContributorOpenItemCap ( r . contributorOpenPrCap , "settings.contributorOpenPrCap" , warnings ) ;
16791688 if ( contributorOpenPrCap !== null ) out . contributorOpenPrCap = contributorOpenPrCap ;
16801689 }
16811690 if ( r . contributorOpenIssueCap === null ) {
16821691 out . contributorOpenIssueCap = null ;
16831692 } else {
1684- const contributorOpenIssueCap = normalizeOptionalPositiveInteger ( r . contributorOpenIssueCap , "settings.contributorOpenIssueCap" , warnings ) ;
1693+ const contributorOpenIssueCap = normalizeOptionalContributorOpenItemCap ( r . contributorOpenIssueCap , "settings.contributorOpenIssueCap" , warnings ) ;
16851694 if ( contributorOpenIssueCap !== null ) out . contributorOpenIssueCap = contributorOpenIssueCap ;
16861695 }
16871696 // #label-scoping: same load-bearing-null idiom as blacklistLabel above.
0 commit comments