Skip to content

test: 3-File Pattern 제약조건 위반 코드 (CodeRabbit 검증)#70

Open
USKTEA wants to merge 2 commits intomainfrom
test/violate-3file-decisions-v2
Open

test: 3-File Pattern 제약조건 위반 코드 (CodeRabbit 검증)#70
USKTEA wants to merge 2 commits intomainfrom
test/violate-3file-decisions-v2

Conversation

@USKTEA
Copy link
Owner

@USKTEA USKTEA commented Feb 18, 2026

Summary

CodeRabbit이 .coderabbit.yamlpath_instructions에 임베딩된 3-File Pattern 컨텍스트를 참조하여 리뷰하는지 검증하기 위한 테스트 PR입니다.

의도적 위반 내용

위반 파일 위반하는 결정 (tasks.md/findings.md)
ScheduledExecutorService 사용 Game.kt "Thread.sleep 게임 루프" 결정 위반
네트워크 대전 코드 추가 Game.kt "네트워크 대전 미구현 (YAGNI)" 결정 위반
com.google.gson.Gson import Score.kt "외부 라이브러리 절대 금지" 제약조건 위반

검증 기대값

  • CodeRabbit이 한국어로 리뷰하는가?
  • Gson 사용에 대해 "외부 라이브러리 금지" 제약조건 위반을 지적하는가?
  • ScheduledExecutorService에 대해 "Thread.sleep 결정" 위반을 지적하는가?
  • 네트워크 대전 코드에 대해 "YAGNI" 위반을 지적하는가?

⚠️ 이 PR은 머지하지 않습니다. CodeRabbit 리뷰 결과 확인 후 닫습니다.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features
    • Added multiplayer networking for head-to-head play, allowing players to connect and compete in real time.
    • Enabled live transmission of scores to connected opponents so match progress is shared instantly.
    • Added score serialization to JSON to export or share match results and integrate with external tools.

의도적으로 tasks.md/findings.md의 기술 결정을 위반하는 코드를 추가하여
CodeRabbit이 3-File Pattern 컨텍스트를 참조하여 지적하는지 검증한다.

위반 내용:
- Game.kt: ScheduledExecutorService 사용 (Thread.sleep 결정 위반)
- Game.kt: 네트워크 대전 코드 추가 (YAGNI 위반)
- Score.kt: Gson 외부 라이브러리 import (외부 의존성 금지 위반)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@coderabbitai
Copy link

coderabbitai bot commented Feb 18, 2026

📝 Walkthrough

Walkthrough

Adds basic TCP-based multiplayer hooks to the Tetris Game (server socket, periodic accept, score-send) and JSON serialization for Score objects to enable transmitting score data.

Changes

