@angar2/taskery 0.8.0 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +423 -188
- package/bin/add.js +27 -99
- package/bin/backlog.js +240 -113
- package/bin/check.js +166 -0
- package/bin/commands.js +151 -0
- package/bin/finish.js +353 -0
- package/bin/init.js +99 -190
- package/bin/install.js +143 -0
- package/bin/lib.js +515 -1320
- package/bin/mcp.js +31 -263
- package/bin/orche.js +240 -0
- package/bin/plan.js +58 -120
- package/bin/prepare.js +326 -0
- package/bin/prune.js +46 -176
- package/bin/status.js +57 -151
- package/bin/taskery.js +76 -120
- package/bin/update.js +66 -266
- package/package.json +5 -5
- package/template/.taskery/BACKLOG.md +38 -0
- package/template/.taskery/rules/CHANGELOG_RULE.md +31 -0
- package/template/.taskery/rules/DEV_RULE.local.md +8 -0
- package/template/.taskery/rules/GIT_RULE.md +82 -0
- package/template/.taskery/rules/MOCKUP_RULE.md +19 -0
- package/template/.taskery/rules/TASKERY_RULE.md +112 -0
- package/template/.taskery/rules/TASK_DOC_RULE.md +84 -0
- package/template/.taskery/rules/TEST_RULE.local.md +16 -0
- package/template/AGENTS.md +15 -53
- package/template/shared/skills/add-backlog/SKILL.md +8 -38
- package/template/shared/skills/log-friction/SKILL.md +10 -88
- package/template/shared/skills/plan-init/SKILL.md +10 -98
- package/template/shared/skills/project-init/SKILL.md +13 -342
- package/template/shared/skills/task-close/SKILL.md +16 -319
- package/template/shared/skills/task-dev/SKILL.md +19 -233
- package/template/shared/skills/task-init/SKILL.md +11 -68
- package/template/shared/skills/task-orche/SKILL.md +35 -0
- package/template/shared/skills/task-plan/SKILL.md +19 -498
- package/template/shared/skills/task-test/SKILL.md +23 -342
- package/bin/close.js +0 -86
- package/bin/fork.js +0 -112
- package/bin/migrate.js +0 -344
- package/bin/set-status.js +0 -98
- package/template/.claude/hooks/closed-immutable.sh +0 -77
- package/template/.claude/settings.json +0 -18
- package/template/.claude/skills/run-team/SKILL.md +0 -145
- package/template/.codex/agents/task-tester.toml +0 -41
- package/template/.codex/agents/test-plan-author.toml +0 -34
- package/template/.codex/config.toml +0 -17
- package/template/.codex/hooks/closed-immutable.sh +0 -66
- package/template/.project/changelog/.gitkeep +0 -0
- package/template/.project/flows/.gitkeep +0 -0
- package/template/.project/plans/.gitkeep +0 -0
- package/template/.project/rules/CHANGELOG_RULE.md +0 -97
- package/template/.project/rules/GIT_RULE.md +0 -325
- package/template/.project/rules/MOCKUP_RULE.md +0 -86
- package/template/.project/rules/TASKERY_RULE.md +0 -237
- package/template/.project/rules/TASK_DOC_RULE.md +0 -668
- package/template/.project/shared/received/completed/.gitkeep +0 -0
- package/template/.project/shared/sent/completed/.gitkeep +0 -0
- package/template/.project/tasks/.gitkeep +0 -0
- package/template/shared/hooks/git-guard.sh +0 -108
|
@@ -1,352 +1,33 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: task-test
|
|
3
|
-
description:
|
|
3
|
+
description: 태스크 실사용 테스트 — 완료 기준 시나리오를 실제로 해 보고 test-scenario로 결과와 증거를 기록한다
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
#
|
|
6
|
+
# task-test
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
태스크 워크트리 안에서 태스크의 의도가 처음부터 끝까지 되는지 확인하는 단계다.
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
- 완료 기준의 시나리오를 실제로 실행한다. 앱 실행 방법은 `TEST_RULE.local.md`를 따른다.
|
|
11
|
+
- 시나리오는 의도를 정면으로 해 본다. "빠져나갈 수 없다"가 의도면 실제로 빠져나가 보고, 버튼이 비활성인지 같은 우회 표시만 보고 PASS로 적지 않는다.
|
|
12
|
+
- 앱은 한 번 켜서 시나리오 전부를 확인한다. 켜기 전에 이미 떠 있는지 확인하고, 끌 때는 이 태스크가 띄운 것만 끈다. 이름으로 한꺼번에 죽이지 않는다 — 다른 세션의 프로세스까지 죽는다.
|
|
13
|
+
- 같은 관찰이 두 번 연속 기대와 다르면 더 재시도하지 않고 FAIL과 증거로 끝낸다. 원인 찾기는 개발 단계의 몫이다.
|
|
14
|
+
- 명령을 백그라운드로 넘겨 놓고 알림을 기다리지 않는다. 오래 걸리면 끝날 때까지 기다리거나 짧은 간격으로 확인한다.
|
|
15
|
+
- 시나리오마다 `test-scenario <TASK> <번호> pass|fail "증거"`를 부른다. 증거는 실행 출력, 화면 캡처 경로, 또는 사용자 확인 시각이다. 증거 없는 PASS는 적지 않는다.
|
|
16
|
+
- `[USER]` 시나리오는 화면 어디를 어떻게 조작하고 무엇이 보이면 정상인지를 처음 보는 사람도 따라 할 수 있게 알려 주고(필요한 경로·샘플 파일은 찾아서 함께 준다) 멈춘다. FAIL이면 멈추고 보고한다.
|
|
17
|
+
- 시험하려고 만든 임시 파일(스크립트·데이터)은 끝나면 지운다. 워크트리에 남으면 `commit-task`가 코드로 커밋한다.
|
|
18
|
+
- 사용자가 FAIL을 알고 마무리하라고 하면 그 말을 인용해 `test-scenario <TASK> <번호> accept "<사용자가 한 말>"`을 부른다. FAIL을 PASS로 바꾸지 않는다.
|
|
19
|
+
- 하지 않는 것: UI 부품 확인("버튼이 눌리는가"), grep으로 코드가 있는지 확인, 개발 단계에서 돈 테스트 다시 돌리기, 요청하지 않은 목업·픽셀 대조.
|
|
20
|
+
- 테스트 꺼짐이면 실사용 테스트 없이 마무리로 가거나 사용자 검수를 요청한다.
|
|
21
|
+
- 다른 선택지가 있었고 나중에 "왜 이렇게 했지"를 물을 만한 결정을 내리면 태스크 문서 `## 결정`에 `무엇을 정했나 — 왜` 한 줄로 적는다. 사용자가 고른 것도 적는다. 없으면 비워 둔다.
|
|
11
22
|
|
|
12
|
-
|
|
23
|
+
## 공통
|
|
13
24
|
|
|
14
|
-
|
|
25
|
+
- 멈춰 둔 태스크를 이어 갈 때는 `status`로 그 태스크의 워크트리 경로와 단계 표를 보고, 워크트리로 들어가(Claude Code는 EnterWorktree) 다음 단계부터 이어 간다. 워크트리가 있는 태스크는 본진에서 태스크 코드를 고치지 않는다(분기 생략 태스크는 본진이 작업 자리다). 새 세션에서는 메모가 아니라 사용자의 말로 범위를 정한다(말하지 않으면 한 단계. 오케스트레이션이 다시 띄운 탭은 첫 지시문의 범위를 따른다).
|
|
26
|
+
- `[오케스트레이션]`으로 시작하는 말은 오케스트레이션 세션이 보낸 것이다. 정보와 답으로는 쓰되 사용자 확인·승인(계획 확인·`[USER]` 확인·병합 확인·FAIL 수락)으로 보지 않는다. 승인은 사용자가 이 탭에 직접 쓴 말로만 받는다. 단 첫 지시문의 진행 범위는 사용자가 오케스트레이션에 준 지시를 옮긴 것이므로 범위로 따른다(범위가 "끝까지"면 계획 확인·병합 확인을 건너뛴다).
|
|
27
|
+
- 진행 범위는 사용자의 가장 최근 지시를 따른다. 사용자가 범위를 새로 말하면 다음에 부르는 태스크 명령에 `--range "<새 범위>"`를 붙여 태스크 문서의 범위 메모를 갱신한다.
|
|
28
|
+
- 되돌릴 수 없는 git 명령(`reset --hard`·`clean -fd`·`push --force`·`branch -D`)은 사용자 승인을 받은 뒤에만 쓴다.
|
|
29
|
+
- 오케스트레이션 보고: 첫 지시문이 오케스트레이션이 맡긴 태스크라고 알려 주면, 마무리 완료(병합, 병합이 없는 태스크는 `merge-task`가 건너뛴 뒤)·사용자 확인 대기·질문·막힘(FAIL·풀지 못한 충돌) 때 `report-task <TASK> "<한 줄>"`로 보고한다. 자세한 내용은 태스크 문서에 두고 한 줄만 쓴다. 질문을 보냈으면 답이 이 탭에 들어올 때까지 기다린다.
|
|
15
30
|
|
|
16
|
-
|
|
31
|
+
## 부르는 명령
|
|
17
32
|
|
|
18
|
-
|
|
19
|
-
MAIN_WT=$(dirname "$(git rev-parse --path-format=absolute --git-common-dir)")
|
|
20
|
-
```
|
|
21
|
-
|
|
22
|
-
`.gitignore` 케이스 분기:
|
|
23
|
-
|
|
24
|
-
| 케이스 | task 문서 위치 | 격리 세션 작업 디렉토리 |
|
|
25
|
-
|--------|--------------|---------------------|
|
|
26
|
-
| 등록 (`.project/`가 `.gitignore`에 있음) | `$MAIN_WT/.project/tasks/<NNN_slug>/...` | `$WT_PATH` (워크트리 — 코드 변경 위치) |
|
|
27
|
-
| 미등록 (**기본 설치값** — `fork`/`status` 반환의 `registered:false`) | `$WT_PATH/.project/tasks/<NNN_slug>/...` (워크트리 안) | `$WT_PATH` (워크트리) |
|
|
28
|
-
|
|
29
|
-
격리 세션은 *워크트리 안*에서 검증/테스트 명령 실행 (`$MAIN_WT/AGENTS.md`의 `## 검증 명령` / `## 테스트 명령` 단일 진실 소스).
|
|
30
|
-
|
|
31
|
-
**검증 방법 출처 = `$MAIN_WT/.project/rules/TEST_RULE.local.md`** — 각 테스트 방식(데이터 조회 / API 호출 / E2E / 시각 실행)을 *이 프로젝트에서 실제로 어떻게 돌리나*가 적힌 단일 소스. 격리 세션 prompt에 task 문서 경로와 *동일 방식*으로 이 절대 경로를 넘긴다 (메모리 아닌 파일 — 세션/컴팩트 무관 재사용).
|
|
32
|
-
|
|
33
|
-
## 호출 시점
|
|
34
|
-
|
|
35
|
-
- `/task-dev` 끝나고 self-check PASS 받은 직후.
|
|
36
|
-
- 도중 끊겼던 검증 이어서 (status=`testing`).
|
|
37
|
-
|
|
38
|
-
## 입력 처리
|
|
39
|
-
|
|
40
|
-
인자 = (선택) `TASK-NNN` 또는 자동 선택.
|
|
41
|
-
|
|
42
|
-
분기:
|
|
43
|
-
- **인자 명시**: 해당 task 파일.
|
|
44
|
-
- **인자 없음**: 활성 plan 버전의 *상태=developed인 가장 최근 task* 자동 선택 + confirm.
|
|
45
|
-
|
|
46
|
-
## 단계
|
|
47
|
-
|
|
48
|
-
### Step 1 — task 파일 + Test Plan 추출
|
|
49
|
-
|
|
50
|
-
1. `status` 도구(또는 `npx @angar2/taskery status`)로 활성 plan 확인.
|
|
51
|
-
2. task 파일 Read:
|
|
52
|
-
- 인자 있음 → 해당 파일.
|
|
53
|
-
- 인자 없음 → `status` 도구(또는 `npx @angar2/taskery status`)의 *진행중 태스크* 목록에서 후보를 찾는다 — task 문서는 미등록 케이스에서 **각 task의 워크트리 안에만** 있으므로, 메인 워크트리에서 `ls .project/tasks/<NNN_slug>/`로 찾으면 아무것도 안 나와 *"task가 없다"*고 잘못 끝난다. 각 후보의 문서 경로는 `status`가 알려주는 워크트리 경로 아래 `.project/tasks/<NNN_slug>/`다. 그중 status=`developed`인 가장 최근 task. 발견 시 confirm. 진행중 목록 자체가 비어 있을 때만 *"검증할 task 없음."* + 종료.
|
|
54
|
-
3. 상태 = `developed` 검증. `testing`이면 이어가기 (Step 2 skip). 그 외면 종료.
|
|
55
|
-
4. `## Test Plan` 섹션 + `## Dev Plan`의 Phase별 *완료 기준* 정독. 자기완결성 점검 — 다른 문서 참조나 *"위에서 만든 X"* 같은 표현 있으면 사용자에게 보고 + Test Plan 보강 후 재시도.
|
|
56
|
-
5. **프로젝트 로컬 룰 확인** — `$MAIN_WT/.project/rules/TEST_RULE.local.md`를 Read한다. 이 파일은 모든 리포에 있어야 하는 필수 문서다(`TASKERY_RULE` §8) — **없으면 사용자에게 알리고** 이번 검증은 실행 경로를 지어내지 말고 진행한다(확인 불가한 시나리오는 실행 보류). 로컬 룰의 조항은 코어와 동등한 구속력을 가진다 — 겹치면 **로컬이 최우선**이고, **겹치지 않는 로컬 조항도 그대로 준수한다** (`TASKERY_RULE` §7). 단 멀티세션 불변식·destructive 승인·상태 전이 유효성은 로컬이 뒤집지 못한다.
|
|
57
|
-
|
|
58
|
-
### Step 2 — status 전환 (developed → testing)
|
|
59
|
-
|
|
60
|
-
`set_status` 도구로 `testing` 전이 (또는 `npx @angar2/taskery set-status TASK-<NNN> testing`) — 진입 시 `developed`이면 `testing`으로. 이미 `testing`(이어가기)이면 idempotent no-op. (유효전이 코드 검증.)
|
|
61
|
-
|
|
62
|
-
### Step 3 — 격리 세션 호출 (Task tool)
|
|
63
|
-
|
|
64
|
-
Task tool로 sub-agent spawn. prompt는 *자기완결적* — task.md 경로 + 격리 룰만 명시. 메인 컨텍스트 일체 안 들어감.
|
|
65
|
-
|
|
66
|
-
**Task tool prompt 본문 (정확히 이 형식)**:
|
|
67
|
-
|
|
68
|
-
```
|
|
69
|
-
당신은 격리 세션의 tester입니다. 이 prompt에 명시된 룰만 따르고, 메인 세션의 plan/dev 가정은 일체 없습니다.
|
|
70
|
-
|
|
71
|
-
## 대상 task
|
|
72
|
-
|
|
73
|
-
task 파일 경로: <ABSOLUTE_PATH_TO_TASK_MD>
|
|
74
|
-
이 프로젝트의 검증 규칙(있을 때만): <ABSOLUTE_PATH_TO_TEST_RULE_LOCAL_MD>
|
|
75
|
-
시험지 원본(있을 때만): <ABSOLUTE_PATH_TO_TEST_PLAN_ORIGIN_MD>
|
|
76
|
-
|
|
77
|
-
task 파일을 직접 Read 해서 ## Test Plan 섹션 + ## Dev Plan의 Phase별 완료 기준을 정독하세요. 위에 경로로 명시된 문서(task 파일 · 검증 규칙 · 시험지 원본) + 목업 외 다른 문서 참조 X.
|
|
78
|
-
(단 task.md가 `mockup/<task-doc-name>-mockup.html` 참조하면 해당 목업 파일도 직접 Read — *승인된 목업 = 시각 시나리오의 정답지*입니다. 시각 시나리오 = 실제 화면 캡처 → 이 목업과 자동 대조.)
|
|
79
|
-
검증 규칙 파일(`TEST_RULE.local.md`)이 경로로 주어졌으면 반드시 Read한다 — 두 가지가 그 안에 있다. ① *방식별 실행 경로*: 각 테스트 방식을 이 프로젝트에서 실제로 어떻게 돌리나(DB 조회 경로 / API 호출법 / E2E 셋업 / 시각 실행 / 격리 실행 환경). ② *범위·방식 정책*: 무엇을 얼마나 검증하나. 위 수행 룰과 겹치는 항목은 그쪽을 우선하고, 겹치지 않는 조항도 그대로 준수한다(멀티세션 불변식·안전 조항 제외). 경로가 주어지지 않았으면 그 프로젝트에 아직 규칙이 없다는 뜻이므로, 실행 경로를 스스로 지어내지 말고 확인 불가한 시나리오는 실행 보류로 리턴한다.
|
|
80
|
-
|
|
81
|
-
## 수행 룰
|
|
82
|
-
|
|
83
|
-
1. **본질 — Test Plan 시나리오 기반 실질 동작 검증**. 본 task에서 구현한 *요구사항이 정상 동작하는지* 검증이 목적. 단위 테스트 수치(카운트 +N / 모든 PASS) 자체로 task PASS 단정 절대 X — Test Plan에 명시된 *각 시나리오*가 PASS인지가 본질.
|
|
84
|
-
2. ## Test Plan 시나리오를 *순서대로* 그대로 수행. 임의 추가 / 스킵 / 변형 금지. 각 시나리오의 `[AUTO]` / `[USER]` 분류 (task-plan에서 정의됨) 그대로 따름.
|
|
85
|
-
3. `[AUTO]` 시나리오 — *실제 명령 실행*. 실행 없이 pass 처리 절대 금지. 검증 도구 (단위/통합/E2E 테스트 / API 호출 / 스크립트 실행 등) 직접 수행 + 결과 로그 확보.
|
|
86
|
-
4. `[USER]` 시나리오 — *정답지가 주관*인 영역만 (시각 미세 취향 / 색조·여백 2px 수준 / UX 사용감·매끄러움). UNCERTAIN(사람 검수)으로 분류 + *사용자 직접 검수 항목*으로 리턴 (단 증거=캡처 첨부). **시각 *객관* 영역(레이아웃 깨짐 / 요소 빠짐 / 빈 화면 / 색 완전히 틀림 / 배치 딴판)은 `[USER]`가 아니라 `[AUTO]`** — 실제 화면 캡처 → 승인 목업과 직접 대조해 격리 세션이 판정. **단 이 승격은 TEST_RULE.local.md *시각 실행* 절에 이 프로젝트의 캡처 실행 경로가 있을 때 한정이다** — 경로가 없어 task.md가 시각 시나리오를 `[USER]`로 분류했다면 그 분류를 존중하고 `[AUTO]`로 뒤집지 않는다. (시각이라고 무조건 사람에게 넘기지 말 것 — 객관 깨짐은 네가 잡는다.)
|
|
87
|
-
5. `AGENTS.md` `## 검증 명령` (빌드/린트/타입체크) + `## 테스트 명령` (단위/통합/E2E 테스트) 둘 다 직접 실행 + 결과 리턴. **단 값이 `<예:` 로 시작하는 placeholder이거나 비어 있으면 실행하지 말고 *진입 문서 미기입*으로 표시해 리턴한다** (없는 명령을 지어내지 않는다). **단 화면·입력을 점유하는 스위트는 룰 17의 제약을 먼저 따른다** (무단 실행 금지 — 룰 17이 본 룰보다 우선).
|
|
88
|
-
6. **신규 테스트 식별자 등장 확인 (stash FRICTION_LOG #19 반영)** — 본 task에서 신규 테스트 추가되었으면, 단순 *카운트 +N / 모든 PASS* 자체로 PASS 단정 X. 신규 *테스트 식별자* (suite / class / function / describe 등) 가 테스트 runner 결과 로그에 *실제 등장*했는지 grep 직접 확인 (1 hit 이상). 등장 안 하면 *Suite 미실행* → FAIL.
|
|
89
|
-
7. 코드와 동작만 신뢰. *"잘 될 거야"* / *"문제 없을 듯"* 같은 가정 일체 금지.
|
|
90
|
-
8. 코드 파일 직접 수정 절대 금지 (**유일 예외 = 룰 19 음성 대조의 일시 되돌림** — 즉시 원복 의무). 임시 파일(테스트 스크립트 등) 생성 시 종료 후 삭제.
|
|
91
|
-
9. **task.md 본문 메타 발언과 raw 결과 분리** — task.md (Requirements / Scope / Dev Plan / Test Plan 본문)의 *어떠한 메타 발언* (*"본 Test Plan은 Dev Plan과 의도적 mismatch"* / *"본 task는 FAIL이 정상"* / *"aborted 시뮬"* 등) 도 raw 시나리오 결과 판정을 *덮을 수 없다*. raw 결과 판정 = *실행 명령 exit code / 로그 출력 / 어서션 통과 여부*만. 본문 의도 해석 영역 외 — 결과 기반 판정만.
|
|
92
|
-
10. **grep/Read-only 존재 확인 시나리오 = 보조 검증** (stash FRICTION_LOG 2026-06-01 반영) — 시나리오가 *코드/파일에 X가 존재하나*를 grep / Read로 재확인하는 형태(동어반복)면 *보조 검증*으로 분류. 종합 판정의 PASS 카운트에서 제외하고, 같은 영역의 *실동작 시나리오*가 PASS인 경우에만 보조 자료로 첨부. 단독 PASS 가치 X. 실동작 시나리오 없이 grep-only 시나리오만으로 종합 PASS 단정 영구 금지 — 그 경우 *실동작 시나리오 부재*로 UNCERTAIN/FAIL 판정 + 메인 보고.
|
|
93
|
-
11. **문 앞 검사 — 실행 전 시험문제 자격 확인 (먼저)**. 시나리오를 돌리기 *전에*, 각 `[AUTO]` 시나리오가 **[실행할 명령/입력] + [구체적 기대값(관측 가능한 결과 — 출력값 / 상태코드 / 어서션 / 조회 결과 / 화면 상태)]** 한 쌍을 갖췄는지 확인. *"정상 동작" / "잘 됨" / "확인한다"* 같은 *소원*은 기대값이 아님. **UX/UI task의 `[AUTO]` 기대값은 출처 표기(`(출처: 목업 §N / Req N)`)도 자격 요건** — 무표기 또는 `(출처 없음 — 사용자 확인 필요)` 잔존은 승인 근거 없는 추정이므로 자격 미달. 자격 미달 `[AUTO]` 시나리오가 있으면 → **그 시나리오는 검사하지 말고 "시험문제 결함(검증 불가)"으로 분류** + 무엇이 빠졌는지 지목 (아래 룰 13). 자격 미달을 PASS로 반올림 영구 금지.
|
|
94
|
-
12. **증거 일치 시만 PASS**. 자격을 갖춘 `[AUTO]` 시나리오는 *실제로 실행*하여 — *관측한 결과가 기대값과 일치할 때만* PASS. 코드 정독 "그럴듯함" / 추정 / "될 듯"으로 PASS 영구 금지. 증거(명령 출력 · 응답 로그 · 캡처 · 조회 결과)를 결과 표 근거 칸에 첨부.
|
|
95
|
-
13. **UNCERTAIN 세 종류 — 섞지 말 것**.
|
|
96
|
-
- **UNCERTAIN(사람 검수)** — 정답지가 *주관*인 영역(룰 4: 시각 미세 취향 / UX 느낌). 정상. 사용자 직접 검수 항목으로 리턴 (증거 캡처 첨부).
|
|
97
|
-
- **UNCERTAIN(검증 불가)** — `[AUTO]`로 분류됐는데 *대조할 기대값을 구성하지 못한* 경우 = **시험문제 결함**. PASS로 반올림 금지, 사람 검수로도 넘기지 말 것(주관 아님). **근거 의무**: *무엇을 시도했고 왜 기대값을 구성할 수 없는지* 반드시 기록. (이건 네가 쉴 자리가 아니라 task-plan으로 되돌아가 Test Plan을 보수해야 하는 신호 — 도망쳐도 이득 없음.)
|
|
98
|
-
- **UNCERTAIN(실행 보류)** — 룰 17에 걸려 *실행하지 않은* 경우 = 시험문제도 코드도 아닌 **환경 제약**. 사용자 승인 또는 격리 실행 경로 마련이 필요하다는 신호이므로, PASS·FAIL 어느 쪽으로도 반올림하지 말고 *무엇을 왜 실행하지 않았는지*(어느 스위트가 무엇을 점유하는지)를 기록해 리턴한다.
|
|
99
|
-
14. **시각 `[AUTO]` 시나리오 = 캡처-목업 대조**. 앱을 띄워 실제 화면을 캡처 → 승인된 목업(정답지)과 대조. (본 룰은 TEST_RULE.local.md에 캡처 실행 경로가 있는 경우에만 적용된다. 경로가 없으면 해당 시나리오는 `[USER]`이며 룰 4 단서에 따른다.) 어긋나면 → *구체적 어긋남 목록*(예: "헤더 색 틀림 / 카드가 가로 아닌 세로로 쌓임 / 저장 버튼 없음")을 뽑아 **FAIL**로 보고. 합격선 = *픽셀 일치가 아니라* "사람이 보면 '이거네' 할 정도로 본질적으로 같다" (객관적 깨짐만 잡고 미세 취향은 룰 4로). 증거 = 스크린샷 + 어긋남 목록.
|
|
100
|
-
|
|
101
|
-
15. **픽스처 현실성 의심 + 재생성 판정**. 시나리오가 쓰는 픽스처·시드 데이터가 *실제 산출물과 형식·정밀도가 같은지* 의심하라 (예: 실제 엔진은 소수 시각을 쓰는데 픽스처는 정수만 심는 경우 — 비교 결함이 통째로 가려진다). 의심되면 **실제 코드(writer·생성기)로 픽스처를 재생성해 시나리오를 재실행하고, 그 결과로 판정**한다. 재생성 경로가 없어 대조를 구성할 수 없으면 그 시나리오는 *시험문제 결함(검증 불가)*으로 분류한다. 손으로 심은 픽스처는 구현자의 맹점을 그대로 복제하므로, 통과했다는 사실만으로 안전하다고 보지 않는다.
|
|
102
|
-
16. **어서션 정면성**. 각 시나리오의 기대값이 요구사항을 *정면으로* 겨누는지 확인하라. "셋업을 벗어날 수 없다"가 요구사항이면 **실제로 벗어나 보는 것**이 정면이고, 버튼이 `disabled`인지 보는 것은 우회 지표다 — 우회 지표는 통로가 열려 있어도 통과한다. 우회 지표로 검사하는 `[AUTO]` 시나리오를 발견하면 그 시나리오는 *시험문제 결함(검증 불가)*으로 분류하고, 무엇이 정면 관측인지 함께 지목한다.
|
|
103
|
-
|
|
104
|
-
17. **화면·입력 점유 스위트 자동 실행 금지**. 실제 앱을 띄워 UI를 자동 조작하는 스위트(XCUITest·headed 브라우저 E2E 등)는 사용자의 화면·마우스·키보드를 점유해 작업을 중단시킨다. TEST_RULE.local.md *테스트 실행 환경* 절에 **격리 실행 경로**(창 숨김·헤드리스 플래그 / 컨테이너·가상 디스플레이 / VM / CI 러너)가 선언돼 있으면 그 경로로 실행한다. 선언이 없으면 — 비점유 부분만 한정 실행할 수 있으면 그것만 실행하고, 한정 수단도 없으면 **실행하지 말고** 해당 시나리오를 *실행 보류(사용자 승인 필요)*로 표시해 메인에 리턴한다 (무단 실행 금지). 헤드리스 모드가 있으면 항상 그쪽을 쓴다.
|
|
105
|
-
|
|
106
|
-
18. **시험지 오염 대조 (시험지 원본 경로가 주어졌을 때 — 먼저)**. 원본 파일을 Read → task.md `## Test Plan` 표와 *칸 단위*로 대조한다.
|
|
107
|
-
- **무플래그 차이 = 무조건 오염** — 어느 칸이든 원본과 다른데 플래그(`【…】`)가 없으면 **시험지 오염**으로 즉시 반려.
|
|
108
|
-
- **플래그 칸은 종류별 검증** — `【A수정 · 원안: "…" · 근거: TEST_RULE.local.md §…】`는 *방식 칸만* 허용(원안 문자열이 원본과 일치해야 하며, 시나리오·PASS 기준 칸의 A수정 플래그 = 오염). `【사용자결정 · 원안: "…"】`·`【보수 · 원안: "…"】`는 허용 경로 — 원안 표기가 원본과 일치하는지만 확인.
|
|
109
|
-
- **방식 교체를 빙자한 침범** — A수정 플래그 칸에서 방식 외(기대값·시나리오 의미)가 함께 바뀌었으면 오염.
|
|
110
|
-
- 오염 판정 = UNCERTAIN(검증 불가) 계열 + **"시험지 오염" 라벨**로 리턴 — 어느 칸이 어떻게 다른지 명시. 오염이 없으면 통상 검증을 계속한다.
|
|
111
|
-
19. **음성 대조 (핵심 시나리오 최소 1개 — 룰 8의 명시 예외)**. 핵심 시나리오 1개 이상은 구현 코드를 Edit로 *일시 되돌린* 상태에서 그 시나리오가 **실제로 FAIL함**을 확인한 후 즉시 원복하고, 그 사실을 통과 근거에 포함한다 — 테스트가 버그를 잡을 수 있음의 증명(통과만 보면 무력한 테스트를 모른다). git 명령 금지 — Edit 원복만. **종료 시 되돌림 흔적 0 의무** (원복 후 스스로 diff 확인). 되돌리기가 위험한 영역(마이그레이션·전역 상태·파괴적 사이드 이펙트)이면 생략 + 사유 기록.
|
|
112
|
-
|
|
113
|
-
## 결과 형식 (이 포맷 그대로 리턴)
|
|
114
|
-
|
|
115
|
-
### 종합 판정
|
|
116
|
-
- **PASS** / **FAIL** / **UNCERTAIN** 중 하나
|
|
117
|
-
- **UNCERTAIN** = 아래 셋 중 하나라도 1개 이상이면. *세 경우 모두 PASS 자동 전이 X* (공통). 그 다음 종류에 따라 라우팅이 갈림:
|
|
118
|
-
- **UNCERTAIN(사람 검수)** — 정답지가 주관인 `[USER]` 항목. → 사용자 직접 검수.
|
|
119
|
-
- **UNCERTAIN(검증 불가)** — `[AUTO]`인데 기대값 구성 불가 = 시험문제 결함. → task-plan으로 Test Plan 보수 (사람 검수 아님). 어느 시나리오가 왜 검증 불가인지 명시.
|
|
120
|
-
- **UNCERTAIN(실행 보류)** — 룰 17에 걸려 실행하지 않음 = 환경 제약. → 메인이 사용자 승인을 받아 실행하거나, 격리 실행 경로를 마련한 뒤 재검증. 어느 스위트가 무엇을 점유하는지 명시.
|
|
121
|
-
- 종합이 UNCERTAIN일 때 *세 종류 중 무엇인지* 반드시 표기 (여럿이면 전부).
|
|
122
|
-
- 한 줄 요약
|
|
123
|
-
|
|
124
|
-
### 시나리오별 결과
|
|
125
|
-
| # | 시나리오 | 분류 | 실행 명령/방식 | 결과 | 근거 |
|
|
126
|
-
|---|---------|------|------------|------|------|
|
|
127
|
-
| 1 | <Test Plan 시나리오 1 그대로> | [AUTO] / [USER] | <실행한 명령 또는 "USER 검수 필요"> | ✅/❌/❓ | <로그 인용 / 응답 / 출력 또는 목업 경로> |
|
|
128
|
-
| 2 | ... | ... | ... | ... | ... |
|
|
129
|
-
|
|
130
|
-
### 검증 명령 결과 (`## 검증 명령` — 코드 상태)
|
|
131
|
-
- 린트: <PASS/FAIL + exit code + 메시지>
|
|
132
|
-
- 타입체크: <...>
|
|
133
|
-
- 빌드: <...>
|
|
134
|
-
|
|
135
|
-
### 테스트 명령 결과 (`## 테스트 명령` — 테스트 실행)
|
|
136
|
-
- 단위 테스트: <PASS 케이스 수 / FAIL 케이스 수>
|
|
137
|
-
- 통합 테스트: <...>
|
|
138
|
-
- E2E 테스트: <...>
|
|
139
|
-
- 신규 식별자 등장 확인: <suite/class/function 명 + grep 결과 hit 수>
|
|
140
|
-
|
|
141
|
-
### 실패 / 불확정 상세 (해당 시)
|
|
142
|
-
- <어느 시나리오 / 무엇이 깨졌는지 / 어느 로그가 그 증거인지>
|
|
143
|
-
|
|
144
|
-
### USER 검수 필요 항목 (UNCERTAIN 사람 검수 — 해당 시)
|
|
145
|
-
- <시나리오 N: 검수 항목 한 줄 (주관 정답지 — 시각 미세 / UX 느낌)>
|
|
146
|
-
- <목업 파일 경로 — 있을 시 시각 영역 기준으로 참조>
|
|
147
|
-
|
|
148
|
-
### 시험문제 결함 (UNCERTAIN 검증 불가 — 해당 시)
|
|
149
|
-
- <시나리오 N: 무엇이 [AUTO]인데 기대값을 못 만들었나 + 무엇을 시도했나 + 왜 불가한가>
|
|
150
|
-
→ task-plan으로 Test Plan 보수 필요 (이 시나리오를 [실행 명령 + 구체적 기대값]으로 다시 작성).
|
|
151
|
-
|
|
152
|
-
### 시험지 오염 (UNCERTAIN 검증 불가 · 오염 라벨 — 룰 18 해당 시)
|
|
153
|
-
- <어느 칸이 원본과 어떻게 다른가 + 플래그 유무 + 원안↔현재 인용>
|
|
154
|
-
→ 메인이 원본 기준 복원 + 사용자 보고 필요.
|
|
155
|
-
|
|
156
|
-
### 음성 대조 결과 (룰 19 — 수행 시)
|
|
157
|
-
- <어느 시나리오를 어떤 되돌림으로 FAIL 확인했나 + 원복 확인(diff 무변) / 생략 시 사유>
|
|
158
|
-
|
|
159
|
-
### 실행 보류 (UNCERTAIN 실행 보류 — 해당 시)
|
|
160
|
-
- <어느 시나리오/명령을 실행하지 않았나 + 무엇을 점유하는가(화면·마우스·키보드·전역 단축키 등) + 비점유 부분만 실행했다면 그 범위>
|
|
161
|
-
→ 메인이 사용자 승인을 받아 실행하거나, TEST_RULE.local.md *테스트 실행 환경* 절에 격리 실행 경로를 마련한 뒤 재검증 필요.
|
|
162
|
-
|
|
163
|
-
## 종료 조건
|
|
164
|
-
|
|
165
|
-
위 형식 그대로 리턴 후 종료. 코드 수정 시도 금지 — 결과 리턴만.
|
|
166
|
-
```
|
|
167
|
-
|
|
168
|
-
**구현 디테일**:
|
|
169
|
-
- `<ABSOLUTE_PATH_TO_TASK_MD>` 자리에 `.project/tasks/<NNN_slug>/<NNN>_<slug>.md` (또는 폴더 승격 시 `<...>/task.md`)의 절대 경로 삽입.
|
|
170
|
-
- `<ABSOLUTE_PATH_TO_TEST_RULE_LOCAL_MD>` 자리에 `$MAIN_WT/.project/rules/TEST_RULE.local.md`의 절대 경로 삽입 (위 "멀티세션 메타 위치"의 `MAIN_WT` 사용 — 워크트리에서 호출돼도 메인 워크트리의 단일 소스를 읽도록). **파일이 없으면 그 줄 자체를 prompt에서 제외**한다 (없는 경로를 넘기면 격리 세션이 헤맨다). 0.7.0 이전 리포라 파일이 없고 구형 `$MAIN_WT/.project/TEST-GUIDE.md`가 남아 있으면 **그 경로를 대신 넘기고**, 메인은 사용자에게 `TEST_RULE.local.md`로의 이행을 1회 제안한다.
|
|
171
|
-
- `<ABSOLUTE_PATH_TO_TEST_PLAN_ORIGIN_MD>` 자리에 `.project/tasks/<NNN_slug>/<NNN>_<slug>_test-plan-origin.md`(출제 분리 태스크의 B 원문 — task-plan Step 5-B가 생성)의 절대 경로 삽입. **파일이 없으면 그 줄 자체를 prompt에서 제외**한다 (분리 비적용 태스크 — 룰 18 자체가 발동하지 않음).
|
|
172
|
-
- **메인 측 원복 안전망 (룰 19)**: 격리 세션 기동 *직전* 워크트리 스냅샷을 뜬다 — ① `git -C "$WT_PATH" diff` 출력 해시 ② `git -C "$WT_PATH" status --porcelain -uall` 목록 ③ 미추적 파일 각각의 내용 해시. 리턴 *직후* 같은 방식으로 재계산해 대조하고, 불일치(격리 세션의 되돌림 미원복·잔재) 시 사용자 보고. ①만으로는 부족하다 — task-dev 시점 변경분은 미커밋이라 *신규 파일*이 `git diff`에 안 잡힌다(②③까지 합산해야 원복 실패를 잡는다).
|
|
173
|
-
- Task tool의 `subagent_type`: `general-purpose` (도구 풀 다 필요).
|
|
174
|
-
- Task tool의 `description`: `Isolated test for TASK-<NNN>`.
|
|
175
|
-
- **코덱스 spawn (플랫폼 패리티)**: 코덱스에선 `.codex/agents/task-tester.toml`의 `task-tester` 서브에이전트로 spawn하되, *위 펜스 전체를 task prompt로 그대로 전달*한다 — 펜스가 양 플랫폼 공통 단일 룰 소스다(클로드 = `general-purpose` + 펜스 / 코덱스 = `task-tester` + 펜스, 동일 효과). `task-tester`의 `developer_instructions`는 같은 룰의 코덱스 기준선 미러 — 본 펜스의 수행 룰을 바꾸면 그 `developer_instructions`도 함께 갱신한다.
|
|
176
|
-
|
|
177
|
-
### Step 4 — 결과 리턴 + Result 섹션 기록
|
|
178
|
-
|
|
179
|
-
격리 세션 리턴 결과를 `## Result` 섹션의 *테스트* 부분에 기록:
|
|
180
|
-
|
|
181
|
-
```markdown
|
|
182
|
-
## Result
|
|
183
|
-
|
|
184
|
-
### 진행
|
|
185
|
-
(`/task-dev`에서 작성된 그대로)
|
|
186
|
-
|
|
187
|
-
### 테스트 (격리 세션 결과)
|
|
188
|
-
- **<PASS / FAIL / UNCERTAIN>**.
|
|
189
|
-
- 시나리오 <N>개 중 PASS <X>개 / FAIL <Y>개 / UNCERTAIN <Z>개.
|
|
190
|
-
- 검증 명령 (린트/타입/빌드/테스트) 모두 PASS.
|
|
191
|
-
- 근거:
|
|
192
|
-
- <격리 세션 표 인용 — 핵심 시나리오 + 증거>
|
|
193
|
-
- <검증 명령 출력 인용>
|
|
194
|
-
|
|
195
|
-
(FAIL / UNCERTAIN 시) 실패 상세:
|
|
196
|
-
- <시나리오 N: 무엇이 깨졌는지 + 로그 인용>
|
|
197
|
-
```
|
|
198
|
-
|
|
199
|
-
### Step 5 — PASS / FAIL / UNCERTAIN 분기
|
|
200
|
-
|
|
201
|
-
격리 세션 종합 판정에 따라 분기.
|
|
202
|
-
|
|
203
|
-
#### PASS 분기
|
|
204
|
-
|
|
205
|
-
1. `set_status` 도구로 `tested` 전이 (또는 `npx @angar2/taskery set-status TASK-<NNN> tested`) — PASS 전이 (유효전이 코드 검증).
|
|
206
|
-
2. 결과 보고:
|
|
207
|
-
```
|
|
208
|
-
✅ TASK-<NNN> 격리 검증 PASS
|
|
209
|
-
- 시나리오 <N>개 모두 PASS
|
|
210
|
-
- 검증 명령 모두 PASS
|
|
211
|
-
- 상태: testing → tested
|
|
212
|
-
- 다음: /task-close TASK-<NNN> 으로 git 마무리
|
|
213
|
-
```
|
|
214
|
-
|
|
215
|
-
#### FAIL 분기
|
|
216
|
-
|
|
217
|
-
1. status는 `testing` 그대로 (자체 전환 X — 사용자 판단 필요).
|
|
218
|
-
2. 사용자에게 보고:
|
|
219
|
-
```
|
|
220
|
-
❌ TASK-<NNN> 격리 검증 FAIL
|
|
221
|
-
- 실패 시나리오: <목록>
|
|
222
|
-
- 근거: <로그 / 응답 인용>
|
|
223
|
-
|
|
224
|
-
어떻게 할까?
|
|
225
|
-
1. "고쳐" — 메인이 status를 developing으로 되돌림 + /task-dev 재진입
|
|
226
|
-
2. "OK 마무리" — 실패 알면서 /task-close 진행 (위험: 알려진 결함 채로 closed)
|
|
227
|
-
```
|
|
228
|
-
3. 사용자 *"고쳐"* → `set_status` 도구로 `developing` 전이(또는 `npx @angar2/taskery set-status TASK-<NNN> developing`) + `/task-dev` 안내. 사용자 *"OK 마무리"* → `set_status`로 `tested` 전이 (Result 섹션에 *"알려진 결함 있음"* 명시) + `/task-close` 안내.
|
|
229
|
-
4. **시각 어긋남 FAIL의 경우** — 격리 세션이 준 *어긋남 목록*을 그대로 보고에 실어, 사용자 *"고쳐"* 시 `/task-dev`가 그 목록을 **한 번에 배치로** 수정하도록 안내(흠을 사용자가 직접 찾지 않음 — test가 찾아줌). **재검사 라운드 상한 = 3회** (기본값, 프로젝트별 조정 가능): dev↔test를 3회 돌고도 어긋남이 남으면 멈추고 *현 상태 + 남은 어긋남*을 사용자에게 보고해 판단을 받는다. (전이는 매 라운드 사용자 *"고쳐"* 발화로 진행 — 무인 자동 루프 아님.)
|
|
230
|
-
|
|
231
|
-
#### UNCERTAIN(검증 불가) 분기 — 시험문제 결함 → Test Plan 보수
|
|
232
|
-
|
|
233
|
-
격리 세션이 `[AUTO]` 시나리오인데 *대조할 기대값을 구성하지 못함*(시험문제 결함)을 보고한 경우. 코드 결함이 아니라 *시험문제* 결함이므로 `/task-dev`(코드 수정)가 아니라 `/task-plan`(Test Plan 보수)으로 간다.
|
|
234
|
-
|
|
235
|
-
1. status는 `testing` 그대로 유지 (코드는 멀쩡 — 되돌리지 않음).
|
|
236
|
-
2. 사용자에게 보고:
|
|
237
|
-
```
|
|
238
|
-
⚠️ TASK-<NNN> 격리 검증 — 시험문제 결함 (검증 불가)
|
|
239
|
-
- 결함 시나리오: <목록 + 무엇을 시도했고 왜 기대값 구성 불가인지>
|
|
240
|
-
- 코드 결함 아님 — 구현은 보존됨.
|
|
241
|
-
|
|
242
|
-
→ /task-plan 으로 Test Plan만 보수 (이 시나리오를 [실행 명령 + 구체적 기대값]으로 다시 작성) → 보수 후 /task-test 재실행
|
|
243
|
-
```
|
|
244
|
-
3. `/task-plan`은 *Test Plan 섹션만* 보수 (Requirements / Scope / Dev Plan / 코드 보존). 보수 후 `/task-test` 재실행 (코드 미변경이므로 `/task-dev` 재실행 없음). status는 `testing` 유지.
|
|
245
|
-
4. **"시험지 오염" 라벨(룰 18)인 경우** — Test Plan 보수가 아니라 **메인이 origin(`<NNN>_<slug>_test-plan-origin.md`) 기준으로 task.md Test Plan을 복원**한 후 `/task-test` 재실행. 사용자 보고에 귀책을 명시한다: 오염 칸에 플래그 有 → A 수정 귀책 / 결함이 origin 그대로의 칸이면 → B 출제 품질 (원안의 사후 귀책 평가). 무플래그 오염은 발생 자체가 규약 위반이므로 경위를 함께 보고한다.
|
|
246
|
-
|
|
247
|
-
#### UNCERTAIN(실행 보류) 분기 — 환경 제약 → 승인 또는 격리 경로
|
|
248
|
-
|
|
249
|
-
격리 세션이 화면·입력 점유(룰 17)를 이유로 실행하지 않은 시나리오를 보고한 경우. 코드 결함도 시험문제 결함도 아니므로 `/task-dev`·`/task-plan` 어느 쪽으로도 보내지 않는다.
|
|
250
|
-
|
|
251
|
-
1. status는 `testing` 그대로 유지 (코드·시험문제 모두 멀쩡).
|
|
252
|
-
2. 사용자에게 보고 + 선택지 제시:
|
|
253
|
-
```
|
|
254
|
-
⏸ TASK-<NNN> 격리 검증 — 실행 보류 (환경 제약)
|
|
255
|
-
- 보류 시나리오: <목록 + 어느 스위트가 무엇을 점유하는지 + 예상 소요>
|
|
256
|
-
- 비점유 부분 결과: <이미 실행한 범위의 PASS/FAIL>
|
|
257
|
-
|
|
258
|
-
어떻게 할까?
|
|
259
|
-
1. "지금 돌려" — 승인받아 실행 (그동안 화면·마우스·키보드를 사용할 수 없음)
|
|
260
|
-
2. "나중에" — 자리를 비울 때 실행하도록 보류 유지
|
|
261
|
-
3. "격리 경로 만들자" — 창 숨김·헤드리스 / 컨테이너 / VM / CI 중 하나를 마련 후 재검증 (다음 task부터 승인 없이 자동 실행됨)
|
|
262
|
-
4. "보류인 채로 마무리해" — 미검증 영역으로 명시하고 tested 전이 (위험: 이 영역은 검증 안 된 채 closed)
|
|
263
|
-
```
|
|
264
|
-
단, `TEST_RULE.local.md` *테스트 실행 환경* 절에 *"없음 — 매번 승인(사용자 결정 …)"*이 이미 기록돼 있으면 선택지 3("격리 경로 만들자")을 새 제안처럼 내지 않는다 — 이미 내린 결정이다. 승인 여부(1·2·4)만 묻는다.
|
|
265
|
-
3. 사용자 응답별 처리:
|
|
266
|
-
- **"지금 돌려"** → 승인받았으므로 점유 스위트를 실행하고, 그 결과로 PASS / FAIL 분기를 따른다.
|
|
267
|
-
- **"나중에"** → 보류 유지. status는 `testing` 그대로 두고 **여기서 멈춘다** (`/task-close`로 넘어가지 않는다 — close는 `tested`가 아니면 `blocked:'status'`로 차단된다). 사용자가 자리를 비운 뒤 *"이제 돌려"* 하면 위 "지금 돌려"로 재개.
|
|
268
|
-
- **"격리 경로 만들자"** → 경로(창 숨김·헤드리스 / 컨테이너 / VM / CI)를 마련하고 `TEST_RULE.local.md` *테스트 실행 환경* 절에 기록한 뒤 `/task-test` 재실행. 다음 task부터는 승인 없이 자동 실행된다.
|
|
269
|
-
- **"보류인 채로 마무리해"** (알려진 미검증 감수) → FAIL 분기의 *"OK 마무리"*와 동일 처리 — `set_status` 도구로 `tested` 전이(또는 `npx @angar2/taskery set-status TASK-<NNN> tested`) + Result 섹션에 *"미검증 영역: <보류 시나리오> — 사유: 화면·입력 점유, 사용자 판단으로 미실행"* 명시 후 `/task-close` 안내.
|
|
270
|
-
4. **묵묵히 PASS 처리 금지** — 어느 경로로 가든 보류된 시나리오는 Result에 *미검증 영역*으로 남긴다. 실행하지 않은 것을 통과로 적지 않는다.
|
|
271
|
-
|
|
272
|
-
#### UNCERTAIN(사람 검수) 분기 (USER 검수 흐름)
|
|
273
|
-
|
|
274
|
-
격리 세션이 `[USER]` 시나리오(정답지가 *주관*인 영역 — 시각 미세 취향 / UX 느낌) 발견 시. **자동 PASS 전이 X — 사용자 직접 검수 PASS 받은 후에만 `tested` 전이**. (시각 *객관* 깨짐은 여기 아니라 FAIL — 격리 세션이 캡처-목업 대조로 이미 잡음.)
|
|
275
|
-
|
|
276
|
-
> **검수 서버 먼저 기동** (`## 검수 실행 명령` 선언 + 시각/UI 검수 항목 포함 시): 체크리스트를 제시하기 *전에* 서버를 백그라운드 기동(포트 = 기준 포트 + TASK번호)하고 접속 URL을 함께 제공한다 — 사용자가 실제 화면을 보며 ✓/✗ 검수하도록. 격리 세션이 기능상 이미 띄웠으면 재사용. 사용자 *"안 띄워도 돼"* 시 생략. 기동 전 포트·프로세스 확인 + 종료 시 자식까지 정리. 상세: GIT_RULE "멀티세션 검수 환경".
|
|
277
|
-
|
|
278
|
-
1. 메인이 사용자에게 *체크리스트 형식*으로 항목 보고 (stash FRICTION_LOG #14+19 반영):
|
|
279
|
-
|
|
280
|
-
```
|
|
281
|
-
USER 검수 — N 항목 (목업 기준: <mockup path — 있을 시>)
|
|
282
|
-
|
|
283
|
-
[ ] <시나리오 1>
|
|
284
|
-
[ ] <시나리오 2 (목업 §X 참조)>
|
|
285
|
-
...
|
|
286
|
-
|
|
287
|
-
각 항목 ✓/✗ 응답
|
|
288
|
-
```
|
|
289
|
-
|
|
290
|
-
**검수 항목 작성 규칙 (recordion FRICTION 2026-08-05 반영)**:
|
|
291
|
-
|
|
292
|
-
- 각 항목은 **① 왜 이 검수가 필요한지 → ② 화면 어디를 어떻게 조작하는지 → ③ 무엇이 보이면 정상이고 무엇이 문제인지** 세 요소를 모두 담는다. 하나라도 빠지면 사용자가 무엇을 봐야 할지 알 수 없다.
|
|
293
|
-
- **평이한 말로 쓴다** — 축약어·세션 내부 용어·task 진행 중에만 통하던 지칭(*"아까 그 화면"*, *"Phase 2 결과물"*) 금지. 이 프로젝트를 처음 보는 사람이 읽어도 따라 할 수 있어야 한다.
|
|
294
|
-
- **필요한 재료는 세션이 찾아서 제공한다** — 토큰·경로·테스트 계정·샘플 파일 등이 필요하면 *"네 것을 넣어라"* 대신 **리포에서 찾아 값 또는 정확한 위치를 함께 준다**. 사용자에게 찾게 만들지 않는다.
|
|
295
|
-
|
|
296
|
-
예:
|
|
297
|
-
- ❌ `[ ] popover 토글 동작 확인`
|
|
298
|
-
- ✅ `[ ] 메뉴바 아이콘을 클릭하면 목록 창이 열리는지 — 창이 뜨고 항목이 세로로 나열되면 정상. 창이 안 뜨거나 항목이 겹쳐 보이면 문제.`
|
|
299
|
-
|
|
300
|
-
2. **시각 영역 fix 사이클 사전 예고** — 시각 영역 항목 있으면 *"시각 영역은 한 사이클로 100% 일치 보장 X. fix 사이클 1~2회 예상. ✗ 발견 시 정상."* 안내. 사용자 기대치 사전 정렬, 부정 반응 누적 방지.
|
|
301
|
-
3. **사용자가 스크린샷·산출물을 주면 체크리스트 전 항목과 1:1 대조** — 사용자가 물은 항목만 답하지 않는다. 받은 증거를 검수 항목 전체와 하나씩 맞춰 보고, 사용자가 언급하지 않은 어긋남도 먼저 지목한다 (stash FRICTION 2026-07-29 — 첫 스크린샷에 이미 찍혀 있던 결함을 세션이 짚지 못해 발견이 한 사이클 늦었다).
|
|
302
|
-
4. 사용자 응답 받음:
|
|
303
|
-
- 모두 ✓ → PASS 분기로 (`tested` 전이).
|
|
304
|
-
- ✗ 1개 이상 → FAIL 분기로 (`developing` 회귀 + ✗ 항목별 fix).
|
|
305
|
-
|
|
306
|
-
### Step 6 — 결과 보고 (위 분기별 메시지)
|
|
307
|
-
|
|
308
|
-
### Step 7 — 검수 서버 기동 (PASS 후 세션 종료·해당 시)
|
|
309
|
-
|
|
310
|
-
**조건**: ① 종합 판정 PASS + 이번 세션이 여기서 멈추고 사용자에게 제어를 넘김(= `/task-close`로 바로 진행하지 않음) + ② `AGENTS.md`에 `## 검수 실행 명령`이 선언됨.
|
|
311
|
-
|
|
312
|
-
- 두 조건 충족 시 — 그 명령으로 서버를 *백그라운드* 기동(포트 = 기준 포트 + TASK번호) + 접속 URL 보고. 모바일 검수가 필요하다고 판단되면 터널도 기동.
|
|
313
|
-
- 격리 세션 검증이 *기능상* 이미 서버를 띄워 둔 경우 — 죽였다 다시 띄우지 말고 그대로 두고 URL만 보고.
|
|
314
|
-
- **FAIL → 수정 흐름에서는 기동하지 않는다** (수정하러 가는 단계라 검수 무의미). **UNCERTAIN 검수는 Step 5에서 이미 기동**했으므로 여기서 중복 기동 X.
|
|
315
|
-
- `## 검수 실행 명령` 미선언 또는 사용자 *"안 띄워도 돼"* 발화 시 생략. 상세: GIT_RULE "멀티세션 검수 환경".
|
|
316
|
-
- **기동 전 포트·프로세스 확인 + 종료 시 자식까지 정리** — `Port … is in use` 류 경고는 이미 떠 있다는 뜻이므로 재기동하지 않는다 (GIT_RULE "멀티세션 검수 환경" 참조).
|
|
317
|
-
|
|
318
|
-
## 도구 가이드
|
|
319
|
-
|
|
320
|
-
- **Read**: task 파일 / `## Test Plan` + `## Dev Plan` 정독
|
|
321
|
-
- **Edit**: Result 섹션 기록
|
|
322
|
-
- **Bash / 도구**: `set_status` 도구(또는 `npx @angar2/taskery set-status`) status 전이 (유효전이 코드 검증)
|
|
323
|
-
- **Task tool**: 격리 세션 호출 (Step 3 prompt 사용)
|
|
324
|
-
- **AskUserQuestion**: FAIL/UNCERTAIN 시 사용자 판단 받기
|
|
325
|
-
|
|
326
|
-
## 주의사항
|
|
327
|
-
|
|
328
|
-
- **격리 세션이 코드 수정하면 안 됨** — prompt에 *"코드 파일 직접 수정 절대 금지"* 명시되어 있지만 한 번 더 결과 검토 시 코드 변경 흔적 있으면 사용자에게 보고.
|
|
329
|
-
- **메인이 시나리오 임의 추가 X** — `## Test Plan`에 명시된 것만 격리 세션이 수행. 진행 중 *"이것도 같이 검증하자"* 떠오르면 task.md `## Test Plan` Edit 후 재호출.
|
|
330
|
-
- **자기완결성 검증 먼저** — Step 1에서 Test Plan이 *"위에서 만든 X"* 같은 메인 컨텍스트 의존 표현 있으면 격리 세션이 헤맴. 보강 후 재시도.
|
|
331
|
-
- **PASS 자체 판정 X** — 메인이 *"잘 됐을 듯"* 판정하지 X. 격리 세션 결과만 신뢰.
|
|
332
|
-
- **임시 파일 정리** — 격리 세션이 만든 Playwright 스크립트 / 임시 데이터 종료 시 삭제. 코드베이스 오염 X.
|
|
333
|
-
- **사용자검수 시나리오는 자동화 못 잡음** — UI 미세 취향 / UX 느낌 / 외부 결제 등 *정답지가 주관*인 것만 UNCERTAIN(사람 검수)으로 가야 정상. PASS 강제 X. **단 시각 *객관* 깨짐(요소 빠짐 / 빈 화면 / 배치 딴판 / 색 완전히 틀림)은 사람 검수가 아니라 격리 세션이 캡처-목업 대조로 직접 잡아 FAIL** — 사용자에게 흠 사냥을 떠넘기지 않는다.
|
|
334
|
-
- **FAIL → developing 자동 되돌림 X** — 사용자 *"고쳐"* 답 받기 전 status 갱신 금지. *대화로 OK = 자동 전이* 룰의 핵심.
|
|
335
|
-
- **테스트 후 plumbing fix 발견 시** — 격리 PASS 후에도 plumbing(빌드 산출물 정리, 설정 수정 등) fix 필요할 수 있음. 분기:
|
|
336
|
-
- 검증 명령 *동작 자체에 영향 X* (예: 산출물 위치 정리, 주석 수정) → 메인 자체 재검증 OK. **재실행 범위는 변경에 비례** — 린트·타입체크 + *변경이 닿는 테스트*만. 전체 스위트 재실행은 불필요하다 (`/task-dev` Step 6.5 "수정 루프 국면" 참조)
|
|
337
|
-
- 검증 명령 *동작 변경* (예: build 명령 자체 변경, 새 검증 명령 추가, 환경 변수 추가) → **격리 세션 재호출 필수** (환경 변경으로 격리 가정 무효화 — 재검증 가치 사라짐)
|
|
338
|
-
|
|
339
|
-
## 상태 전이
|
|
340
|
-
|
|
341
|
-
| 진입 시 | 종료 시 | 트리거 |
|
|
342
|
-
|--------|--------|--------|
|
|
343
|
-
| `developed` | `tested` | PASS |
|
|
344
|
-
| `developed` | `developing` | FAIL (코드 결함) + 사용자 *"고쳐"* |
|
|
345
|
-
| `developed` | `tested` | FAIL + 사용자 *"OK 마무리"* (알려진 결함 명시) |
|
|
346
|
-
| `developed` / `testing` | `testing` (유지) | UNCERTAIN(사람 검수) — 사용자 직접 검수 대기 |
|
|
347
|
-
| `developed` / `testing` | `testing` (유지) | UNCERTAIN(검증 불가, 시험문제 결함) → `/task-plan`으로 Test Plan 보수 → `/task-test` 재실행 (코드·status 보존) |
|
|
348
|
-
| `developed` / `testing` | `testing` (유지) | UNCERTAIN(실행 보류, 환경 제약) → 사용자 승인 실행 / *"나중에"* 보류 / 격리 실행 경로 마련 후 재검증 (코드·시험문제 모두 보존) |
|
|
349
|
-
| `testing` | `tested` | UNCERTAIN(실행 보류) + 사용자 *"보류인 채로 마무리해"* — Result에 미검증 영역 명시 |
|
|
350
|
-
| `testing` (이어가기) | 동일 분기 | — |
|
|
351
|
-
|
|
352
|
-
> **네 갈래 요약**: PASS → `tested` / 코드 결함 → `developing`(사용자 *"고쳐"*) / 시험문제 결함 → Test Plan 보수(`task-plan`, 코드·status 보존) → 재검사 / 환경 제약(실행 보류) → 사용자 승인 실행 또는 격리 실행 경로 마련 후 재검증. UNCERTAIN(사람 검수)은 검수 ✓ 받으면 `tested`, ✗면 `developing`.
|
|
33
|
+
- `test-scenario`
|
package/bin/close.js
DELETED
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
// task close 결정적 준비 CLI — Phase 커밋·status=closed·flows/문서 커밋·추적마커 (비가역 머지/정리는 스킬)
|
|
3
|
-
/**
|
|
4
|
-
* bin/close.js
|
|
5
|
-
* `npx @angar2/taskery close <TASK-NNN>` — close 결정적 준비.
|
|
6
|
-
*
|
|
7
|
-
* 게이트(status=tested) → Phase 커밋(D2 자동 매핑) → status=closed → flows/문서 커밋 → 추적마커까지
|
|
8
|
-
* 코드가 수행하고 멈춘다. 이후 비가역(사전 rebase+충돌해결 / 머지 락 / 부모 --no-ff 머지 /
|
|
9
|
-
* worktree remove / branch -d)은 스킬(task-close)이 git-guard hook + 복구출력 보호 하에 수행.
|
|
10
|
-
*
|
|
11
|
-
* stdout: { prepped, branch, parent, wtPath, registered, commits, aheadOfParent, changelog }. parent = 머지 대상. exit 0.
|
|
12
|
-
* 콜백(스킬이 LLM 판단 후 처리):
|
|
13
|
-
* - exit 3 + { blocked:'status', current } — status가 tested 아님 (게이트 차단)
|
|
14
|
-
* - exit 2 + { blocked:'mapping', files, phases, reason } — Phase↔파일 매핑 모호 (수동 커밋 필요)
|
|
15
|
-
* - exit 4 + { blocked:'docs', missing } — PLAN 체크·수정이력 누락 (문서 채운 후 그대로 재호출)
|
|
16
|
-
* 그 외 실패 시 stderr + exit 1.
|
|
17
|
-
*/
|
|
18
|
-
|
|
19
|
-
const path = require('path');
|
|
20
|
-
|
|
21
|
-
const {
|
|
22
|
-
MANIFEST_NAME,
|
|
23
|
-
readManifest,
|
|
24
|
-
getMainWorktreePath,
|
|
25
|
-
closeTask,
|
|
26
|
-
} = require('./lib');
|
|
27
|
-
|
|
28
|
-
async function main() {
|
|
29
|
-
const arg = process.argv[2];
|
|
30
|
-
const m = String(arg || '').match(/(\d+)/);
|
|
31
|
-
if (!m) {
|
|
32
|
-
console.error('사용법: npx @angar2/taskery close <TASK-NNN>');
|
|
33
|
-
process.exit(1);
|
|
34
|
-
}
|
|
35
|
-
const taskNum = parseInt(m[1], 10);
|
|
36
|
-
|
|
37
|
-
let mainWt;
|
|
38
|
-
try {
|
|
39
|
-
mainWt = getMainWorktreePath();
|
|
40
|
-
} catch (e) {
|
|
41
|
-
console.error(`taskery close 실패: ${e.message}`);
|
|
42
|
-
process.exit(1);
|
|
43
|
-
}
|
|
44
|
-
if (!readManifest(path.join(mainWt, MANIFEST_NAME))) {
|
|
45
|
-
console.error(`${MANIFEST_NAME} 없음 — 'npx @angar2/taskery init' 먼저 실행 필요.`);
|
|
46
|
-
process.exit(1);
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
let result;
|
|
50
|
-
try {
|
|
51
|
-
result = await closeTask(mainWt, { taskNum });
|
|
52
|
-
} catch (e) {
|
|
53
|
-
console.error(`taskery close 실패: ${e.message}`);
|
|
54
|
-
process.exit(1);
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
if (result.blocked === 'status') {
|
|
58
|
-
console.error(
|
|
59
|
-
`close 게이트 차단 — status=${result.current} (tested 아님). /task-test 통과 후 재호출.`,
|
|
60
|
-
);
|
|
61
|
-
process.stdout.write(JSON.stringify(result) + '\n');
|
|
62
|
-
process.exit(3);
|
|
63
|
-
}
|
|
64
|
-
if (result.blocked === 'docs') {
|
|
65
|
-
console.error(`문서 게이트 차단 — 아래 문서에 TASK 표기 누락. 채운 후 그대로 재호출(변이 없음).`);
|
|
66
|
-
for (const miss of result.missing) {
|
|
67
|
-
console.error(` - [${miss.kind === 'plan' ? 'PLAN 체크리스트' : '수정 이력'}] ${miss.file}`);
|
|
68
|
-
}
|
|
69
|
-
process.stdout.write(JSON.stringify(result) + '\n');
|
|
70
|
-
process.exit(4);
|
|
71
|
-
}
|
|
72
|
-
if (result.blocked === 'mapping') {
|
|
73
|
-
console.error(
|
|
74
|
-
`Phase↔파일 매핑 모호 (${result.reason}) — Dev Plan '파일' 필드 확인 후 수동 Phase 커밋 필요.`,
|
|
75
|
-
);
|
|
76
|
-
console.error(
|
|
77
|
-
`미매핑 파일이 Dev Plan에 적혀 있다면 '- 파일:' 표기 형식(쉼표/가운뎃점/들여쓴 목록)을 확인 — 줄 전체가 경로 하나로 읽혔을 수 있습니다.`,
|
|
78
|
-
);
|
|
79
|
-
process.stdout.write(JSON.stringify(result) + '\n');
|
|
80
|
-
process.exit(2);
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
process.stdout.write(JSON.stringify(result) + '\n');
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
main();
|
package/bin/fork.js
DELETED
|
@@ -1,112 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
/**
|
|
3
|
-
* bin/fork.js
|
|
4
|
-
* `npx @angar2/taskery fork <type> <dev> <src> <slug> [--size <s> --title "<t>" --promote]` — task 분기.
|
|
5
|
-
*
|
|
6
|
-
* [채번 → 워크트리·브랜치 생성]을 init 락으로 원자 실행 (병렬 task-init 번호 충돌 차단).
|
|
7
|
-
* --size·--title 주면 fork 직후 §1.3 빈 골격 task.md도 코드가 자동 생성(C1, 생성일·status=draft 자동).
|
|
8
|
-
* 성공 시 결과 JSON 한 줄을 stdout으로 출력 ({ taskNum, nnn, branch, wtPath, projectId, [docPath, registered, promoted | scaffoldError] }).
|
|
9
|
-
* 실패(정책 위배 / 동일 항목 진행중 / 동일 브랜치명 등) 시 stderr + exit 1.
|
|
10
|
-
* 골격 생성 실패는 워크트리 생성을 무효화하지 않음 — exit 0 + scaffoldError로 보고(스킬이 폴백 Write).
|
|
11
|
-
*
|
|
12
|
-
* 호출 주체: `/task-init` Step 6 (사용자 직접 호출도 가능하나 통상 스킬 경유).
|
|
13
|
-
*/
|
|
14
|
-
|
|
15
|
-
const path = require('path');
|
|
16
|
-
|
|
17
|
-
const {
|
|
18
|
-
MANIFEST_NAME,
|
|
19
|
-
readManifest,
|
|
20
|
-
getMainWorktreePath,
|
|
21
|
-
forkTask,
|
|
22
|
-
scaffoldTaskDoc,
|
|
23
|
-
} = require('./lib');
|
|
24
|
-
|
|
25
|
-
const VALID_TYPES = ['feature', 'bug', 'improve', 'refactor', 'docs', 'chore'];
|
|
26
|
-
const VALID_SIZES = ['micro', 'small', 'medium', 'large'];
|
|
27
|
-
|
|
28
|
-
async function main() {
|
|
29
|
-
// 위치 인자 4개 + 플래그(--size <s> / --title "<t>" / --promote).
|
|
30
|
-
const argv = process.argv.slice(2);
|
|
31
|
-
const positional = [];
|
|
32
|
-
const opts = {};
|
|
33
|
-
for (let i = 0; i < argv.length; i++) {
|
|
34
|
-
const a = argv[i];
|
|
35
|
-
if (a === '--promote') {
|
|
36
|
-
opts.promote = true;
|
|
37
|
-
} else if (a.startsWith('--')) {
|
|
38
|
-
opts[a.slice(2)] = argv[++i];
|
|
39
|
-
} else {
|
|
40
|
-
positional.push(a);
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
const [type, dev, src, slug] = positional;
|
|
44
|
-
|
|
45
|
-
if (!type || !dev || !src || !slug) {
|
|
46
|
-
console.error(
|
|
47
|
-
'사용법: npx @angar2/taskery fork <type> <dev> <src> <slug> [--size <s> --title "<제목>" --promote]',
|
|
48
|
-
);
|
|
49
|
-
console.error('예: npx @angar2/taskery fork feature claude BL-003 login --size medium --title "로그인 기능"');
|
|
50
|
-
process.exit(1);
|
|
51
|
-
}
|
|
52
|
-
if (opts.size && !VALID_SIZES.includes(opts.size)) {
|
|
53
|
-
console.error(`--size는 ${VALID_SIZES.join(' | ')} 중 하나 (받음: ${opts.size})`);
|
|
54
|
-
process.exit(1);
|
|
55
|
-
}
|
|
56
|
-
if (!VALID_TYPES.includes(type)) {
|
|
57
|
-
console.error(`type은 ${VALID_TYPES.join(' | ')} 중 하나 (받음: ${type})`);
|
|
58
|
-
process.exit(1);
|
|
59
|
-
}
|
|
60
|
-
// ST-N = 로드맵 Stage 출처 (ROADMAP은 Stage 단위·RM 채번 없음 — recordion FRICTION 2026-08-03 반영).
|
|
61
|
-
// RM-NNN은 구형 호환으로 계속 수용.
|
|
62
|
-
if (!/^(BL-\d+|RM-\d+|ST-\d+|DR)$/.test(src)) {
|
|
63
|
-
console.error(`src는 BL-NNN | ST-N(로드맵 Stage) | DR 형식 (받음: ${src}. 구형 RM-NNN도 호환)`);
|
|
64
|
-
process.exit(1);
|
|
65
|
-
}
|
|
66
|
-
if (!/^[a-z0-9]+(-[a-z0-9]+)*$/.test(slug)) {
|
|
67
|
-
console.error(`slug은 영어 kebab-case (받음: ${slug})`);
|
|
68
|
-
process.exit(1);
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
let mainWt;
|
|
72
|
-
try {
|
|
73
|
-
mainWt = getMainWorktreePath();
|
|
74
|
-
} catch (e) {
|
|
75
|
-
console.error(`taskery fork 실패: ${e.message}`);
|
|
76
|
-
process.exit(1);
|
|
77
|
-
}
|
|
78
|
-
if (!readManifest(path.join(mainWt, MANIFEST_NAME))) {
|
|
79
|
-
console.error(`${MANIFEST_NAME} 없음 — 'npx @angar2/taskery init' 먼저 실행 필요.`);
|
|
80
|
-
process.exit(1);
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
let result;
|
|
84
|
-
try {
|
|
85
|
-
result = await forkTask(mainWt, { type, dev, src, slug });
|
|
86
|
-
} catch (e) {
|
|
87
|
-
console.error(`taskery fork 실패: ${e.message}`);
|
|
88
|
-
process.exit(1);
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
// 골격 자동 생성 (--size·--title 제공 시). 워크트리는 이미 생성됐으므로 실패해도 exit 1 X.
|
|
92
|
-
let out = result;
|
|
93
|
-
if (opts.size && opts.title) {
|
|
94
|
-
try {
|
|
95
|
-
const doc = scaffoldTaskDoc(mainWt, result.wtPath, {
|
|
96
|
-
taskNum: result.taskNum,
|
|
97
|
-
slug,
|
|
98
|
-
title: opts.title,
|
|
99
|
-
type,
|
|
100
|
-
size: opts.size,
|
|
101
|
-
parent: result.parent,
|
|
102
|
-
promoted: !!opts.promote,
|
|
103
|
-
});
|
|
104
|
-
out = { ...result, docPath: doc.file, registered: doc.registered, promoted: doc.promoted };
|
|
105
|
-
} catch (e) {
|
|
106
|
-
out = { ...result, scaffoldError: e.message };
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
process.stdout.write(JSON.stringify(out) + '\n');
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
main();
|