Skip to content

Commit b879290

Browse files
committed
fix: issue weighting and classification
1 parent 22b842d commit b879290

1 file changed

Lines changed: 20 additions & 7 deletions

File tree

src/sources/issues.ts

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -101,18 +101,30 @@ const DOCS_LABELS = new Set([
101101
'typo',
102102
])
103103

104+
/**
105+
* Check if a label contains any keyword from a set.
106+
* Handles emoji-prefixed labels like ":sparkles: feature request" or ":lady_beetle: bug".
107+
*/
108+
function labelMatchesAny(label: string, keywords: Set<string>): boolean {
109+
for (const keyword of keywords) {
110+
if (label === keyword || label.includes(keyword))
111+
return true
112+
}
113+
return false
114+
}
115+
104116
/**
105117
* Classify an issue by its labels into a type useful for skill generation
106118
*/
107119
export function classifyIssue(labels: string[]): IssueType {
108120
const lower = labels.map(l => l.toLowerCase())
109-
if (lower.some(l => BUG_LABELS.has(l)))
121+
if (lower.some(l => labelMatchesAny(l, BUG_LABELS)))
110122
return 'bug'
111-
if (lower.some(l => QUESTION_LABELS.has(l)))
123+
if (lower.some(l => labelMatchesAny(l, QUESTION_LABELS)))
112124
return 'question'
113-
if (lower.some(l => DOCS_LABELS.has(l)))
125+
if (lower.some(l => labelMatchesAny(l, DOCS_LABELS)))
114126
return 'docs'
115-
if (lower.some(l => FEATURE_LABELS.has(l)))
127+
if (lower.some(l => labelMatchesAny(l, FEATURE_LABELS)))
116128
return 'feature'
117129
return 'other'
118130
}
@@ -122,7 +134,7 @@ export function classifyIssue(labels: string[]): IssueType {
122134
*/
123135
function isNoiseIssue(issue: { labels: string[], title: string, body: string }): boolean {
124136
const lower = issue.labels.map(l => l.toLowerCase())
125-
if (lower.some(l => NOISE_LABELS.has(l)))
137+
if (lower.some(l => labelMatchesAny(l, NOISE_LABELS)))
126138
return true
127139
// Tracking/umbrella issues — low signal for skill generation
128140
if (issue.title.startsWith('☂️') || issue.title.startsWith('[META]') || issue.title.startsWith('[Tracking]'))
@@ -152,12 +164,13 @@ export function isNonTechnical(issue: { body: string, title: string, reactions:
152164

153165
/**
154166
* Freshness-weighted score: reactions * decay(age_in_years)
155-
* A 2024 issue with 50 reactions outranks a 2014 issue with 500.
167+
* Steep decay so recent issues dominate over old high-reaction ones.
168+
* At 0.6: 1yr=0.63x, 2yr=0.45x, 4yr=0.29x, 6yr=0.22x
156169
*/
157170
export function freshnessScore(reactions: number, createdAt: string): number {
158171
const ageMs = Date.now() - new Date(createdAt).getTime()
159172
const ageYears = ageMs / (365.25 * 24 * 60 * 60 * 1000)
160-
return reactions * (1 / (1 + ageYears * 0.3))
173+
return reactions * (1 / (1 + ageYears * 0.6))
161174
}
162175

163176
/**

0 commit comments

Comments
 (0)