@@ -136,7 +136,47 @@ class ArchitectureBoundaryTest {
136136 )
137137 }
138138
139+ @Test
140+ fun `known large orchestration files stay under size budgets` () {
141+ val violations = lineBudgets.mapNotNull { budget ->
142+ val file = projectRoot.resolve(budget.path)
143+ val lineCount = Files .readAllLines(file).size
144+ if (lineCount <= budget.maxLines) {
145+ null
146+ } else {
147+ " ${budget.path} : $lineCount lines exceeds budget ${budget.maxLines} "
148+ }
149+ }
150+
151+ assertTrue(
152+ violations.isEmpty(),
153+ " Large files should shrink or stay flat; raise a budget only with an accompanying split plan:\n ${violations.joinToString(" \n " )} "
154+ )
155+ }
156+
157+ @Test
158+ fun `known broad public surfaces stay under method budgets` () {
159+ val violations = publicMethodBudgets.mapNotNull { budget ->
160+ val file = projectRoot.resolve(budget.path)
161+ val methodCount = Files .readString(file).lineSequence()
162+ .count { line -> publicMemberPattern.matches(line) }
163+ if (methodCount <= budget.maxPublicMembers) {
164+ null
165+ } else {
166+ " ${budget.path} : $methodCount public members exceeds budget ${budget.maxPublicMembers} "
167+ }
168+ }
169+
170+ assertTrue(
171+ violations.isEmpty(),
172+ " Broad public surfaces should shrink or stay flat; prefer narrow interfaces before adding more public members:\n ${violations.joinToString(" \n " )} "
173+ )
174+ }
175+
139176 private companion object {
177+ data class LineBudget (val path : String , val maxLines : Int )
178+ data class PublicMethodBudget (val path : String , val maxPublicMembers : Int )
179+
140180 val projectRoot: Path = Path .of(" " ).toAbsolutePath()
141181 val forbiddenRuleImports = listOf (
142182 " import org.bukkit." ,
@@ -173,6 +213,18 @@ class ArchitectureBoundaryTest {
173213 " src/main/kotlin/top/ellan/mahjong/riichi" ,
174214 " src/main/kotlin/top/ellan/mahjong/gb/jni"
175215 ).map { projectRoot.resolve(it).normalize() }
216+ val lineBudgets = listOf (
217+ LineBudget (" build.gradle.kts" , 350 ),
218+ LineBudget (" src/main/java/top/ellan/mahjong/table/core/MahjongTableSession.java" , 1650 ),
219+ LineBudget (" src/main/java/top/ellan/mahjong/table/core/MahjongTableManager.java" , 1000 ),
220+ LineBudget (" src/main/java/top/ellan/mahjong/render/scene/TableRenderer.java" , 2150 )
221+ )
222+ val publicMethodBudgets = listOf (
223+ PublicMethodBudget (" src/main/java/top/ellan/mahjong/table/core/MahjongTableSession.java" , 230 ),
224+ PublicMethodBudget (" src/main/java/top/ellan/mahjong/table/core/MahjongTableManager.java" , 50 ),
225+ PublicMethodBudget (" src/main/java/top/ellan/mahjong/render/scene/TableRenderer.java" , 40 )
226+ )
227+ val publicMemberPattern = Regex (""" ^\s+public (?!class|interface|enum|record).*""" )
176228
177229 fun sourceFiles (vararg roots : String ): List <Path > = roots.flatMap { root ->
178230 val rootPath = projectRoot.resolve(root)
0 commit comments