@@ -27,20 +27,33 @@ export function buildCandidateReview(
2727 registry ,
2828 excludedLogins ,
2929 fingerprintKey ,
30- generatedAt = new Date ( ) . toISOString ( )
30+ generatedAt = new Date ( ) . toISOString ( ) ,
31+ usageRecords = [ ]
3132) {
3233 validateRegistry ( registry ) ;
3334 validateRegistryKey ( registry , fingerprintKey ) ;
3435 assertIsoDate ( generatedAt ) ;
3536 const excluded = new Set ( validateExcludedLogins ( excludedLogins ) ) ;
37+ const usageByInstallation = new Map ( ) ;
38+ for ( const record of usageRecords ) {
39+ const valid = validateInstallationUsageRecord ( record ) ;
40+ if ( usageByInstallation . has ( valid . installationId ) ) {
41+ throw new Error ( 'Duplicate installation usage record' ) ;
42+ }
43+ usageByInstallation . set ( valid . installationId , valid . successfulFeedbackCount ) ;
44+ }
3645 const decided = registry . entries . map ( entry => Buffer . from ( entry . accountFingerprint , 'hex' ) ) ;
3746 const eligible = records
3847 . map ( validateInstallationRecord )
39- . map ( record => ( {
40- account : record . account ,
41- installedAt : record . installedAt ,
42- accountFingerprint : fingerprintAccount ( record . account . login , fingerprintKey ) ,
43- } ) )
48+ . map ( record => {
49+ const successfulFeedbackCount = usageByInstallation . get ( record . installationId ) ;
50+ return {
51+ account : record . account ,
52+ installedAt : record . installedAt ,
53+ accountFingerprint : fingerprintAccount ( record . account . login , fingerprintKey ) ,
54+ ...( successfulFeedbackCount === undefined ? { } : { successfulFeedbackCount } ) ,
55+ } ;
56+ } )
4457 . filter (
4558 record =>
4659 ! excluded . has ( record . account . login . toLocaleLowerCase ( 'en-US' ) ) &&
@@ -56,13 +69,26 @@ export function buildCandidateReview(
5669 candidatesByAccount . set ( candidate . accountFingerprint , candidate ) ;
5770 }
5871 }
59- const candidates = [ ...candidatesByAccount . values ( ) ] . sort ( ( a , b ) =>
60- a . installedAt . localeCompare ( b . installedAt )
61- ) ;
72+ const candidates = [ ...candidatesByAccount . values ( ) ] . sort ( compareCandidatePriority ) ;
6273
6374 return { schemaVersion : 1 , generatedAt, candidates } ;
6475}
6576
77+ function validateInstallationUsageRecord ( record ) {
78+ if (
79+ ! isObject ( record ) ||
80+ ! hasExactKeys ( record , [ 'schemaVersion' , 'installationId' , 'successfulFeedbackCount' ] ) ||
81+ record . schemaVersion !== 1
82+ ) {
83+ throw new Error ( 'Invalid installation usage record' ) ;
84+ }
85+ assertPositiveInteger ( record . installationId ) ;
86+ if ( ! Number . isSafeInteger ( record . successfulFeedbackCount ) || record . successfulFeedbackCount < 0 ) {
87+ throw new Error ( 'Invalid installation usage record' ) ;
88+ }
89+ return record ;
90+ }
91+
6692export function buildApprovedExport ( registry , generatedAt = new Date ( ) . toISOString ( ) ) {
6793 validateRegistry ( registry ) ;
6894 assertIsoDate ( generatedAt ) ;
@@ -193,6 +219,16 @@ function validateInstallationRecord(record) {
193219 return record ;
194220}
195221
222+ function compareCandidatePriority ( a , b ) {
223+ const aKnown = Number . isSafeInteger ( a . successfulFeedbackCount ) ;
224+ const bKnown = Number . isSafeInteger ( b . successfulFeedbackCount ) ;
225+ if ( aKnown !== bKnown ) return aKnown ? - 1 : 1 ;
226+ if ( aKnown && a . successfulFeedbackCount !== b . successfulFeedbackCount ) {
227+ return b . successfulFeedbackCount - a . successfulFeedbackCount ;
228+ }
229+ return b . installedAt . localeCompare ( a . installedAt ) ;
230+ }
231+
196232function normalizeGitHubLogin ( value ) {
197233 if ( typeof value !== 'string' || ! / ^ [ A - Z a - z 0 - 9 ] (?: [ A - Z a - z 0 - 9 - ] { 0 , 98 } [ A - Z a - z 0 - 9 ] ) ? $ / . test ( value ) ) {
198234 throw new Error ( 'Invalid GitHub account' ) ;
0 commit comments