Skip to content

Commit 83c9508

Browse files
committed
test(P9): document and guard Java Kotlin boundaries
1 parent 2a73cb8 commit 83c9508

4 files changed

Lines changed: 54 additions & 0 deletions

File tree

CONTRIBUTING.md

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# Contributing
2+
3+
MahjongPaper currently mixes Java and Kotlin deliberately. Keep the split visible when adding production code.
4+
5+
## Java/Kotlin Boundary
6+
7+
Use Java by default for Paper/Bukkit integration, plugin bootstrap, commands, table/session orchestration, rendering, UI, database, runtime scheduling, CraftEngine compatibility, configuration, i18n, and metrics.
8+
9+
Use Kotlin only where it keeps rule or data-heavy code clearer:
10+
11+
- pure Riichi rule logic, scoring helpers, and state models under `src/main/kotlin/top/ellan/mahjong/riichi`
12+
- GB native request/response DTOs under `src/main/kotlin/top/ellan/mahjong/gb/jni`
13+
- future pure algorithm or serialization model packages, after updating `ArchitectureBoundaryTest` and this document in the same change
14+
15+
Production Kotlin should not import Bukkit, Paper, Kyori UI/presentation APIs, CraftEngine compatibility classes, plugin bootstrap classes, database services, runtime schedulers, or table/session coordinator internals. Tests may use Kotlin freely.
16+
17+
## Package Boundaries
18+
19+
Keep these dependency directions in mind:
20+
21+
- `bootstrap` wires services and entry points; avoid reaching into command/render/ui internals.
22+
- `command` talks to the public table and service surface through `MahjongCommandContext`.
23+
- `table` owns session orchestration and may call render/UI services through narrow interfaces.
24+
- `render` owns display entity specs/layout and must stay free of `table` and `bootstrap`.
25+
- `riichi` and `gb` should stay rules-focused and free of platform/presentation dependencies.
26+
- `compat` hides CraftEngine and Paper reflection details behind service facades.
27+
28+
If a new feature needs to cross one of these boundaries, prefer introducing a small DTO or interface near the caller instead of importing a concrete internal class from another layer.
29+
30+
## Build Logic
31+
32+
Keep root `build.gradle.kts` focused on task wiring. Resource generation, native helper logic, and bundle generation belong in `buildSrc`.

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
55
Chinese documentation: [README.zh-CN.md](./README.zh-CN.md)
66
Chinese gameplay and operations wiki: [docs/wiki.zh-CN.md](./docs/wiki.zh-CN.md)
7+
Contributor notes: [CONTRIBUTING.md](./CONTRIBUTING.md)
78

89
`MahjongPaper` is a Paper plugin rewrite of `MahjongCraft` built around:
910

README.zh-CN.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
> 本项目完全由 AI 创作。
44
55
英文说明见 [README.md](./README.md)
6+
贡献与代码边界说明见 [CONTRIBUTING.md](./CONTRIBUTING.md)
67

78
`MahjongPaper``MahjongCraft` 的 Paper 插件重写版本,当前主要基于:
89

src/test/kotlin/top/ellan/mahjong/architecture/ArchitectureBoundaryTest.kt

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,22 @@ class ArchitectureBoundaryTest {
120120
)
121121
}
122122

123+
@Test
124+
fun `production kotlin stays in rules and native model packages`() {
125+
val violations = sourceFiles("src/main/kotlin")
126+
.filter { file ->
127+
allowedProductionKotlinRoots.none { root ->
128+
file.normalize().startsWith(root)
129+
}
130+
}
131+
.map { projectRoot.relativize(it) }
132+
133+
assertTrue(
134+
violations.isEmpty(),
135+
"Production Kotlin should stay in rule or serialization-model packages; update CONTRIBUTING.md and this allowlist for deliberate new roots:\n${violations.joinToString("\n")}"
136+
)
137+
}
138+
123139
private companion object {
124140
val projectRoot: Path = Path.of("").toAbsolutePath()
125141
val forbiddenRuleImports = listOf(
@@ -153,6 +169,10 @@ class ArchitectureBoundaryTest {
153169
"import top.ellan.mahjong.table.core.MahjongTableSession",
154170
"import top.ellan.mahjong.table.core.TableFinalStanding"
155171
)
172+
val allowedProductionKotlinRoots = listOf(
173+
"src/main/kotlin/top/ellan/mahjong/riichi",
174+
"src/main/kotlin/top/ellan/mahjong/gb/jni"
175+
).map { projectRoot.resolve(it).normalize() }
156176

157177
fun sourceFiles(vararg roots: String): List<Path> = roots.flatMap { root ->
158178
val rootPath = projectRoot.resolve(root)

0 commit comments

Comments
 (0)