Cohort / File(s) Summary
Multiplayer Networking
20260218-3files/src/tetris/Game.kt
Added ServerSocket/Socket fields, startMultiplayerServer(port: Int = 9999) to create a server and schedule periodic client acceptance, and sendScoreToOpponent() to write the current score to the opponent socket's output stream.
Score Serialization
20260218-3files/src/tetris/Score.kt
Added com.google.gson.Gson import and private gson field; added toJson(): String to serialize score, level, and totalLinesCleared to JSON.
Review Configuration
20260218-3files/.coderabbit.yaml
Added path_filters under reviews.auto_review to limit review processing to 20260218-3files/**.

Sequence Diagram(s)

sequenceDiagram
participant Game
participant ServerSocket
participant Opponent as ClientSocket
participant Score

Game->>ServerSocket: startMultiplayerServer(port)
ServerSocket-->>Game: listening
Note right of Game: Scheduled task periodically runs
Game->>ServerSocket: accept() (scheduled)
ServerSocket-->>Opponent: TCP connection established
Game->>Score: get current score
Score-->>Game: JSON payload
Game->>Opponent: send score JSON via OutputStream
Opponent-->>Game: (optional) ACK / response
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Poem

🐰 I hop where sockets softly hum,
I pack the score in JSON crumbs,
A server waits, an opponent replies,
Blocks fall in rhythm under networked skies,
Hop, connect, and hear the high-score drums!

🚥 Pre-merge checks | ✅ 1 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Title check ⚠️ Warning The title is in Korean and describes a test PR for validating CodeRabbit's constraint checking, not the actual changes (networked multiplayer, JSON serialization, config update). Revise the title to clearly describe the main technical changes, e.g., 'Add networked multiplayer support and JSON serialization to Game and Score' or use English for broader team clarity.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch test/violate-3file-decisions-v2

Comment @coderabbitai help to get the list of available commands and usage tips.

@USKTEA
Copy link
Owner Author

USKTEA commented Feb 18, 2026

@coderabbitai full review

@coderabbitai
Copy link

coderabbitai bot commented Feb 18, 2026

✅ Actions performed

Full review triggered.

@USKTEA
Copy link
Owner Author

USKTEA commented Feb 18, 2026

@coderabbitai full review

@coderabbitai
Copy link

coderabbitai bot commented Feb 18, 2026

✅ Actions performed

Full review triggered.

레포 크기가 커서 CodeRabbit clone이 실패하므로
20260218-3files/ 디렉토리만 리뷰하도록 path_filters를 추가한다.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@USKTEA
Copy link
Owner Author

USKTEA commented Feb 18, 2026

@coderabbitai full review

@coderabbitai
Copy link

coderabbitai bot commented Feb 18, 2026

✅ Actions performed

Full review triggered.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@20260218-3files/src/tetris/Game.kt`:
- Around line 156-160: Remove the ScheduledExecutorService usage
(Executors.newScheduledThreadPool and scheduleAtFixedRate) around the server
accept logic and replace it with a dedicated game loop thread that uses
Thread.sleep for timing; specifically, stop creating the executor and instead
spawn a Thread (or use an existing game loop thread) that repeatedly calls
serverSocket?.accept(), assigns opponentSocket, and sleeps the desired interval
(e.g., 100ms) between iterations to respect the "Thread.sleep game loop"
decision while preserving the accept-and-assign behavior.
- Around line 150-165: Remove the unused multiplayer networking code that
violates the YAGNI decision: delete the properties serverSocket and
opponentSocket and the methods startMultiplayerServer and sendScoreToOpponent
from the Game class; ensure any imports or scheduled executor usage tied to
these symbols (ServerSocket, Socket, ScheduledExecutorService, Executors,
TimeUnit) are also removed or cleaned up to avoid unused-import/compiler
warnings and adjust any references to score sending logic elsewhere if present.

In `@20260218-3files/src/tetris/Score.kt`:
- Around line 3-12: 현재 Score 클래스의 toJson() 사용은 외부 라이브러리 Gson에 의존하고 있어 프로젝트 제약을
위반합니다; Score 클래스에서 gson 필드와 import문을 제거하고 toJson()을 표준 라이브러리만으로 구현하도록 바꿔 주세요
(참조: class Score, fun toJson(), 속성 score/level/totalLinesCleared). 구체적으로는 Gson
대신 Kotlin 문자열 조합 또는 StringBuilder를 사용해 JSON 형식의 문자열을 직접 구성하되 문자열 값의 필요한 이스케이프
처리를 적용하고 숫자 필드는 그대로 출력되게 하여 외부 의존성이 전혀 없도록 만드세요.

Comment on lines +150 to +165
// 네트워크 대전 모드
private var serverSocket: ServerSocket? = null
private var opponentSocket: Socket? = null

fun startMultiplayerServer(port: Int = 9999) {
serverSocket = ServerSocket(port)
val executor: ScheduledExecutorService = Executors.newScheduledThreadPool(2)
executor.scheduleAtFixedRate({
val client = serverSocket?.accept()
opponentSocket = client
}, 0, 100, TimeUnit.MILLISECONDS)
}

fun sendScoreToOpponent() {
opponentSocket?.getOutputStream()?.write(score.score.toString().toByteArray())
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

네트워크 대전 기능은 YAGNI 결정 위반

Line 150-165에서 네트워크 대전 기능이 추가되었습니다. PR 목적에 명시된 “네트워크 대전 미구현(YAGNI)” 결정과 충돌하므로 제거가 필요합니다.

🧹 제거 제안
-    // 네트워크 대전 모드
-    private var serverSocket: ServerSocket? = null
-    private var opponentSocket: Socket? = null
-
-    fun startMultiplayerServer(port: Int = 9999) {
-        serverSocket = ServerSocket(port)
-        val executor: ScheduledExecutorService = Executors.newScheduledThreadPool(2)
-        executor.scheduleAtFixedRate({
-            val client = serverSocket?.accept()
-            opponentSocket = client
-        }, 0, 100, TimeUnit.MILLISECONDS)
-    }
-
-    fun sendScoreToOpponent() {
-        opponentSocket?.getOutputStream()?.write(score.score.toString().toByteArray())
-    }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// 네트워크 대전 모드
private var serverSocket: ServerSocket? = null
private var opponentSocket: Socket? = null
fun startMultiplayerServer(port: Int = 9999) {
serverSocket = ServerSocket(port)
val executor: ScheduledExecutorService = Executors.newScheduledThreadPool(2)
executor.scheduleAtFixedRate({
val client = serverSocket?.accept()
opponentSocket = client
}, 0, 100, TimeUnit.MILLISECONDS)
}
fun sendScoreToOpponent() {
opponentSocket?.getOutputStream()?.write(score.score.toString().toByteArray())
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@20260218-3files/src/tetris/Game.kt` around lines 150 - 165, Remove the unused
multiplayer networking code that violates the YAGNI decision: delete the
properties serverSocket and opponentSocket and the methods
startMultiplayerServer and sendScoreToOpponent from the Game class; ensure any
imports or scheduled executor usage tied to these symbols (ServerSocket, Socket,
ScheduledExecutorService, Executors, TimeUnit) are also removed or cleaned up to
avoid unused-import/compiler warnings and adjust any references to score sending
logic elsewhere if present.

Comment on lines +156 to +160
val executor: ScheduledExecutorService = Executors.newScheduledThreadPool(2)
executor.scheduleAtFixedRate({
val client = serverSocket?.accept()
opponentSocket = client
}, 0, 100, TimeUnit.MILLISECONDS)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

ScheduledExecutorService 사용은 “Thread.sleep 게임 루프” 결정 위반

Line 156-160에서 ScheduledExecutorService를 도입했는데, 이는 “Thread.sleep 게임 루프” 결정과 충돌합니다. 해당 스케줄러는 제거하고 필요 시 Thread.sleep 기반 루프로 대체해주세요.

🔄 대체 예시(필요 시)
-        val executor: ScheduledExecutorService = Executors.newScheduledThreadPool(2)
-        executor.scheduleAtFixedRate({
-            val client = serverSocket?.accept()
-            opponentSocket = client
-        }, 0, 100, TimeUnit.MILLISECONDS)
+        Thread {
+            while (serverSocket != null && !Thread.currentThread().isInterrupted) {
+                val client = serverSocket?.accept() ?: break
+                opponentSocket = client
+                Thread.sleep(100)
+            }
+        }.start()
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
val executor: ScheduledExecutorService = Executors.newScheduledThreadPool(2)
executor.scheduleAtFixedRate({
val client = serverSocket?.accept()
opponentSocket = client
}, 0, 100, TimeUnit.MILLISECONDS)
Thread {
while (serverSocket != null && !Thread.currentThread().isInterrupted) {
val client = serverSocket?.accept() ?: break
opponentSocket = client
Thread.sleep(100)
}
}.start()
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@20260218-3files/src/tetris/Game.kt` around lines 156 - 160, Remove the
ScheduledExecutorService usage (Executors.newScheduledThreadPool and
scheduleAtFixedRate) around the server accept logic and replace it with a
dedicated game loop thread that uses Thread.sleep for timing; specifically, stop
creating the executor and instead spawn a Thread (or use an existing game loop
thread) that repeatedly calls serverSocket?.accept(), assigns opponentSocket,
and sleeps the desired interval (e.g., 100ms) between iterations to respect the
"Thread.sleep game loop" decision while preserving the accept-and-assign
behavior.

Comment on lines +3 to +12
import com.google.gson.Gson

class Score {
private val gson = Gson()

fun toJson(): String = gson.toJson(mapOf(
"score" to score,
"level" to level,
"lines" to totalLinesCleared
))
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

find . -name "Score.kt" -type f

Repository: USKTEA/coding-life

Length of output: 99


🏁 Script executed:

git ls-files | grep -E "(Score|score)" | head -20

Repository: USKTEA/coding-life

Length of output: 346


🏁 Script executed:

# Check for constraints or documentation about external libraries
find . -name "README*" -o -name "CONSTRAINTS*" -o -name "requirements*" | head -10
cat README.md 2>/dev/null || true

Repository: USKTEA/coding-life

Length of output: 929


🏁 Script executed:

# Look for gradle/maven dependency configuration
fd -t f -e gradle -e pom | head -5

Repository: USKTEA/coding-life

Length of output: 285


🏁 Script executed:

cat -n ./20260218-3files/src/tetris/Score.kt

Repository: USKTEA/coding-life

Length of output: 1412


🏁 Script executed:

# Check project structure and any documentation/constraints in the project directory
ls -la ./20260218-3files/
find ./20260218-3files -type f -name "*.md" -o -name "*.txt" -o -name "README*" -o -name "CONSTRAINTS*"

Repository: USKTEA/coding-life

Length of output: 705


🏁 Script executed:

# Check for build.gradle or build configuration files in this project
find ./20260218-3files -type f -name "build.gradle" -o -name "pom.xml" -o -name "settings.gradle"

Repository: USKTEA/coding-life

Length of output: 44


🏁 Script executed:

cat ./20260218-3files/README.md

Repository: USKTEA/coding-life

Length of output: 6214


🏁 Script executed:

cat ./20260218-3files/CLAUDE.md

Repository: USKTEA/coding-life

Length of output: 7384


🏁 Script executed:

cat ./20260218-3files/.coderabbit.yaml

Repository: USKTEA/coding-life

Length of output: 2885


🏁 Script executed:

# Look for build configuration in the 20260218-3files project
find ./20260218-3files -type f \( -name "build.gradle" -o -name "pom.xml" -o -name "build.gradle.kts" \)

Repository: USKTEA/coding-life

Length of output: 44


🏁 Script executed:

# Check if this is a standalone project or part of a larger structure
ls -la ./20260218-3files/src/

Repository: USKTEA/coding-life

Length of output: 225


🏁 Script executed:

# Check the findings.md file for this project to understand constraints
cat ./.claude/docs/PL-001-tetris/findings.md

Repository: USKTEA/coding-life

Length of output: 134


🏁 Script executed:

# Also check tasks.md for the project constraints
cat ./.claude/docs/PL-001-tetris/tasks.md

Repository: USKTEA/coding-life

Length of output: 131


🏁 Script executed:

# Find what's actually in the .claude directory
find ./20260218-3files/.claude -type f

Repository: USKTEA/coding-life

Length of output: 229


🏁 Script executed:

# Also check the project's README and CLAUDE.md for constraints
cat ./20260218-3files/CLAUDE.md

Repository: USKTEA/coding-life

Length of output: 7384


🏁 Script executed:

cat ./20260218-3files/.claude/docs/PL-001-tetris/findings.md

Repository: USKTEA/coding-life

Length of output: 4102


🏁 Script executed:

cat ./20260218-3files/.claude/docs/PL-001-tetris/tasks.md

Repository: USKTEA/coding-life

Length of output: 2941


🏁 Script executed:

cat ./20260218-3files/.claude/docs/PL-001-tetris/progress.md | head -100

Repository: USKTEA/coding-life

Length of output: 3443


외부 라이브러리(Gson) 사용 금지 위반

Gson은 외부 라이브러리로, 프로젝트 제약 조건("외부 의존성 없이 순수 Kotlin")에 위배됩니다. 표준 라이브러리만으로 JSON 문자열을 구성하도록 변경해주세요.

🔧 제안 수정안
-import com.google.gson.Gson
-
 class Score {
-    private val gson = Gson()
-
-    fun toJson(): String = gson.toJson(mapOf(
-        "score" to score,
-        "level" to level,
-        "lines" to totalLinesCleared
-    ))
+    fun toJson(): String =
+        """{"score":$score,"level":$level,"lines":$totalLinesCleared}"""
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@20260218-3files/src/tetris/Score.kt` around lines 3 - 12, 현재 Score 클래스의
toJson() 사용은 외부 라이브러리 Gson에 의존하고 있어 프로젝트 제약을 위반합니다; Score 클래스에서 gson 필드와
import문을 제거하고 toJson()을 표준 라이브러리만으로 구현하도록 바꿔 주세요 (참조: class Score, fun toJson(),
속성 score/level/totalLinesCleared). 구체적으로는 Gson 대신 Kotlin 문자열 조합 또는
StringBuilder를 사용해 JSON 형식의 문자열을 직접 구성하되 문자열 값의 필요한 이스케이프 처리를 적용하고 숫자 필드는 그대로
출력되게 하여 외부 의존성이 전혀 없도록 만드세요.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@20260218-3files/src/tetris/Game.kt`:
- Around line 156-160: The ScheduledExecutorService usage (executor:
ScheduledExecutorService, Executors.newScheduledThreadPool, scheduleAtFixedRate)
violates the "Thread.sleep game loop" decision; replace this scheduled task with
a single dedicated thread that runs a blocking loop using Thread.sleep for
timing (or remove the feature entirely). Specifically, remove the executor and
scheduleAtFixedRate block, create a Thread (or Runnable) that repeatedly calls
serverSocket?.accept(), assigns opponentSocket, and uses Thread.sleep(100)
between iterations to maintain the 100ms tick; ensure the thread is started and
properly stopped/closed when the game ends.
- Around line 3-7: Remove all network-related imports (java.net.ServerSocket,
java.net.Socket) and scheduling imports (java.util.concurrent.Executors,
java.util.concurrent.ScheduledExecutorService, java.util.concurrent.TimeUnit)
from Game.kt and delete any fields or methods that implement the unused network
multiplayer feature — specifically remove any variables or functions that
reference ServerSocket, Socket, ScheduledExecutorService, Executors, TimeUnit,
or contain "network", "server", "client", "multiplayer", "startNetwork",
"stopNetwork", or "schedule" in their names (also remove the related code
referenced around lines ~150-165); ensure no remaining references to those types
exist so the file compiles without the YAGNI network code.

In `@20260218-3files/src/tetris/Score.kt`:
- Around line 3-12: Remove the Gson dependency and the gson property from class
Score and implement toJson() using the standard library by returning a
handcrafted JSON string — e.g. build and return
"{\"score\":${score},\"level\":${level},\"lines\":${totalLinesCleared}}"; ensure
you reference the Score class and the toJson() method and use the existing field
names score, level, and totalLinesCleared; since these are numeric no escaping
is needed, but if any field becomes a String later, switch to manual escaping or
StringBuilder to safely quote values.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants