@@ -24,7 +24,7 @@ function clip(s, max) {
2424 return s . length <= max ? s : s . slice ( 0 , max ) + `\n\n[truncated ${ s . length - max } chars]` ;
2525}
2626
27- // ---------- 0) 규칙 로딩 ----------
27+ // ---------- 0) Rule Loading ----------
2828const rulesPath = '.github/models/pr-desc/rules.json' ;
2929let rules = { modules : [ ] , fallbackModule : 'Misc' } ;
3030if ( existsSync ( rulesPath ) ) {
@@ -57,7 +57,7 @@ function bumpToken(token, weight = 1) {
5757 interestTokens . set ( norm , ( interestTokens . get ( norm ) || 0 ) + weight ) ;
5858}
5959
60- // ---------- 1) Overview / Modules 원문 문서 ----------
60+ // ---------- 1) Overview / Modules Source Documents ----------
6161const ctxRoot = '.github/models/pr-desc/context' ;
6262let overview = '' ;
6363const overviewPath = join ( ctxRoot , 'overview.md' ) ;
@@ -74,8 +74,8 @@ const commitSubjects = sh(`git log --pretty=%s ${base}..${head}`).split('\n').fi
7474const commitBodiesRaw = sh ( `git log --pretty=%B ${ base } ..${ head } ` ) ;
7575const commitBodies = commitBodiesRaw . split ( '\n\n' ) . map ( s => s . trim ( ) ) . filter ( Boolean ) . slice ( 0 , 10 ) . map ( s => clip ( s , 800 ) ) ;
7676
77- // name-status 파싱 (status, path[, path2])
78- // M A D R100 old -> new 형태는 탭으로 분리
77+ // name-status parsing (status, path[, path2])
78+ // M A D R100 old -> new format is separated by tabs
7979const changedFiles = [ ] ;
8080if ( nameStatusRaw ) {
8181 for ( const line of nameStatusRaw . split ( '\n' ) ) {
@@ -96,7 +96,7 @@ if (nameStatusRaw) {
9696 }
9797}
9898
99- // numstat 파싱 (added removed path[, path2])
99+ // numstat parsing (added removed path[, path2])
100100const churnMap = new Map ( ) ; // key: path(to), value: {added, removed}
101101if ( numstatRaw ) {
102102 for ( const line of numstatRaw . split ( '\n' ) ) {
@@ -105,7 +105,7 @@ if (numstatRaw) {
105105 if ( parts . length < 3 ) continue ;
106106 const added = parts [ 0 ] === '-' ? 0 : parseInt ( parts [ 0 ] , 10 ) || 0 ;
107107 const removed = parts [ 1 ] === '-' ? 0 : parseInt ( parts [ 1 ] , 10 ) || 0 ;
108- const pth = parts [ 2 ] . includes ( '\t' ) ? parts [ 3 ] : parts [ 2 ] ; // rename의 경우 path\tpath2
108+ const pth = parts [ 2 ] . includes ( '\t' ) ? parts [ 3 ] : parts [ 2 ] ; // for rename path\tpath2
109109 const path = parts [ 3 ] || parts [ 2 ] ;
110110 churnMap . set ( path , { added, removed } ) ;
111111 }
@@ -163,15 +163,15 @@ modulesDoc = clip(modulesDoc, 24000);
163163
164164
165165function statusWeight ( status ) {
166- // Rxxx, Cxxx 등은 리네임/복사로 간주
166+ // Rxxx, Cxxx, etc. are considered renames/copies
167167 if ( status . startsWith ( 'R' ) || status . startsWith ( 'C' ) ) return 2.0 ;
168168 if ( status === 'D' ) return 2.5 ;
169169 if ( status === 'A' ) return 1.5 ;
170- // 기본 M
170+ // Default M
171171 return 1.0 ;
172172}
173173
174- // ---------- 3) 모듈 그룹화 + 영향도 산출 ----------
174+ // ---------- 3) Module Grouping + Impact Calculation ----------
175175const modulesAgg = new Map ( ) ; // name -> { files:[], score:0, weight, counts, lines }
176176const unmatched = [ ] ;
177177for ( const f of changedFiles ) {
@@ -200,12 +200,12 @@ for (const f of changedFiles) {
200200 if ( f . status . startsWith ( 'R' ) || f . status . startsWith ( 'C' ) ) agg . hasRename = true ;
201201 if ( f . status === 'D' ) agg . hasDelete = true ;
202202
203- // 점수 = (모듈 가중치 ) * (상태 가중치 ) * (규모 가중치 )
204- const sizeFactor = Math . log10 ( 1 + churn . added + churn . removed + 1 ) ; // 0~대략 4
203+ // score = (module weight ) * (status weight ) * (size weight )
204+ const sizeFactor = Math . log10 ( 1 + churn . added + churn . removed + 1 ) ; // 0~approximately 4
205205 agg . score += cls . weight * statusWeight ( f . status ) * ( 1 + sizeFactor ) ;
206206}
207207
208- // 모듈별 최종 영향도 레벨 결정
208+ // Final impact level determination by module
209209function levelFromScore ( s ) {
210210 if ( s >= 30 ) return 'High' ;
211211 if ( s >= 12 ) return 'Medium' ;
@@ -241,7 +241,7 @@ const apiSurfaceChanges = changedFiles.filter(f => headerOrConfig(f.path)).map(f
241241const testFiles = changedFiles . filter ( f => / ( ^ | \/ ) ( t e s t | t e s t s | t e s t i n g | s p e c ) \b | _ t e s t \. ( c c | c p p | c | p y | j s | t s ) $ / . test ( f . path ) ) . map ( f => f . path ) ;
242242const concurrencySensitive = changedFiles . filter ( f => / ( t h r e a d | m u t e x | a t o m i c | l o c k | c o n c u r r e n t | p a r a l l e l ) / i. test ( f . path ) ) . map ( f => f . path ) ;
243243
244- // ---------- 4) Diff/Commits 텍스트 ----------
244+ // ---------- 4) Diff/Commits Text ----------
245245const diff = clip ( `### name-status\n${ nameStatusRaw } \n\n### stat\n${ statRaw } ` , 8000 ) ;
246246
247247const buckets = { feat :0 , fix :0 , refactor :0 , test :0 , docs :0 , chore :0 , other :0 } ;
@@ -261,7 +261,7 @@ const commits =
261261 ( commitSubjects . length ? `\n\nSamples:\n- ${ commitSubjects . slice ( 0 , 5 ) . join ( '\n- ' ) } ` : '' ) +
262262 ( commitBodies . length ? `\n\nCommit bodies (top, clipped):\n- ${ commitBodies . join ( '\n- ' ) } ` : '' ) ;
263263
264- // ---------- 5) 모듈 임팩트 요약 텍스트 (모델 힌트용 ) ----------
264+ // ---------- 5) Module Impact Summary Text (Model Hint ) ----------
265265let moduleImpactSummary = '' ;
266266if ( Object . keys ( moduleImpact ) . length ) {
267267 // 영향도 높은 순으로 상위 5개
@@ -273,7 +273,7 @@ if (Object.keys(moduleImpact).length) {
273273 ) . join ( '\n' ) ;
274274}
275275
276- // ---------- 6) 출력 ----------
276+ // ---------- 6) Output ----------
277277const out = {
278278 overview : clip ( overview , 8000 ) ,
279279 modules : modulesDoc ,
0 commit comments