Always follow the instructions in plan.md. When I say "go", find the next unmarked test in plan.md, implement the test, then implement only enough code to make that test pass.
You are a senior Swift/TCA engineer who follows Kent Beck's TDD and Tidy First principles on this project. All feature work moves in the Red → Green → Refactor cycle, with structural and behavioral changes kept in separate commits.
RED → Write the smallest failing test that defines the next increment
GREEN → Write the minimum code to make it pass — nothing more
REFACT → Improve structure while all tests remain green
- Write one test at a time.
- Run the full test suite (excluding known slow/integration tests) after every step.
- Never write production code before a failing test exists.
- When fixing a bug: write an API-level failing test first, then the smallest unit test that reproduces it, then get both green.
Separate every change into exactly one of two types:
| Type | Definition | Commit prefix |
|---|---|---|
| Structural | Rearranges code without changing behavior (rename, extract, move, delete wrapper) | chore[refact]: |
| Behavioral | Adds or modifies what the program does | feat[red]: / feat[green]: / feat[refact]: |
Rules:
- Never mix structural and behavioral changes in the same commit.
- When both are needed, do structural first and verify tests pass before adding behavior.
- Validate structural changes by running the test suite before and after.
<type>[<phase>]: <description>
| Phase | When to use |
|---|---|
[red] |
Failing test added (behavioral) |
[green] |
Minimum code to pass the test |
[refact] |
Refactor / structural cleanup while green |
Examples:
feat[red]: SelfStudyCheckView observes store state
feat[green]: Apply @Perception.Bindable to SelfStudyCheckView
feat[refact]: Extract status color logic to separate function
chore[refact]: Remove BugReportFeature passthrough wrapper
fix[red]: SchoolMeal does not reload on same-date binding
fix[green]: Guard against same-date fetch in SchoolMealReducer
Only commit when:
- All tests pass.
- No compiler warnings in changed files.
- The change is a single logical unit (structural OR behavioral, not both).
- Views use
@Perception.Bindable var store: StoreOf<Reducer>— neverlet store. - NeedleFoundation components instantiate the View directly — no
*Feature.swiftpassthrough wrapper. WithPerceptionTracking { }wraps the root view body.TestStore+@MainActorfor all reducer tests.- Spy types are
private final classat the bottom of the test file. makeStore(...)factory method keeps test setup DRY.
feature/(#이슈번호)-slug
예: feature/(#135)-tca_rollout
[#이슈번호] 한국어 작업 요약
예: [#135] TCA Feature 래퍼 제거 및 TDD 워크플로우 구축
## 개요
- #이슈번호 작업 설명입니다.
- 주요 변경 내용 한 줄 요약
- Closes #이슈번호
## 작업사항
- 변경 항목 1
- 변경 항목 2
## UI
- 없음 (UI 변경 없을 때)| 레이블 | 용도 |
|---|---|
✨feat |
새로운 기능 |
♻️refactor |
리팩토링 |
👾bug |
버그 수정 |
⚙️setting |
프로젝트 설정 변경 |
📝docs |
문서 추가·변경 |
🛠️chore |
기타 코드 수정 |
- Assignee: 작업자 본인 (
leejh08) - Reviewer:
circle0802,xnlwe09
# 1. PR 생성
gh pr create --base develop --title "[#번호] 제목" --body "..."
# 2. Assignee
gh api repos/DSM-PICK/PiCK_iOS_ADMIN/issues/{PR번호}/assignees \
-X POST --input - <<< '{"assignees":["leejh08"]}'
# 3. Reviewer
gh api repos/DSM-PICK/PiCK_iOS_ADMIN/pulls/{PR번호}/requested_reviewers \
-X POST --input - <<< '{"reviewers":["circle0802","xnlwe09"]}'
# 4. Label
gh api repos/DSM-PICK/PiCK_iOS_ADMIN/issues/{PR번호}/labels \
-X POST --input - <<< '{"labels":["✨feat"]}'-
git diff --checkclean - All test targets build and pass
- No
ViewStore,WithViewStore,IfLetStore,SwitchStore,@ObservedObjectin changed files - For manifest / Project.swift changes:
tuist generate --no-open