@simplysm/sd-claude 14.0.66 → 14.0.68

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.
Files changed (25) hide show
  1. package/claude/references/sd-simplysm14/manuals/client-component.md +1 -0
  2. package/claude/rules/sd-base-rules.md +20 -1
  3. package/claude/scripts/sd_paths.py +22 -0
  4. package/claude/sd-check-bash.py +14 -0
  5. package/claude/skills/sd-commit/SKILL.md +1 -0
  6. package/claude/skills/sd-demo/SKILL.md +37 -15
  7. package/claude/skills/sd-impl/SKILL.md +102 -78
  8. package/claude/skills/sd-impl/evals/fixtures/case-001-new-screen/spec.md +55 -0
  9. package/claude/skills/sd-impl/evals/fixtures/case-002-auto-process/spec.md +55 -0
  10. package/claude/skills/sd-impl/evals/fixtures/case-003-update-screen/packages/client/src/pages/book-list.ts +22 -0
  11. package/claude/skills/sd-impl/evals/fixtures/case-003-update-screen/spec.md +57 -0
  12. package/claude/skills/sd-impl/evals/fixtures/case-004-ambiguous-spec/spec.md +58 -0
  13. package/claude/skills/sd-impl/evals/fixtures/case-005-id-mismatch/spec.md +52 -0
  14. package/claude/skills/sd-impl/evals/fixtures/case-006-with-reference-units/packages/client/src/pages//352/261/260/353/236/230/354/262/230//352/261/260/353/236/230/354/262/230-/353/252/251/353/241/235.test.ts +10 -0
  15. package/claude/skills/sd-impl/evals/fixtures/case-006-with-reference-units/packages/client/src/pages//352/261/260/353/236/230/354/262/230//352/261/260/353/236/230/354/262/230-/353/252/251/353/241/235.ts +11 -0
  16. package/claude/skills/sd-impl/evals/fixtures/case-006-with-reference-units/packages/server/src/data-access//352/261/260/353/236/230/354/262/230-/354/240/221/352/267/274.ts +12 -0
  17. package/claude/skills/sd-impl/evals/fixtures/case-006-with-reference-units/packages/server/src/models//352/261/260/353/236/230/354/262/230.ts +8 -0
  18. package/claude/skills/sd-impl/evals/fixtures/case-006-with-reference-units/spec.md +77 -0
  19. package/claude/skills/sd-impl/evals/golden.jsonl +6 -2
  20. package/claude/skills/sd-impl/references/spec-cross-check.md +82 -0
  21. package/claude/skills/sd-skill/SKILL.md +1 -1
  22. package/claude/skills/sd-skill/evals/golden.jsonl +1 -1
  23. package/claude/skills/sd-skill/references/eval-authoring.md +16 -0
  24. package/package.json +1 -1
  25. package/scripts/sd-entries.mjs +2 -2
@@ -528,6 +528,7 @@ async onSubmit(): Promise<void> {
528
528
  - 단, **숫자 셀은 `tx-right` 기본 적용** (수량·금액·단가·합계 등 숫자값 컬럼).
529
529
  - `[cell]="items()"` 는 타입 추론용 더미 — 실제 행 데이터는 `<sd-sheet>` 의 `[items]` 가 들고 있다.
530
530
  - 셀 컨텍스트: `let-item="item"` / `let-index="index"` / `let-depth="depth"` / `let-edit="edit"`.
531
+ - 셀 안 div 에 배경색 클래스(`bg-theme-*-lightest` 등)를 토글할 때는 빈 값 자리에 `&nbsp;` 등을 채워 div 가 셀 높이를 유지하게 한다. (table cell 자식 div 가 콘텐츠 없을 때 높이 0 → bg 가 셀에 차지 않음.)
531
532
 
532
533
  **list 안에서**: `<sd-crud-list>` 의 직속 자식으로 `<sd-sheet-column>` 을 두면 내부 시트로 자동 투영된다.
533
534
 
@@ -49,10 +49,14 @@ Claude 에이전트가 반드시 지켜야 할 행동 지침이다.
49
49
 
50
50
  - 점검 없이 "근거 없음" 결론 금지. 표면 검색 1회로 결론 X. 점검·검색 대상은 [결정 근거](#결정-근거) 섹션의 근거 채택 가능 자료.
51
51
  - 답을 주면 묻지 말고 진행.
52
+ - **자연 도출 자가 점검**: 결정 옵션을 던지기 전, "식·로직·기존 정의가 자연 도출하는 결과를 결정이라 부르고 있지 않은가" 자가 점검. 자연 도출이면 묻지 말고 그대로 진행.
53
+ - 나쁜 예: 부호로 자연 분기되는 케이스를 옵션 A/B/C 로 묶어 던지기 (식대로 자동 결정됨)
54
+ - 나쁜 예: 기존 정의에 이미 포함된 항목을 "추가 결정 필요" 로 던지기
52
55
  - 출력 직전 체크 (위반 시 출력 보류):
53
56
  - [ ] 선택지 중 정확히 1개에 `(추천)` 마커가 있는가
54
57
  - [ ] 응답 내 선택지 세트가 정확히 1개인가
55
58
  - [ ] [결정 근거](#결정-근거) 자료 점검을 충분히 했는가
59
+ - [ ] 자연 도출 가능 항목을 결정으로 포장하지 않았는가
56
60
 
57
61
  **진행 근거 인용**:
58
62
 
@@ -84,6 +88,11 @@ Claude 에이전트가 반드시 지켜야 할 행동 지침이다.
84
88
  - 시스템 내부 용어 회피.
85
89
  - 사람을 위한 간결하고 명확하게 응답.
86
90
  - 문서의 식별자(코드·약어·번호·라벨·§번호 등)만 노출 금지. 인용 시 식별자 옆에 실제 의미(이름·내용 요약)를 함께 표기해, 사용자가 원본을 펴보지 않아도 문장만으로 의미가 통해야 함. 응답·질문·산출물 모두 동일.
91
+ - 다음 표현은 그대로 단독 노출 금지 — 모두 도메인 어휘·시나리오로 풀어쓸 것:
92
+ - 수식·계산식 단독 (예: `(A − B) − C` 만 던지기) → 도메인 시나리오 예시 1건 (값 대입) 동반
93
+ - 영문 변수명·코드 식별자 (예: `surplus`, `isCompleted`, `joinSingle`) → 한국어 도메인 어휘로 풀이
94
+ - SQL/프레임워크/구현 용어 (예: "LEFT JOIN 깊이 1 자르기", "subagent 위탁") → 도메인 흐름으로 풀이
95
+ - 사용자가 "이해 못함"·"무슨 소리야" 류 피드백을 주면 같은 내용을 반복하지 말고 도메인 시나리오 예시로 다시 풀어쓸 것.
87
96
 
88
97
  질문·답변 프로토콜은 [질문/답변](#질문답변) 참조.
89
98
 
@@ -98,6 +107,13 @@ Claude 에이전트가 반드시 지켜야 할 행동 지침이다.
98
107
  - 본질 의도 불명확 시 추측 금지. 사용자에게 적극 질문.
99
108
  - 피드백 받을 때마다 자문: "이게 1회 사례인가, 일반 규칙인가?" → 1회면 굳히지 말 것.
100
109
 
110
+ **모호 표현 굳히기 금지** (자체 임의안 작성 시 적용):
111
+
112
+ - 사용자 답변 없이 자체 임의안을 산출물에 작성할 때, 추상 단어·추측 단어·미정의 외부 의존을 표현으로 박지 말 것.
113
+ - 나쁜 예: "기본값 = 시스템 설정값" (정의 없는 외부 의존), "필요 시 자동 처리" (조건 미정), "적절한 값" (구체 X)
114
+ - 좋은 예: "기본값 = 14일" (구체 값 + 사용자 확정 마커 부착)
115
+ - 임의안이면 구체 값 1개 + 결정 근거 출처 또는 사용자 확정 필요 마커 (`[OPEN]` 등) 부착.
116
+
101
117
  ## 문서 작성
102
118
 
103
119
  - **CRITICAL**: Claude 에이전트용 문서는 에이전트가 즉시 따를 수 있게 작성. 사람 가독성 기준 X.
@@ -108,6 +124,7 @@ Claude 에이전트가 반드시 지켜야 할 행동 지침이다.
108
124
  - **합의 누락 금지**: 확정된 모든 결정·근거·예외·단서는 즉시 산출물에 작성. ([결정 근거](#결정-근거))
109
125
  - "이 단계 범위 밖" / "템플릿에 자리 없음" 등을 이유로 누락 금지
110
126
  - 대화 메모리에만 두고 진행 금지. 후속 세션이 산출물만 읽어도 동일하게 이어갈 수 있어야 함.
127
+ - **상위 룰 중복 금지**: 자동 로드되는 상위 룰(예: `sd-base-rules.md`)에 이미 명시된 내용을 하위 지침 문서(`CLAUDE.md`·스킬 SKILL.md·참고 자료 등)에 다시 옮겨 적지 말 것. 하위 문서는 해당 스코프 고유 내용만 작성.
111
128
 
112
129
  ## ASCII 그림
113
130
 
@@ -133,13 +150,15 @@ Claude 에이전트가 반드시 지켜야 할 행동 지침이다.
133
150
  ## 분석 작업
134
151
 
135
152
  - `.back` 폴더 및 `.gitignore` 등재 경로는 코드베이스에서 배제. 명시 첨부 없이 읽거나 참고 금지.
136
- - 현재 워킹트리만 기준. 사용자 명시 지침 없이 과거 버전(git history 등) 읽지 말 것 (이미 폐기된 패턴을 답습하는 실수 방지).
153
+ - 현재 워킹트리만 기준. 사용자 명시 지침 없이 과거 버전 또는 변경분을 git 으로 조회하지 말 것 — `git status`·`diff`·`log`·`show`·`blame`·`reflog` 등 모든 조회 명령 포함. 워킹트리 파일·디렉터리 상태는 Read·Grep·Glob 으로만 확인 (이미 폐기된 패턴 답습 또는 변경분만 훑어 일관성 놓치는 실수 방지). Pre-tool 훅이 이들을 차단함.
154
+ - 사용자가 명시 지시한 경우에만 git 조회 가능. 이 때도 명령 prefix `$env:SDGIT='1'; ` (PowerShell) 또는 `SDGIT=1 ` (Bash) 를 붙여야 훅이 통과.
137
155
  - 입력 파일 옆에 가공/펼친 산출물이 있으면 원본 대신 가공본부터.
138
156
 
139
157
  ## 코드 설계·변경
140
158
 
141
159
  - 산출물 소비자 표면(공개 API/props/옵션/UI/출력 등) 단순함이 내부 구현 단순함보다 우선. 충돌 시 복잡도는 내부로 흡수.
142
160
  - 내부 구현 난이도 회피를 위해 소비자 요구 완화/근사화 제안 금지. 난이도는 내부로 흡수. 불가 시 사용자 보고 후 결정.
161
+ - **명시 정의 자체 단순화·임의 처리 금지**: spec·사용자 directive·합의 산출물에 식·정의·분기·경계가 명시된 항목은 코드에서 자체 단순화·근사화·안전 처리(NULL 강제·0 클램프·방어 가드·생략 분기 등) 임의 추가 금지. 식 그대로 풀어쓸 것. 정확 구현 부담이 크면 단순화안을 사용자에 보고 후 합의. ([결정 근거](#결정-근거) "안티패턴" 의 코드 적용형)
143
162
  - 변경 전, 변경 영역의 기존 코드 패턴과 개발 매뉴얼을 먼저 조사.
144
163
  - 의존 라이브러리 동작 이상 → 우회 코드 작성 전 라이브러리 측 원인 먼저 조사.
145
164
  - 라이브러리 버그/누락 판단 시 → 사용자에게 보고 후 수정 경로 제안 (예: 모노레포 내부=직접 패치, 외부=이슈 등록).
@@ -0,0 +1,22 @@
1
+ """공용 경로 헬퍼.
2
+
3
+ 실행 위치는 항상 프로젝트 루트라고 가정한다 (cd 금지 규칙).
4
+ """
5
+ from __future__ import annotations
6
+
7
+ import json
8
+ import tempfile
9
+ from pathlib import Path
10
+
11
+
12
+ def resolve_tmp_base() -> Path:
13
+ """프로젝트 루트의 .claude/simplysm.json 의 tmpdir → 없으면 OS tmp."""
14
+ cfg_path = Path(".claude/simplysm.json")
15
+ if cfg_path.exists():
16
+ try:
17
+ cfg = json.loads(cfg_path.read_text(encoding="utf-8"))
18
+ if cfg.get("tmpdir"):
19
+ return Path(cfg["tmpdir"])
20
+ except Exception:
21
+ pass
22
+ return Path(tempfile.gettempdir())
@@ -30,3 +30,17 @@ for pattern, label in BLOCKED:
30
30
  if re.search(pattern, cmd):
31
31
  print(f"Blocked: {label}", file=sys.stderr)
32
32
  sys.exit(2)
33
+
34
+ # Git read-only inspection block (working-tree-only policy).
35
+ # Bypass: any occurrence of `SDGIT` token in the command.
36
+ GIT_READ_VERBS = r"status|diff|log|show|blame|reflog|rev-list|rev-parse|ls-files|ls-tree|cat-file|describe|whatchanged|shortlog|grep"
37
+ if not re.search(r"\bSDGIT\b", cmd):
38
+ m = re.search(CMD_POS + rf"git\s+(?P<verb>{GIT_READ_VERBS})\b", cmd)
39
+ if m:
40
+ print(
41
+ f"Blocked: git {m.group('verb')} "
42
+ "(working-tree inspection via git is forbidden; use Read/Grep/Glob). "
43
+ "If intentional, prefix the command with `SDGIT=1 ` (bash) or `$env:SDGIT='1'; ` (PowerShell).",
44
+ file=sys.stderr,
45
+ )
46
+ sys.exit(2)
@@ -7,6 +7,7 @@ description: 워크스페이스의 모든 변경을 단일 커밋으로 묶는
7
7
 
8
8
  system prompt 의 "Committing changes with git" 절차를 따르되, 아래만 적용한다.
9
9
 
10
+ - 모든 git 호출(`status`/`diff`/`log`/`add`/`commit`)은 prefix `$env:SDGIT='1'; git ...` (PowerShell) 또는 `SDGIT=1 git ...` (Bash) 로 호출. (Pre-tool 훅의 전역 git 조회 차단 우회 마커. add/commit 도 일관성으로 동일 prefix.)
10
11
  - Staging은 `git add -A` 사용. 본 스킬 호출 = 사용자가 -A 위험(민감 파일 staging) 인지·동의한 것으로 간주.
11
12
  - 메시지는 사용자 응답 언어와 일치.
12
13
  - 변경이 여러 갈래면:
@@ -24,7 +24,7 @@ spec.md 화면 1개를 클라이언트 패키지의 화면 컴포넌트 자리
24
24
 
25
25
  - 대상 spec.md 경로
26
26
  - 만들 화면 식별자 — `[화면.X]` 또는 §4.x
27
- - 산출 위치 — 클라이언트 패키지 + 화면 폴더. client 타겟이 1개면 자동, 여러 개면 후보 제시 후 사용자 확정. **3단계-C 답습 화면이 있으면위치로 자동 채택** (1단계 초안을 답습 위치로 갱신).
27
+ - 산출 위치 — 클라이언트 패키지 + 화면 폴더. client 타겟이 1개면 자동, 여러 개면 후보 제시 후 사용자 확정. **3단계-C 도메인 인접 화면이 명확히 식별되면 위치(같은 도메인 폴더)로 자동 채택** (1단계 초안을 인접 위치로 갱신).
28
28
 
29
29
  없으면 묻기. spec.md 에 식별자 매칭이 안 되면 §4 화면 목록 표에서 후보 제시 후 확정.
30
30
 
@@ -51,18 +51,34 @@ spec.md 화면 1개를 클라이언트 패키지의 화면 컴포넌트 자리
51
51
 
52
52
  쓰려는 컴포넌트(예: `sd-form`, `sd-crud-list`)가 있으면 **본체 소스를 직접 Read** 해 input/output·동작을 정확히 파악. 사용처 grep 만으로는 누락된 prop 을 놓친다.
53
53
 
54
- **C. 답습 후보 화면 (사용자 확정)**
54
+ **C. 부위별 패턴 레퍼런스 수집**
55
55
 
56
- LLM 단독으로 답습 원본 1개를 뽑으면 부적절한 화면을 고르는 경우가 잦다. 다음 절차:
56
+ 코드베이스의 클라이언트 화면 전반에서 **부위(부분)별로 공통 패턴**을 수집한다. "구성 똑같은 화면 1개를 골라 통째 답습" 모델이 아니다. 일치 화면이 있어도, 부위별 종합 결과 위에 추가로 얹는다.
57
57
 
58
- 1. 코드베이스에서 화면 구성(단순 목록 / 마스터-디테일 / 마스터-라인 / 폼 편집 / 모달) 일치하는 **후보 2~3개** 추리기. 도메인 영역(같은 sub-app)이 같으면 우선.
59
- 2. 사용자에게 후보 목록 제시 후 1회 질문 — "이 중 답습할 화면 선택 부탁".
60
- 3. 사용자 확정분 1개(또는 복수) Read 후 답습 항목:
61
- - template 슬롯 사용·영역 분할·항목 클래스 패턴
62
- - 빈 상태 마크업(아이콘·여백·문구)
63
- - 도메인 폴더 위치 · 라우팅·메뉴 등록 위치·방식 · 슬러그 규칙
58
+ **수집 대상 부위** (대상 화면이 사용하는 것만 골라 수집):
64
59
 
65
- 후보 0개면 사용자에게 1회 보고 후 라이브러리 문서(A) + 컴포넌트 소스(B) 만으로 진행.
60
+ | 부위 | 수집 내용 |
61
+ | ----------- | --------------------------------------------------------------- |
62
+ | 화면 골격 | 컴포넌트 selector·파일 위치·라우팅/메뉴 등록 위치 |
63
+ | 헤더/타이틀 | 페이지 타이틀·도구 버튼 배치 |
64
+ | 툴바 | 검색·필터·추가/삭제 버튼·페이지네이션 위치·정렬 인터랙션 |
65
+ | 영역 분할 | 좌우/상하 split·탭·sheet·dock 사용 |
66
+ | 리스트 | 테이블·카드 그리드·트리 마크업·헤더 셀·행 셀·선택/정렬·빈 상태 |
67
+ | 폼 | 필드 그리드·라벨/입력 배치·필수 표시·버튼 푸터 |
68
+ | 모달 | 헤더·본문·푸터·확인/취소 버튼·크기 |
69
+ | 빈 상태 | 아이콘·여백·문구 |
70
+ | 도메인 위치 | 같은 sub-app·같은 도메인 폴더 후보(산출 위치 자동 채택용) |
71
+
72
+ **절차**:
73
+
74
+ 1. 클라이언트 패키지의 화면 폴더 전반 Glob 으로 훑어 화면 목록 확보.
75
+ 2. 위 부위별로 **각 부위마다 화면 2~4개**를 골라 template 부분 발췌 Read. 도메인 영역(같은 sub-app)이 가까운 화면 우선. 부위마다 다른 화면을 골라도 됨 (예: 헤더는 화면 X·Y, 리스트는 화면 Z·W).
76
+ 3. 부위별 공통 패턴(자주 쓰는 슬롯·클래스·요소 구조) 메모화. 1회만 쓰인 변종은 채택 후보에서 배제, 다수에서 반복되는 것을 채택.
77
+ 4. 부위별 패턴이 화면마다 갈라지면 (예: 리스트가 테이블·카드 두 갈래) 대상 화면의 와이어프레임이 어느 쪽인지로 선택.
78
+
79
+ **도메인 인접 후보**: 같은 sub-app·같은 도메인 폴더에 화면이 1개 이상 있으면 그 폴더를 산출 위치 자동 채택 근거로 쓴다. 0개면 라우팅·메뉴 등록 위치를 사용자에게 1회 질문.
80
+
81
+ LLM 단독 판단 한계: 동일 구성 화면이 한 곳도 없다고 framework 처방만으로 그리면 안 된다. **반드시 부위별로 수집한 패턴을 근거로** 그려야 한다. 부위별 후보가 0개인 부위가 있으면 그 부위만 사용자에게 1회 질문 (그 화면의 그 부위 어떻게 처리할지).
66
82
 
67
83
  ### 4단계: 충돌 확인
68
84
 
@@ -77,7 +93,8 @@ LLM 단독으로 답습 원본 1개를 뽑으면 부적절한 화면을 고르
77
93
  3단계 분석 자료(A/B/C)를 1순위 근거로, **template 부터** 채운다.
78
94
 
79
95
  - 파일명·selector·시그널·DI 명명 등은 라이브러리 문서(A) 가 정한 형식 그대로.
80
- - 슬롯·영역 분할·클래스 패턴은 답습 화면(C) 그대로.
96
+ - 슬롯·영역 분할·클래스 패턴은 3단계-C 부위별 패턴 채택분 그대로. 부위별로 다른 화면을 참조했더라도 각 부위 채택분을 그대로 옮긴다.
97
+ - 부위별 채택분이 코드베이스 어느 화면에서 왔는지 출처를 머릿속에 두고 비교 가능 상태로 유지(6단계 점검용).
81
98
  - 모달 호출 화면이면 동반 모달 §4.x 도 같은 단계로 생성.
82
99
 
83
100
  **표식 마커 (고정)**
@@ -94,11 +111,16 @@ LLM 단독으로 답습 원본 1개를 뽑으면 부적절한 화면을 고르
94
111
 
95
112
  ### 6단계: 자체 점검
96
113
 
97
- **패스 1: 답습 매칭** — 3단계-C 사용자 확정 화면 다시 Read 비교:
114
+ **패스 1: 부위별 패턴 일치** — 3단계-C 에서 부위마다 채택한 레퍼런스 화면을 다시 Read 부위별로 비교:
115
+
116
+ - 헤더/툴바: 도구 버튼 배치·라벨 형식·간격·클래스 동일
117
+ - 영역 분할: split/탭/sheet/dock 사용 동일
118
+ - 리스트: 헤더 셀·행 셀 마크업·정렬/선택 슬롯 동일
119
+ - 폼: 필드 그리드·라벨/입력 배치·푸터 버튼 동일
120
+ - 모달: 헤더·본문·푸터 구조 동일
121
+ - 빈 상태: 아이콘·여백·문구 동일
98
122
 
99
- - 슬롯 사용 위치·내용 패턴 동일
100
- - 영역 분할·클래스 패턴 동일
101
- - 빈 상태·아이콘·여백 동일
123
+ 부위 중 한 곳이라도 채택 패턴과 어긋나면(임의 변형·새 클래스 발명·새 슬롯 사용) 수정. "비슷한 화면이 없어서 알아서 그렸다"는 자기 합리화 금지 — 그 부위 채택분이 비어 있다는 뜻이므로 3단계-C 로 돌아가 수집·재선택.
102
124
 
103
125
  **패스 2: 라이브러리 문서 위배 점검** — 3단계-A 의 매뉴얼 문서 항목별 일치 확인. 위배 항목이 있으면 수정 후 재점검.
104
126
 
@@ -1,146 +1,170 @@
1
1
  ---
2
2
  name: sd-impl
3
- description: spec.md 화면 1개를 현재 코드베이스 상태와 비교해 차이만큼 풀 구현(테스트·시연 포함)한다. Use when "화면 풀 구현", "데모를 실 구현으로", "화면 실가동" 을 요청할 때.
3
+ description: spec.md 의 단위(§4.x 화면 또는 §5.x 자동 처리) 1개를 현재 코드베이스 상태와 비교해 차이만큼 풀 구현(테스트·시연 포함)한다. Use when "화면 풀 구현", "데모를 실 구현으로", "화면 실가동", "자동 처리 풀 구현" 을 요청할 때.
4
4
  ---
5
5
 
6
6
  # sd-impl
7
7
 
8
- spec.md 화면 1개를 현재 코드베이스 상태와 비교해 빠지거나 어긋난 부분만큼 풀 구현한다. 데모 골격이 있으면 보존, 도메인 모델·서버 함수·화면 로직·테스트는 차이가 있을 때만 신규/갱신. 끝에 사용자 시연으로 회귀를 잡는다.
8
+ spec.md 단위(§4.x 화면 또는 §5.x 자동 처리) 1개를 현재 코드베이스 상태와 비교해 빠지거나 어긋난 부분만큼 풀 구현한다. 데모 골격이 있으면 보존. 신규/갱신 무관 동일 워크플로. 끝에 사용자 시연으로 회귀를 잡는다.
9
9
 
10
10
  ## 본질
11
11
 
12
- - **차이만 작업**: 현재 상태와 spec 목표를 (없음 / 불일치 / 일치) 3분류로 판정. 일치 항목은 손대지 않는다.
13
- - **YAGNI 구현**: spec 에 없는 기능·옵션·추상화 추가 금지.
14
- - **환경 무관**: framework 처방을 본문에 박지 않는다. 코드베이스의 매뉴얼·답습 화면·테스트 환경은 발견되면 따르고, 없으면 표준 패턴으로 진행.
12
+ - **차이만 작업**: spec 항목 1개당 (없음 / 불일치 / 일치) 판정. 일치 항목은 손대지 않는다.
13
+ - **YAGNI**: spec 에 없는 기능·옵션·추상화 추가 금지.
14
+ - **임의 채움 금지**: spec 본문에 명시 없거나 모호한 분기를 발견하면 즉시 멈추고 사용자에게 질문. 자체 판단으로 채우지 않는다. 신규/갱신 무관.
15
+ - **환경 무관**: framework 처방을 본문에 박지 않는다. 코드베이스 매뉴얼·기준 단위 + 계층별 보강 패턴·테스트 환경은 발견되면 따르고, 없으면 표준 패턴.
15
16
 
16
17
  ## 워크플로
17
18
 
18
19
  ### 1단계: 입력 확보
19
20
 
20
- 호출에 다음 필요:
21
-
22
21
  - 대상 spec.md 경로
23
- - 구현할 화면 식별자 — `[화면.X]` 또는 §4.x
22
+ - 구현할 단위 식별자 — `§4.x` (화면) 또는 `§5.x` (자동 처리)
24
23
 
25
- 없으면 묻기. spec.md 에 식별자 매칭이 안 되면 §4 화면 목록 표에서 후보 제시 후 확정.
24
+ 없으면 묻기. spec.md 에 식별자 매칭이 안 되면 §4 화면 목록 / §5 자동 처리 목록 표에서 후보 제시 후 확정.
26
25
 
27
- ### 2단계: spec §4.x 분석
26
+ ### 2단계: 외부 입력 점검 (BLOCKING)
28
27
 
29
- §4.x 에서 추출:
28
+ 작업 대상 §4.x/§5.x 그가 참조하는 §5/§6/§7/§8 항목 점검:
30
29
 
31
- - 헤더 인덱스(Actor · 관련 섹션 · 장치)
32
- - 기능 개요 · 와이어프레임 · 항목표 · 동작 · 도메인 규칙(해당 )
33
- - §4.x 참조하는 도메인 모델(§7.x), 자동 처리5.x), 외부 인터페이스(§8.x), 공통 정의(§6.x)
30
+ - **헤더 `[OPEN: 날짜]` 섹션**: 본문이 재분석 포인터일 뿐 임의안 부재 → sd-impl 해소 불가. 사용자 보고 후 **종료**. 사용자가 sd-spec 으로 확정 받은 뒤 sd-impl 재호출.
31
+ - **본문 인라인 `[OPEN]`**: `sd-base-rules` "결정 근거" 적용 근거 없으면 1건씩 질문. 답변 후 즉시 spec.md 반영 → 다음 건. 결정이 다른 섹션의 구조 변경(필드 추가, 새 규칙 항목 등)을 요구하면 헤더 OPEN 과 동일 처리: 종료 + sd-spec 재호출. 종료 전 식별·보고:
32
+ - sd-spec 넘길 변경 항목위치 + 변경 내용)
33
+ - 그 변경이 영향 미치는 **다른 §4.x/§5.x 단위 목록** — 구조 변경된 §5/§6/§7/§8 항목을 spec 에서 역인용해 수집
34
+ - 영향 단위 중 이미 구현된 것 / 미구현인 것 구분
35
+ - **사용자 제공 예정 자료**: spec 본문에 "사용자 제공 예정" 류로 적힌 파일·값. 사용자 회신 후 진행.
36
+ - **묵시적 모호**: 명시 마커 없지만 spec 본문이 분기·정의·정의식·경계 케이스를 다루지 않는 부분. 4단계 분해 표 작성 중 발견될 가능성 높음. 발견 시 본 단계로 회귀해 인라인 `[OPEN]` 절차 적용.
34
37
 
35
- ### 3단계: 외부 입력 점검 (BLOCKING)
38
+ ### 3단계: 보조 자료 수집 (있다면 활용)
36
39
 
37
- 작업 대상 §4.x 와 그가 참조하는 §5/§6/§7/§8 항목에서 점검 (이 화면이 쓰지 않는 다른 섹션은 무관):
40
+ 부재로 워크플로를 멈추지 않는다.
38
41
 
39
- - **헤더 `[OPEN: 날짜]` 섹션**: 본문이 재분석용 포인터일 뿐 임의안 부재 → sd-impl 해소 불가. 사용자에게 보고 후 **종료**. 사용자가 sd-spec 으로 확정 받은 뒤 sd-impl 재호출.
40
- - **본문 인라인 `[OPEN]`**: `sd-base-rules` "결정 근거" 적용 — 근거 없으면 1건씩 질문. 답변 후 즉시 spec.md 반영(아래 "spec.md 동기화") → 다음 건. 단, 결정이 다른 섹션의 구조 변경(필드 추가, 새 규칙 항목 등)까지 요구하면 헤더 OPEN 과 동일 처리: 종료 후 사용자 보고 + sd-spec 재호출. 종료 전에 다음을 식별·보고:
41
- - sd-spec 에 넘길 변경 항목 (§ 위치 + 변경 내용)
42
- - 그 변경이 영향 미치는 **다른 §4.x 화면 목록** — 구조 변경된 §5/§6/§7/§8 항목을 spec 에서 역인용해 참조 §4.x 수집. sd-spec 확정 후 sd-impl 재호출 대상.
43
- - 영향 §4.x 중 이미 구현된 것 / 미구현인 것 구분 (이미 구현분은 재구현 필요, 미구현분은 향후 sd-impl 첫 호출 시점에 자연 반영).
44
- - **사용자 제공 예정 자료**: spec 본문에 "사용자 제공 예정" 류로 적힌 파일·값(디자인 시안, 샘플 데이터, 외부 API 명세, 자격증명 등). 사용자에게 요청 후 회신분으로 다음 건.
42
+ **A. 라이브러리/개발 매뉴얼**
45
43
 
46
- ### 4단계: 보조 자료 수집 (있다면 활용)
44
+ - `@simplysm/*` 14.x [.claude/references/sd-simplysm14/README.md](../../references/sd-simplysm14/README.md) Read 후 "개발 매뉴얼" 진입.
45
+ - 그 외 framework — 코드베이스 안의 동등 위치 문서 Read.
46
+ - 없으면 표준 패턴.
47
47
 
48
- 다음 셋은 발견되면 패턴을 따르고, 없으면 LLM 의 일반 지식으로 표준 패턴 채택해 그냥 진행한다. **부재로 워크플로를 멈추지 않는다.**
48
+ **B. 기준 단위 + 계층별 보강**
49
49
 
50
- **A. 라이브러리/개발 매뉴얼**
50
+ 구현은 다층 흐름이 한 줄로 가야 일관성이 유지된다. 답습 단위 1개를 통째 답습하는 모델이 아니라, 기준 단위 1개를 잡고 비어있거나 부적합한 계층만 다른 단위에서 보강한다. 계층 간 의존성(모델 → 데이터 접근 → 본체 → 테스트)을 끊지 않으면서, 기준 단위에 부재한 계층의 LLM 단독 처방을 막는다.
51
+
52
+ **4계층**: 도메인 모델 / 데이터 접근 / 본체(§4.x = 화면 컴포넌트, §5.x = 자동 처리 로직 + 트리거) / 테스트.
51
53
 
52
- 코드베이스에 권위 규약/매뉴얼 문서가 있으면 1순위로 따른다.
54
+ **B-1. 기준 단위 선정** (같은 종류 §4.x↔§4.x, §5.x↔§5.x 안에서):
53
55
 
54
- - `@simplysm/*` 14.x 사용 시 — [.claude/references/sd-simplysm14/README.md](../../references/sd-simplysm14/README.md) Read "개발 매뉴얼" 항목 진입.
55
- - framework 코드베이스 안의 동등 위치 문서를 찾아 Read.
56
- - 없으면 흔한 표준(예: TypeScript + 흔한 테스트 러너) 으로 채택.
56
+ 1. 도메인/sub-app 인접 풀구현 단위 후보 Glob 탐색.
57
+ 2. 1개 자동 채택. 2개 이상 후보 목록 제시 후 사용자 1회 질문. 0개 → 같은 종류 전 범위로 확장 후 동일 규칙.
58
+ 3. 범위에도 0개 기준 단위 없이 매뉴얼(3-A) + 표준 패턴.
57
59
 
58
- **B. 답습 풀구현 후보**
60
+ **B-2. 계층별 보강**:
59
61
 
60
- 도메인/구성이 유사한 이미 구현된 화면이 코드베이스에 있으면 그 패턴(파일 위치·이름 규약·모델 정의·데이터 접근/저장·테스트 작성) 답습.
62
+ 기준 단위의 4계층 각각을 (비어있음 / 부적합 / 적합) 으로 평가:
61
63
 
62
- 1. 후보 2~3개 추리기. 도메인 영역이 같으면 우선.
63
- 2. 사용자에게 후보 목록 제시 1회 질문 "이 답습할 화면 선택 부탁".
64
- 3. 사용자 확정분 1개 Read.
64
+ - 비어있음: 해당 계층 파일이 기준 단위에 없음 (예: 테스트 없음).
65
+ - 부적합: 있지만 spec 요구와 어긋남 (예: 단일 테이블 접근인데 spec 조인 요구).
66
+ - 적합: 그대로 답습.
65
67
 
66
- 후보 0건이면 답습 없이 진행.
68
+ 비어있음·부적합 계층은 같은 종류 다른 단위에서 그 계층만 발췌해 다수 반복 패턴 자동 채택. 1회만 쓰인 변종은 배제. 다수 패턴이 갈리면 사용자 1회 질문.
69
+
70
+ **B-3. Read**: 기준 단위의 적합 계층 파일 + 보강 출처 파일을 모두 Read. 7단계 정합 점검 입력.
67
71
 
68
72
  **C. 테스트 환경**
69
73
 
70
- 코드베이스의 단위 테스트 프로젝트 구분·실행 명령·mocking 패턴·dev 서버 실행 명령을 파악. 없으면 흔한 조합으로 진행.
74
+ 단위 테스트 프로젝트 구분·실행 명령·mocking 패턴·dev 서버 실행 명령 파악. 없으면 표준 조합.
75
+
76
+ ### 4단계: spec 분해 표
77
+
78
+ 대상 §4.x/§5.x 와 참조 §5/§6/§7/§8 본문을 **항목 단위까지 분해**해 표 작성. 표는 assistant 응답으로 출력 (이후 5·6단계 입력).
71
79
 
72
- ### 5단계: 차이 식별
80
+ | 항목 | spec 인용 | 현재 코드 상태 | 판정 | 매핑 파일 | 의존 |
81
+ | ---- | --------- | -------------- | ---- | --------- | ---- |
73
82
 
74
- 분석 자료 기준으로 spec §4.x 가 요구하는 산출물 목록을 만들고, 현재 코드베이스의 각 항목을 (없음 / 불일치 / 일치) 3분류로 판정.
83
+ **항목 분해 단위:**
75
84
 
76
- 전형 산출물: 도메인 모델, 데이터 접근 코드, 서버 함수(보안·네이티브 사유 시), 화면 컴포넌트, 라우팅·메뉴 등록, 단위 테스트.
85
+ - 도메인 모델: 필드 1개당 1줄 (타입·제약·기본값)
86
+ - 계산식: 정의식 1개당 1줄 (좌변·우변·참조)
87
+ - 상태값·분기: 케이스 1개당 1줄 (조건·결과)
88
+ - UI 항목: 컬럼·필드·버튼 1개당 1줄
89
+ - 동작·자동 처리: 트리거·결과 단위 1줄
77
90
 
78
- **일치 항목은 손대지 않는다.** 차이는 갱신·덮어쓰기·신규 추가로 처리. 이 단계에서는 삭제하지 않는다 — 미참조 잔재 정리는 9단계에서 일괄.
91
+ **컬럼:**
79
92
 
80
- ### 6단계: 계획
93
+ - **항목**: 분해 단위 1개의 짧은 식별자
94
+ - **spec 인용**: spec.md 의 § 위치 + 본문 문구를 그대로
95
+ - **현재 코드 상태**: 코드베이스 조사 결과 사실. 신규 호출은 "없음", 갱신 호출은 "있음(어떻게)". 조사는 워킹트리 파일 Read·Grep·Glob 만. **git 호출(`status`/`diff`/`log`/`show`/`blame` 등) 금지** — 갱신 호출이라도 현재 워킹트리 자체가 진실 원천이며, git 으로 변경분만 훑으면 일관성을 놓침 (sd-base-rules "분석 작업" 참조).
96
+ - **판정**: 없음 / 불일치(차이) / 일치
97
+ - **매핑 파일**: 이 항목이 작성·갱신될 파일 경로
98
+ - **의존**: 다른 항목 ID
81
99
 
82
- (없음 / 불일치) 항목을 작업 단위 목록으로 정리. 의존 관계 표시 (예: 모델 데이터 접근 → 화면). 작업 추적 도구가 있으면 활용한다(필수 아님).
100
+ 분해 spec 본문이 정의·정의식·분기·경계 케이스를 다루지 않거나 모순되는 부분 발견2단계 회귀.
83
101
 
84
- ### 7단계: 작업 사이클
102
+ 작성 완료 5단계 진입.
85
103
 
86
- 작업 시작 시 **테스트 작성 가능 여부** 판정. 4-C 의 테스트 환경 이용.
104
+ ### 5단계: 작업 사이클
87
105
 
88
- 판정 기준: "테스트 환경이 이미 존재 + 작성 비용 대비 회귀 방지 가치".
106
+ 표의 (없음·불일치) 항목만 의존 순서로 진행. 일치 항목은 손대지 않는다.
89
107
 
90
- - **테스트 가능** 입출력 명확 + 외부 의존 통제 가능 (도메인 로직·계산·변환·서버 함수·데이터 접근 헬퍼).
108
+ 항목 시작 **테스트 작성 가능 여부** 판정 (3-C 테스트 환경 이용):
109
+
110
+ - **테스트 가능** — 입출력 명확 + 외부 의존 통제 가능 (도메인 로직·계산·변환·서버 함수·데이터 접근).
91
111
  사이클: **RED → GREEN → REFACTOR**
92
- - **RED**: 테스트만 작성 → 테스트 러너 실행 → 실패(또는 대상 미존재) 확인. **이 단계에서 구현 파일 절대 손대지 말 것.** 실패를 눈으로 본 뒤에만 GREEN 진입.
93
- - **GREEN**: 테스트가 통과하는 **최소** 구현만 (YAGNI) → 러너 재실행 → 통과 확인.
94
- - **REFACTOR**: 중복·가독성·기존 패턴 정합 정리 → 러너 재실행 → 통과 유지 확인. 정리할 게 없으면 스킵.
95
- - **테스트 불가/비효율** — UI 시각·인터랙션, 외부 서비스 실호출, 환경 의존 코드.
112
+ - **RED**: 테스트만 작성 → 러너 실행 → 실패 확인. **구현 파일 손대지 않음.**
113
+ - **GREEN**: 테스트 통과하는 **최소** 구현 → 러너 통과 확인.
114
+ - **REFACTOR**: 중복·가독성·기존 패턴 정합 정리 → 러너 통과 유지. 정리할 게 없으면 스킵.
115
+ - **테스트 불가/비효율** — UI 시각·인터랙션, 외부 서비스 실호출, 환경 의존.
96
116
  사이클: **구현 → REFACTOR**
97
- - **구현**: YAGNI 로 작성. 동작 검증은 10단계 시연으로 미룬다.
98
- - **REFACTOR**: 위와 동일. 정리할 게 없으면 스킵.
99
117
 
100
- ### 8단계: spec 대조
118
+ **임의 채움 금지**: 작업 사이클 중 spec 미정의/모호 분기 만나면 즉시 멈추고 2단계 회귀. 자체 판단으로 채우지 않는다.
101
119
 
102
- 시연 진입 전, spec §4.x 요구가 실제 구현·테스트에 다 들어갔는지 self-check.
120
+ ### 6단계: spec 대조 (subagent 위탁)
103
121
 
104
- 대조 대상:
122
+ 5단계 모든 항목 완료 후, 별도 subagent 에 위탁해 spec ↔ 현재 코드 전체를 독립 대조. 같은 LLM 셀프 검증의 표면 훑기 편향 제거.
105
123
 
106
- - 5단계에서 뽑은 산출물 목록 전부 작업 완료 상태인지
107
- - §4.x 본문의 와이어프레임·항목표·동작·도메인 규칙 — 항목 단위로 누락 여부 (와이어프레임은 컴포넌트 구조 대 레이아웃 매핑 수준에서 대조)
108
- - §4.x 가 참조하는 §5(자동 처리)·§6(공통)·§7(도메인 모델)·§8(외부 인터페이스) 항목 — 구현 반영 여부
124
+ **대조는 단위 전체 대상.** 신규/갱신 무관, "이번 변경분만" 스코프 제한 없음.
109
125
 
110
- 누락·불일치 발견 해당 작업으로 돌아가 7단계 사이클 재수행. 전부 일치 확인된 뒤에만 다음 단계.
126
+ 상세 (subagent 호출 형식, 입력 패키지, 4분류 출력 스키마, 분류별 처리): [references/spec-cross-check.md](references/spec-cross-check.md) Read 진행.
111
127
 
112
- ### 9단계: 코드 정리
128
+ 차이 0건이면 7단계 진입. 1건 이상이면 분류별 처리 후 본 단계 재실행.
113
129
 
114
- 전체 변경분을 한번 훑어 정돈. 7단계 REFACTOR 가 잡지 못한 횡단 이슈와 작업 잔재가 대상.
130
+ ### 7단계: 코드 정리
115
131
 
116
- - **횡단 중복**: 작업 사이클 사이에 동일 로직이 흩어져 있으면 합치기.
117
- - **답습 패턴 재확인**: 4-B 에서 채택한 화면 vs 실제 작성 파일 위치·네이밍·구조 정합.
118
- - **불필요한 코드**: 미사용 import·변수·주석, 요구 없는 옵션·추상화 제거. 7단계 갱신·덮어쓰기 결과로 어디서도 참조되지 않는 파일도 포함 (검사 범위는 화면 스코프 넘어 전체 워크스페이스). **단 파일 단위 삭제는 후보 목록을 사용자에게 보고 → 확정분만 삭제** (dynamic import·마이그레이션·문서 자산 등 보존분 사용자 제외).
119
- - **매뉴얼 권위 규약**: 4-A 에서 Read 한 매뉴얼(@simplysm/* 면 sd-simplysm14) 위반 항목 수정.
132
+ - **횡단 중복**: 작업 사이클 사이 흩어진 동일 로직 합치기.
133
+ - **계층별 정합 점검**: 3-B 기준 단위 + 보강 출처 파일을 다시 Read 해 4계층별로 실제 작성분과 비교. 계층이라도 채택 패턴과 어긋나면 (임의 변형·새 발명) 수정.
134
+ - 도메인 모델: 필드·타입·제약·네이밍 패턴 일치
135
+ - 데이터 접근: 함수 시그니처·쿼리 패턴·에러 처리 일치
136
+ - 본체: 컴포넌트 구조·상태·핸들러·의존성 패턴 일치 (§4.x) / 트리거·처리 단계 구조 일치 (§5.x)
137
+ - 테스트: 러너·assertion·mock 패턴 일치
138
+ - **불필요한 코드**: 미사용 import·변수·주석, 요구 없는 옵션·추상화 제거. 작업 결과로 어디서도 참조되지 않는 파일도 포함 (검사 범위는 전체 워크스페이스). **단 파일 단위 삭제는 후보 목록을 사용자에게 보고 → 확정분만 삭제** (dynamic import·마이그레이션·문서 자산 등 보존분 사용자 제외).
139
+ - **매뉴얼 권위 규약**: 3-A Read 한 매뉴얼 위반 항목 수정.
120
140
 
121
141
  정리 후 단위 테스트 재실행 — 회귀 없음 확인.
122
142
 
123
- ### 10단계: 시연 검증
143
+ ### 8단계: 시연 검증
124
144
 
125
145
  사용자에게 요청: "**dev 서버**를 실행하고 접속 주소를 알려달라."
126
146
 
127
- 주소 회신 `playwright-cli` spec §4.x 동작 시나리오를 직접 시연:
147
+ **dev 서버·외부 프로세스 자체 실행 금지**: assistant 가 직접 `ng serve`·`npm run dev`·`vite`·`pnpm dev` 등으로 dev 서버를 띄우지 않는다. 사용자가 띄워 주소를 회신할 때까지 대기. 사용자가 본 단계 스킵을 지시하거나 시연 불가 환경이 명시되면 본 단계 스킵 후 9단계.
148
+
149
+ 주소 회신 후 `playwright-cli` 로 §4.x/§5.x 동작 시나리오 직접 시연:
128
150
 
129
- - 기능 개요·동작에 적힌 사용자 흐름 1회씩 수행.
130
- - 화면 항목·와이어프레임 위치와 실제 렌더 결과 비교.
151
+ - 기능 개요·동작 사용자 흐름 1회씩 수행.
152
+ - 화면 항목·와이어프레임 위치와 실제 렌더 비교.
153
+ - §5.x (자동 처리) 는 트리거 발생 → 결과 확인.
131
154
 
132
- 회귀 발견 시 해당 작업으로 돌아가 수정 → 재시연.
155
+ 회귀 발견 시 5단계 회귀 수정 → 재시연.
133
156
 
134
- ### 11단계: 완료 보고
157
+ ### 9단계: 완료 보고
135
158
 
136
- - 대상 spec.md 의 해당 §4.x / §5.x 헤더 `[확정: 날짜]` 를 `[확정: 날짜, 구현: 오늘날짜]` 로 확장 (오늘날짜는 Bash `date +%Y-%m-%d`). 이미 `구현: …` 가 들어있으면 그 날짜만 갱신.
137
- - 만들거나 갱신한 파일 목록 보고 (마커 부착한 spec.md 포함).
138
- - 본 세션에서 §5/§6/§7/§8 공통 자원을 신규/변경했다면, 그 자원을 참조하는 **다른 §4.x 화면 중 이미 구현된 것**을 spec 역인용으로 수집해 영향 화면 목록으로 보고 (재구현 필요 여부 사용자 판단용). 변경 없었으면 생략.
139
- - 시연에서 사용자 확인이 끝나면 종료.
159
+ - 대상 spec.md 의 해당 §4.x / §5.x 헤더 `[확정: 날짜]` 를 `[확정: 날짜, 구현: 오늘날짜]` 로 확장 (Bash `date +%Y-%m-%d`). 이미 `구현: …` 가 들어있으면 그 날짜만 갱신.
160
+ - 만들거나 갱신한 파일 목록 보고 (마커 부착한 spec.md 포함).
161
+ - 본 세션에서 §5/§6/§7/§8 공통 자원을 신규/변경했다면, 그 자원을 참조하는 **다른 §4.x/§5.x 중 이미 구현된 것**을 spec 역인용으로 수집해 영향 단위 목록 보고 (재구현 필요 여부 사용자 판단용). 변경 없었으면 생략.
162
+ - 시연에서 사용자 확인 끝나면 종료.
140
163
 
141
164
  ## 운용
142
165
 
143
166
  - 결정 근거: `sd-base-rules.md` "결정 근거" 적용.
144
- - **spec.md 동기화**: sd-impl 직접 손대는 spec 변경은 다음 2건뿐. 헤더 OPEN·구조 변경은 3단계 규칙대로 종료 sd-spec.
145
- - 본문 인라인 `[OPEN]` 해소 해당 위치의 마커를 결정 내용으로 교체 (3단계).
146
- - 11단계 완료 시 §4.x / §5.x 헤더 `[확정: …]` 마커를 `[확정: …, 구현: 날짜]` 확장.
167
+ - **사용자 보고 어휘**: 코드 식별자(변수명·SQL 함수명·타입 키워드 등) 노출 금지. 도메인 어휘로 풀어 보고. (`sd-base-rules.md` "산출물 소비자 도메인 어휘" 적용)
168
+ - **spec.md 동기화**: sd-impl 직접 손대는 spec 변경은 다음 2건뿐. 헤더 OPEN·구조 변경은 2단계 규칙대로 종료 후 sd-spec.
169
+ - 본문 인라인 `[OPEN]` 해소 마커를 결정 내용으로 교체 (2단계).
170
+ - 9단계 완료 시 §4.x/§5.x 헤더 `[확정: …]` 를 `[확정: …, 구현: 날짜]` 로 확장.
@@ -0,0 +1,55 @@
1
+ # 도서 관리 시스템 spec
2
+
3
+ ## §1 개요
4
+
5
+ 도서관 내부 시스템. 사서가 도서를 등록·조회.
6
+
7
+ ## §4 화면
8
+
9
+ | ID | 이름 | Actor | 장치 |
10
+ | ----- | -------- | ----- | ---- |
11
+ | §4.1 | 도서 목록 | 사서 | PC |
12
+
13
+ ### §4.1 도서 목록 [확정: 2026-05-01]
14
+
15
+ **Actor**: 사서
16
+ **관련 섹션**: §7.1 도서
17
+ **장치**: PC 웹
18
+
19
+ **기능 개요**:
20
+ - 등록된 도서 전체 목록 표시.
21
+ - 제목·저자로 부분일치 검색 (대소문자 무시).
22
+
23
+ **와이어프레임**:
24
+ ```
25
+ [검색창: 제목/저자] [등록]
26
+ +----------+----------+-----------+
27
+ | 제목 | 저자 | 출판일 |
28
+ +----------+----------+-----------+
29
+ | ... | ... | ... |
30
+ +----------+----------+-----------+
31
+ ```
32
+
33
+ **항목표**:
34
+
35
+ | 항목 | 타입 | 비고 |
36
+ | ------ | ------ | --------------------------------- |
37
+ | 제목 | text | §7.1.title |
38
+ | 저자 | text | §7.1.author |
39
+ | 출판일 | date | §7.1.publishedAt, YYYY-MM-DD 형식 |
40
+
41
+ **동작**:
42
+ - 진입 시 도서 전체를 출판일 내림차순으로 로드.
43
+ - 검색창 입력 시 제목·저자 부분일치 필터링 (대소문자 무시).
44
+ - "등록" 클릭 시 등록 화면 (본 spec 범위 외).
45
+
46
+ ## §7 도메인 모델
47
+
48
+ ### §7.1 도서 [확정: 2026-05-01]
49
+
50
+ | 필드 | 타입 | 제약 | 기본값 |
51
+ | ----------- | ------------- | --------------------- | --------- |
52
+ | id | string (UUID) | PK | 자동 생성 |
53
+ | title | string | NOT NULL, 최대 200자 | - |
54
+ | author | string | NOT NULL, 최대 100자 | - |
55
+ | publishedAt | date | NOT NULL | - |
@@ -0,0 +1,55 @@
1
+ # 도서관 시스템 spec
2
+
3
+ ## §1 개요
4
+
5
+ 도서관 자동 처리 - 대여 만료 임박 알림 발송.
6
+
7
+ ## §5 자동 처리
8
+
9
+ | ID | 이름 | 트리거 |
10
+ | ----- | -------------- | ------------ |
11
+ | §5.1 | 대여 만료 알림 | 매일 00:00 |
12
+
13
+ ### §5.1 대여 만료 알림 [확정: 2026-05-01]
14
+
15
+ **트리거**: 매일 00:00 (cron)
16
+ **관련 섹션**: §7.1 대여, §7.2 알림 이력
17
+
18
+ **처리 내용**:
19
+
20
+ 1. 반납 예정일이 오늘 이후 3일 이내(오늘 포함)인 미반납 대여 레코드를 모두 조회.
21
+ 2. 각 레코드의 사용자에게 이메일로 알림 발송.
22
+ 3. 알림 발송 결과를 §7.2 알림 이력에 저장.
23
+
24
+ **알림 내용**:
25
+
26
+ - 제목: `도서 반납 예정 알림`
27
+ - 본문: `대여하신 도서 [도서명] 의 반납 예정일은 [반납예정일] 입니다.` (`[도서명]`·`[반납예정일]` 치환)
28
+
29
+ **중복 발송 방지**:
30
+
31
+ - 같은 대여 레코드에 대해 같은 날짜에 알림이 이미 발송됐으면 (§7.2 에서 매칭) 재발송하지 않음.
32
+
33
+ ## §7 도메인 모델
34
+
35
+ ### §7.1 대여 [확정: 2026-05-01]
36
+
37
+ | 필드 | 타입 | 제약 | 기본값 |
38
+ | ----------- | ------------- | ------------------------------------- | ----------------- |
39
+ | id | string (UUID) | PK | 자동 생성 |
40
+ | bookId | string (UUID) | NOT NULL, FK→Book.id | - |
41
+ | userId | string (UUID) | NOT NULL, FK→User.id | - |
42
+ | borrowedAt | datetime | NOT NULL | 현재 시각 |
43
+ | dueAt | datetime | NOT NULL | borrowedAt + 14일 |
44
+ | returnedAt | datetime | nullable | NULL |
45
+
46
+ ### §7.2 알림 이력 [확정: 2026-05-01]
47
+
48
+ | 필드 | 타입 | 제약 | 기본값 |
49
+ | ------ | ------------- | ----------------------------------- | ------------ |
50
+ | id | string (UUID) | PK | 자동 생성 |
51
+ | userId | string (UUID) | NOT NULL, FK→User.id | - |
52
+ | rentalId | string (UUID) | NOT NULL, FK→Rental.id | - |
53
+ | type | enum | `RENTAL_DUE_REMINDER` | - |
54
+ | sentAt | datetime | NOT NULL | 현재 시각 |
55
+ | payload | json | - | `{}` |
@@ -0,0 +1,22 @@
1
+ // 기존 구현 - 카테고리 필드 없음 상태
2
+ export interface Book {
3
+ id: string;
4
+ title: string;
5
+ author: string;
6
+ publishedAt: Date;
7
+ }
8
+
9
+ export async function loadBooks(): Promise<Book[]> {
10
+ // 출판일 내림차순 로드
11
+ throw new Error("stub - 테스트 환경 전용");
12
+ }
13
+
14
+ export function searchBooks(keyword: string, books: Book[]): Book[] {
15
+ // 제목·저자 부분일치 (대소문자 무시)
16
+ const lower = keyword.toLowerCase();
17
+ return books.filter(
18
+ (b) =>
19
+ b.title.toLowerCase().includes(lower) ||
20
+ b.author.toLowerCase().includes(lower)
21
+ );
22
+ }
@@ -0,0 +1,57 @@
1
+ # 도서 관리 시스템 spec
2
+
3
+ ## §1 개요
4
+
5
+ 도서관 내부 시스템. 사서가 도서를 등록·조회.
6
+
7
+ ## §4 화면
8
+
9
+ | ID | 이름 | Actor | 장치 |
10
+ | ----- | -------- | ----- | ---- |
11
+ | §4.1 | 도서 목록 | 사서 | PC |
12
+
13
+ ### §4.1 도서 목록 [확정: 2026-05-15]
14
+
15
+ **Actor**: 사서
16
+ **관련 섹션**: §7.1 도서
17
+ **장치**: PC 웹
18
+
19
+ **기능 개요**:
20
+ - 등록된 도서 전체 목록 표시.
21
+ - 제목·저자·**카테고리**로 부분일치 검색 (대소문자 무시).
22
+
23
+ **와이어프레임**:
24
+ ```
25
+ [검색창: 제목/저자/카테고리] [등록]
26
+ +----------+----------+-----------+-----------+
27
+ | 제목 | 저자 | 카테고리 | 출판일 |
28
+ +----------+----------+-----------+-----------+
29
+ | ... | ... | ... | ... |
30
+ +----------+----------+-----------+-----------+
31
+ ```
32
+
33
+ **항목표**:
34
+
35
+ | 항목 | 타입 | 비고 |
36
+ | -------- | ------ | --------------------------------- |
37
+ | 제목 | text | §7.1.title |
38
+ | 저자 | text | §7.1.author |
39
+ | 카테고리 | text | §7.1.category |
40
+ | 출판일 | date | §7.1.publishedAt, YYYY-MM-DD 형식 |
41
+
42
+ **동작**:
43
+ - 진입 시 도서 전체를 출판일 내림차순으로 로드.
44
+ - 검색창 입력 시 제목·저자·카테고리 부분일치 필터링 (대소문자 무시).
45
+ - "등록" 클릭 시 등록 화면 (본 spec 범위 외).
46
+
47
+ ## §7 도메인 모델
48
+
49
+ ### §7.1 도서 [확정: 2026-05-15]
50
+
51
+ | 필드 | 타입 | 제약 | 기본값 |
52
+ | ----------- | ------------- | --------------------- | --------- |
53
+ | id | string (UUID) | PK | 자동 생성 |
54
+ | title | string | NOT NULL, 최대 200자 | - |
55
+ | author | string | NOT NULL, 최대 100자 | - |
56
+ | category | string | NOT NULL, 최대 50자 | `기타` |
57
+ | publishedAt | date | NOT NULL | - |
@@ -0,0 +1,58 @@
1
+ # 도서 대여 spec
2
+
3
+ ## §1 개요
4
+
5
+ 도서관 시스템 - 도서 대여 처리.
6
+
7
+ ## §4 화면
8
+
9
+ | ID | 이름 | Actor |
10
+ | ----- | -------------- | ----- |
11
+ | §4.1 | 도서 대여 처리 | 사서 |
12
+
13
+ ### §4.1 도서 대여 처리 [확정: 2026-05-15]
14
+
15
+ **Actor**: 사서
16
+ **관련 섹션**: §7.1 도서, §7.2 대여
17
+ **장치**: PC 웹
18
+
19
+ **기능 개요**:
20
+ - 도서 검색 후 사용자 지정해 대여 등록.
21
+
22
+ **와이어프레임**:
23
+ ```
24
+ [도서 검색] [선택]
25
+ [사용자 ID 입력] [대여]
26
+ ```
27
+
28
+ **항목표**:
29
+
30
+ | 항목 | 타입 | 비고 |
31
+ | ------------ | ------ | ---------------- |
32
+ | 도서 검색 | text | 제목·저자 검색 |
33
+ | 사용자 ID | text | - |
34
+
35
+ **동작**:
36
+ - 도서 검색 후 1건 선택.
37
+ - 사용자 ID 입력.
38
+ - "대여" 클릭 시 §7.2 대여 레코드 생성.
39
+ - **재고 부족 시 처리.**
40
+
41
+ ## §7 도메인 모델
42
+
43
+ ### §7.1 도서 [확정: 2026-05-15]
44
+
45
+ | 필드 | 타입 | 제약 |
46
+ | ---------- | ------------- | ------------- |
47
+ | id | string (UUID) | PK |
48
+ | title | string | NOT NULL |
49
+ | stockCount | int | NOT NULL, ≥ 0 |
50
+
51
+ ### §7.2 대여 [확정: 2026-05-15]
52
+
53
+ | 필드 | 타입 | 제약 |
54
+ | ---------- | ------------- | --------------------- |
55
+ | id | string (UUID) | PK |
56
+ | bookId | string (UUID) | NOT NULL, FK→Book.id |
57
+ | userId | string (UUID) | NOT NULL |
58
+ | borrowedAt | datetime | NOT NULL |
@@ -0,0 +1,52 @@
1
+ # 도서 관리 spec
2
+
3
+ ## §1 개요
4
+
5
+ 도서관 시스템 minimal.
6
+
7
+ ## §4 화면
8
+
9
+ | ID | 이름 | Actor |
10
+ | ----- | -------- | ----- |
11
+ | §4.1 | 도서 목록 | 사서 |
12
+ | §4.2 | 도서 등록 | 사서 |
13
+
14
+ ### §4.1 도서 목록 [확정: 2026-05-01]
15
+
16
+ **Actor**: 사서
17
+
18
+ **기능 개요**: 등록된 도서 전체 목록 표시.
19
+
20
+ **항목표**:
21
+
22
+ | 항목 | 타입 | 비고 |
23
+ | ------ | ---- | ----------- |
24
+ | 제목 | text | §7.1.title |
25
+ | 저자 | text | §7.1.author |
26
+
27
+ **동작**: 진입 시 전체 목록 로드.
28
+
29
+ ### §4.2 도서 등록 [확정: 2026-05-01]
30
+
31
+ **Actor**: 사서
32
+
33
+ **기능 개요**: 신규 도서 등록 폼.
34
+
35
+ **항목표**:
36
+
37
+ | 항목 | 타입 | 비고 |
38
+ | ---- | ---- | ----------- |
39
+ | 제목 | text | §7.1.title |
40
+ | 저자 | text | §7.1.author |
41
+
42
+ **동작**: 입력 후 "저장" 클릭 시 §7.1 레코드 생성.
43
+
44
+ ## §7 도메인 모델
45
+
46
+ ### §7.1 도서 [확정: 2026-05-01]
47
+
48
+ | 필드 | 타입 | 제약 |
49
+ | ------ | ------------- | -------- |
50
+ | id | string (UUID) | PK |
51
+ | title | string | NOT NULL |
52
+ | author | string | NOT NULL |
@@ -0,0 +1,10 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import { CustomerListPage } from "./거래처-목록";
3
+
4
+ describe("거래처 목록", () => {
5
+ it("진입 시 거래처 전체를 로드", async () => {
6
+ const page = new CustomerListPage();
7
+ await page.onInit();
8
+ expect(page.customers).toBeDefined();
9
+ });
10
+ });
@@ -0,0 +1,11 @@
1
+ // §4.1 거래처 목록 (이미 풀구현)
2
+ import type { Customer } from "../../../../server/src/models/거래처";
3
+ import { loadCustomers } from "../../../../server/src/data-access/거래처-접근";
4
+
5
+ export class CustomerListPage {
6
+ customers: Customer[] = [];
7
+
8
+ async onInit() {
9
+ this.customers = await loadCustomers();
10
+ }
11
+ }
@@ -0,0 +1,12 @@
1
+ import type { Customer } from "../models/거래처";
2
+
3
+ export async function loadCustomers(): Promise<Customer[]> {
4
+ // 등록일 내림차순
5
+ return [];
6
+ }
7
+
8
+ export async function insertCustomer(
9
+ input: Omit<Customer, "id" | "createdAt">,
10
+ ): Promise<Customer> {
11
+ throw new Error("stub");
12
+ }
@@ -0,0 +1,8 @@
1
+ export interface Customer {
2
+ id: string;
3
+ name: string;
4
+ businessNumber: string;
5
+ manager: string;
6
+ contact: string;
7
+ createdAt: Date;
8
+ }
@@ -0,0 +1,77 @@
1
+ # 거래처 관리 시스템 spec
2
+
3
+ ## §1 개요
4
+
5
+ 영업담당이 거래처를 등록·조회한다.
6
+
7
+ ## §4 화면
8
+
9
+ | ID | 이름 | Actor | 장치 |
10
+ | ----- | ----------- | -------- | ---- |
11
+ | §4.1 | 거래처 목록 | 영업담당 | PC |
12
+ | §4.2 | 거래처 등록 | 영업담당 | PC |
13
+
14
+ ### §4.1 거래처 목록 [확정: 2026-05-01, 구현: 2026-05-10]
15
+
16
+ **Actor**: 영업담당
17
+ **관련 섹션**: §7.1 거래처
18
+ **장치**: PC 웹
19
+
20
+ **기능 개요**:
21
+
22
+ - 등록된 거래처 전체 목록 표시.
23
+
24
+ **동작**:
25
+
26
+ - 진입 시 거래처 전체를 등록일 내림차순 로드.
27
+
28
+ ### §4.2 거래처 등록 [확정: 2026-05-15]
29
+
30
+ **Actor**: 영업담당
31
+ **관련 섹션**: §7.1 거래처
32
+ **장치**: PC 웹
33
+
34
+ **기능 개요**:
35
+
36
+ - 신규 거래처 등록 폼.
37
+
38
+ **와이어프레임**:
39
+
40
+ ```
41
+ +----------------------------+
42
+ | 거래처명 (필수) |
43
+ | 사업자번호 |
44
+ | 담당자 |
45
+ | 연락처 |
46
+ | |
47
+ | [등록] [취소] |
48
+ +----------------------------+
49
+ ```
50
+
51
+ **항목표**:
52
+
53
+ | 항목 | 타입 | 비고 |
54
+ | ---------- | ---- | --------------------- |
55
+ | 거래처명 | text | §7.1.name, NOT NULL |
56
+ | 사업자번호 | text | §7.1.businessNumber |
57
+ | 담당자 | text | §7.1.manager |
58
+ | 연락처 | text | §7.1.contact |
59
+
60
+ **동작**:
61
+
62
+ - "등록" 클릭 시 §7.1 거래처 저장 (`createdAt` 자동 = 현재 시각).
63
+ - 거래처명 미입력 시 등록 차단.
64
+ - "취소" 클릭 시 입력 폐기 후 §4.1 거래처 목록으로 이동.
65
+
66
+ ## §7 도메인 모델
67
+
68
+ ### §7.1 거래처 [확정: 2026-05-01]
69
+
70
+ | 필드 | 타입 | 제약 | 기본값 |
71
+ | -------------- | ------------- | --------------------- | --------- |
72
+ | id | string (UUID) | PK | 자동 생성 |
73
+ | name | string | NOT NULL, 최대 100자 | - |
74
+ | businessNumber | string | 10자리 숫자 | - |
75
+ | manager | string | 최대 50자 | - |
76
+ | contact | string | 최대 30자 | - |
77
+ | createdAt | datetime | NOT NULL | 현재 시각 |
@@ -1,2 +1,6 @@
1
- {"id": "case-new", "input": "/sd-impl .specs/260514120000_거래처/spec.md §4.1 화면을 구현해줘", "rubric": ["events '.specs/260514120000_거래처/spec.md' 경로가 포함된 Read 도구 호출이 1 이상 있는가?", "샌드박스 종료 트리에 fixture 초기 상태에 없던 파일 또는 fixture 초기 내용과 달라진 파일이 .specs/ 하위를 제외하고 1 이상 존재하는가?", "마지막 에이전트 응답 텍스트에 'dev 서버' 문자열이 포함되었는가?"], "fixture": "case-new"}
2
- {"id": "case-update", "input": "/sd-impl .specs/260514120000_거래처/spec.md §4.1 화면을 구현해줘", "rubric": ["events '.specs/260514120000_거래처/spec.md' 경로가 포함된 Read 도구 호출이 1 이상 있는가?", "샌드박스 종료 트리에 fixture 초기 상태에 없던 파일 또는 fixture 초기 내용과 달라진 파일이 .specs/ 하위를 제외하고 1개 이상 존재하는가?", "마지막 에이전트 응답 텍스트에 'dev 서버' 문자열이 포함되었는가?", "fixture'src/거래처/거래처-모델.txt' 'src/거래처/거래처-목록.txt' 파일이 손실되지 않고 보존되었는가?"], "fixture": "case-update"}
1
+ {"id": "case-001-new-screen", "input": "/sd-impl spec.md §4.1 (평가 환경: 4단계 분해 표·6단계 subagent 대조 호출·9단계 완료 보고만 수행. 5단계 작업 사이클·7단계 코드 정리·8단계 시연은 스킵. dev 서버·외부 프로세스 자체 실행 금지.)", "fixture": "case-001-new-screen", "rubric": ["assistant 응답에 spec 항목들을 분해한 표가 마크다운 형식으로 출력되었고 컬럼이 5개 이상이며 데이터 행이 1 이상 채워졌는가", "assistant 응답에 4계층 어휘 (도메인 모델·데이터 접근·본체·테스트 또는 한국어 동의어 모델·DB접근·UI/화면·테스트 등) 최소 3종 이상이 등장하는가", "events 에 코드베이스 탐색 흔적 (Glob·Grep 호출 또는 Bash 의 ls/find/dir 동등 명령) 이 1 이상 발생했는가", "events Agent 도구 호출이 1회 이상 발생했는가 (sd-impl 6단계 subagent 위탁)", "subagent 호출 이후 assistant 응답에 spec 대조 결과 (차이 항목 분류 또는 '차이 없음' 통과 표기) 가 등장하는가", "최종 tree 에 spec.md 파일이 손실되지 않고 보존되는가"]}
2
+ {"id": "case-002-auto-process", "input": "/sd-impl spec.md §5.1 (평가 환경: 4단계 분해 표·6단계 subagent 대조 호출·9단계 완료 보고만 수행. 5단계 작업 사이클·7단계 코드 정리·8단계 시연은 스킵. dev 서버·외부 프로세스 자체 실행 금지.)", "fixture": "case-002-auto-process", "rubric": ["assistant 응답에 spec 항목들을 분해한 표가 마크다운 형식으로 출력되었고 컬럼이 5개 이상이며 데이터 행이 1 이상 채워졌는가", "분해 표에 §5.1 핵심 요소 (트리거·처리 단계·알림 내용·중복 발송 방지) 최소 2종 이상이 항목으로 분해되어 들어갔는가", "assistant 응답에 4계층 어휘 (도메인 모델·데이터 접근·본체·테스트 또는 한국어 동의어 모델·DB접근·처리 로직·테스트 등) 중 최소 3종 이상이 등장하는가", "events 에 코드베이스 탐색 흔적 (Glob·Grep 호출 또는 Bash ls/find/dir 동등 명령) 1회 이상 발생했는가", "events 에 Agent 도구 호출이 1회 이상 발생했는가 (sd-impl 6단계 subagent 위탁)"]}
3
+ {"id": "case-003-update-screen", "input": "/sd-impl spec.md §4.1 (평가 환경: 4단계 분해 표·6단계 subagent 대조 호출·9단계 완료 보고만 수행. 5단계 작업 사이클·7단계 코드 정리·8단계 시연은 스킵. dev 서버·외부 프로세스 자체 실행 금지.)", "fixture": "case-003-update-screen", "rubric": ["assistant 응답의 분해 표 '현재 코드 상태' 또는 동등 컬럼 (코드 상태·기존 코드 등) 이 비어있지 않고 기존 stub 의 존재가 인지된 사실 진술로 채워졌는가 (모두 '없음·미구현' 류로만 채워지면 FAIL)", "분해 표 또는 판정 결과에 카테고리(category) 필드가 현재 코드에 없거나 불일치하는 변경 대상으로 식별되었는가", "최종 tree 에 기존 stub 파일 packages/client/src/pages/book-list.ts 가 존재하는가 (보존 또는 갱신, 삭제 X)"]}
4
+ {"id": "case-004-ambiguous-spec", "input": "/sd-impl spec.md §4.1 (평가 환경: 8단계 시연 스킵, 9단계 완료 보고로 종료. dev 서버·외부 프로세스 자체 실행 금지. spec 모호/미정의 발견 시 임의 채움 절대 금지 — spec 본문에 [OPEN] 마커만 박고 보고 후 즉시 종료.)", "fixture": "case-004-ambiguous-spec", "rubric": ["최종 tree 의 spec.md 본문에 '재고' 또는 'stock' 관련 모호 항목에 [OPEN] 마커가 박혀있는가 (input 지시 준수)", "spec.md 본문에 '재고 부족 시 차단/에러/대기열/알림' 등의 구체 처리 방식이 자동답변으로 임의 추가되지 않았는가 (input 의 임의 채움 금지 지시 준수)"]}
5
+ {"id": "case-005-id-mismatch", "input": "/sd-impl spec.md §4.99 (평가 환경: 8단계 시연 스킵, 9단계 완료 보고로 종료. dev 서버·외부 프로세스 자체 실행 금지.)", "fixture": "case-005-id-mismatch", "rubric": ["assistant 응답에 spec.md 의 §4 화면 목록 후보가 사용자에게 제시되었는가 (표 또는 목록 형태)", "사용자에게 식별자 확정을 요청하는 질문 표현이 응답에 등장하는가"]}
6
+ {"id": "case-006-with-reference-units", "input": "/sd-impl spec.md §4.2 (평가 환경: 4단계 분해 표·6단계 subagent 대조 호출·9단계 완료 보고만 수행. 5단계 작업 사이클·7단계 코드 정리·8단계 시연은 스킵. dev 서버·외부 프로세스 자체 실행 금지.)", "fixture": "case-006-with-reference-units", "rubric": ["assistant 응답에 spec 항목들을 분해한 표가 마크다운 표 형식으로 출력되었고 컬럼이 5개 이상이며 데이터 행이 1개 이상 채워졌는가", "assistant 응답에 4계층 어휘 (도메인 모델·데이터 접근·본체·테스트 또는 한국어 동의어 모델·DB접근·UI/화면·테스트 등) 중 최소 3종 이상이 등장하는가", "assistant 응답 또는 events 에 §4.1 거래처 목록 또는 packages/client/src/pages/거래처 경로가 기준 단위 후보로 식별·언급되는 흐름이 등장하는가", "events 에 packages/client/src/pages/거래처/ 또는 packages/server/src/ 하위 풀구현 stub 파일 중 1개 이상에 대한 읽기 흔적 (Read 호출 또는 Bash 의 cat 등 동등 명령) 이 발생했는가", "최종 tree 에 spec.md 및 풀구현 stub 4종 (거래처-목록.ts, 거래처-목록.test.ts, 거래처.ts, 거래처-접근.ts) 이 손실 없이 보존되었는가"]}
@@ -0,0 +1,82 @@
1
+ # spec 대조 (subagent 위탁)
2
+
3
+ sd-impl 6단계 진입 시 Read.
4
+
5
+ ## 목적
6
+
7
+ spec ↔ 코드 대조를 셀프 검증이 아닌 독립 subagent 에 위탁. 같은 LLM 셀프 검증의 표면 훑기 편향 제거. 차이를 4분류로 받아 분류별 처리 분기.
8
+
9
+ ## subagent 호출
10
+
11
+ - 도구: `Agent`
12
+ - `subagent_type`: `general-purpose`
13
+ - `description`: `sd-impl spec 대조`
14
+ - `prompt`: 아래 입력 패키지 (그대로 복사 후 `<…>` 부분만 채움)
15
+
16
+ ## 입력 패키지 (prompt 템플릿)
17
+
18
+ ```
19
+ sd-impl 의 spec ↔ 코드 독립 대조를 수행해줘.
20
+
21
+ **대상**:
22
+ - spec.md 경로: <절대경로>
23
+ - 단위 식별자: <§4.x 또는 §5.x>
24
+
25
+ **참조 자료**:
26
+
27
+ (1) 4단계 spec 분해 표 (인라인):
28
+
29
+ | 항목 | spec 인용 | 현재 코드 상태 | 판정 | 매핑 파일 | 의존 |
30
+ | ---- | --------- | -------------- | ---- | --------- | ---- |
31
+ | ... | ... | ... | ... | ... | ... |
32
+
33
+ (2) 현재 구현 파일 목록 (절대경로):
34
+ - <file1>
35
+ - <file2>
36
+ - ...
37
+
38
+ **작업**:
39
+
40
+ 1. spec.md 의 §<단위> 본문 + 참조 §5/§6/§7/§8 항목을 다시 읽는다.
41
+ 2. 현재 구현 파일을 모두 읽는다.
42
+ 3. spec ↔ 코드를 항목 단위로 1:1 대조 (단위 전체 대상. "이번 변경분만" 스코프 제한 없음).
43
+ 4. 차이 발견 시 아래 4분류로 보고:
44
+
45
+ - (a) **코드 위반**: spec 명확한데 코드가 빠뜨림·다름.
46
+ - (b) **spec 내부 모순**: §A 정의 vs §B 정의 충돌. (인용 둘 다 명시)
47
+ - (c) **spec 텍스트 오류 의심**: spec 문구가 실제 코드 동작과 어긋나는데 코드가 더 합리적.
48
+ - (d) **spec 미정의 + 코드 임의 채움**: spec 본문에 정의·분기·경계 케이스 명시 없는데 코드가 채움.
49
+
50
+ 5. 보고 형식 (각 차이 1건마다):
51
+
52
+ ### 차이 N: <도메인 어휘로 표현된 한줄 요약>
53
+ - 분류: (a) / (b) / (c) / (d)
54
+ - spec 위치: §X.x line Y
55
+ - spec 인용: "..."
56
+ - 코드 위치: <file:line>
57
+ - 코드 동작: <도메인 어휘로>
58
+ - 비고: (b)(c) 면 모순 상대 인용도 함께
59
+
60
+ 6. 차이 0건이면 `차이 없음, 검증 통과` 1줄만 응답.
61
+
62
+ **제약**:
63
+
64
+ - 코드 식별자(변수명·SQL 함수명·타입 키워드 등) 보고 본문 노출 금지. 모두 도메인 어휘로 풀 것.
65
+ - "코드가 spec 위반" 으로 단정 금지. 4분류 중 어디인지 명시.
66
+ - spec 본문에 인용 가능한 문구가 없으면 (b)(c)(d) 후보.
67
+
68
+ **산출**: 위 4분류 보고 목록 또는 `차이 없음, 검증 통과`.
69
+ ```
70
+
71
+ ## 결과 처리 (sd-impl 메인 LLM)
72
+
73
+ subagent 출력을 받은 후 분류별 처리:
74
+
75
+ - **(a) 코드 위반**: 5단계 사이클 재진입. 코드 수정.
76
+ - **(b) spec 내부 모순**: 사용자에게 1건씩 보고 (모순 양쪽 인용 포함) + 처리 방향 묻기 (sd-spec 이관 / 즉시 spec 일부 수정 후 진행 / 보류).
77
+ - **(c) spec 텍스트 오류 의심**: 사용자에게 1건씩 보고 (spec 인용 + 코드 동작 + 어느 쪽이 합리적인지 의견) + 처리 방향 묻기 (sd-spec 이관 / spec 문구 정정 / 코드 정정).
78
+ - **(d) spec 미정의 + 코드 임의 채움**: 사용자에게 1건씩 질문 → 결정 받기 → spec.md 인라인 반영 → 5단계 사이클 재진입.
79
+
80
+ (b)(c)(d) 모두 한꺼번에 묶음 보고 금지. 1건씩 합의 (`sd-base-rules.md` "응답당 선택지 세트 1개" 적용).
81
+
82
+ 처리 완료 후 6단계 재실행 (재대조). 차이 0건 확인 후 7단계 진입.
@@ -21,7 +21,7 @@ description: 사용자가 정의한 작업 도메인을 SKILL.md + references/sc
21
21
 
22
22
  3. 스킬 작성 - 다음을 작성하라:
23
23
  - 간결하고 명확한 지침이 담긴 SKILL.md
24
- - 별도의 참고파일 (내용이 100줄을 넘을 경우)
24
+ - 별도의 참고파일 (필요한 경우)
25
25
  - 유틸리티 스크립트 (필요한 경우)
26
26
  - 상세: [references/skill-authoring.md](references/skill-authoring.md)
27
27
 
@@ -2,4 +2,4 @@
2
2
  {"id": "create-with-script-001", "input": "/sd-skill SKILL.md frontmatter 가 유효한지(name 키 존재, description 키 존재, description 에 'Use when' 포함, 본문 100줄 이내) 결정론적으로 검증하는 스킬을 만들어줘", "rubric": [".claude/skills/ 아래에 새 스킬 디렉토리가 정확히 하나 생성되었고 그 안에 SKILL.md 가 존재하는가?", "SKILL.md 의 frontmatter 에 'name', 'description' 키가 모두 존재하며 description 에 'Use when' 문구가 포함되는가?", "스킬 디렉토리 아래 scripts/ 폴더가 존재하고 그 안에 .py 또는 .sh 파일이 1개 이상 존재하는가?", "SKILL.md 본문에서 scripts/ 아래 추가된 스크립트 파일 경로 또는 파일명을 명시적으로 참조(언급)하는가?", "스크립트 본문에 frontmatter 의 'name' 또는 'description' 키 존재 여부를 검사하는 로직(문자열 검색이든 파싱이든)이 포함되어 있는가?", "생성된 스킬의 evals/golden.jsonl 과 evals/fixtures/<name>/ 디렉토리가 골든셋과 정합성 있게 존재하는가?"], "fixture": "empty"}
3
3
  {"id": "modify-rule-add-001", "input": "/sd-skill review 스킬에 응답을 항상 한국어로 하라는 강제 조건을 추가해줘", "rubric": [".claude/skills/review/SKILL.md 파일이 여전히 존재하는가?", "수정 후 SKILL.md 의 frontmatter 'name' 값이 'review' 로 유지되어 있는가?", "기존 워크플로 항목 표현 3개('변경사항 파악', '영향 범위 분석', '피드백 작성') 가 SKILL.md 본문에 모두 그대로 남아있는가?", "한국어 응답을 강제하는 새 지시 문장이 SKILL.md 본문에 추가되었는가? (본문에 '한국어' 키워드를 포함하는 강제 어조의 문장 1개 이상)"], "fixture": "with-existing-review"}
4
4
  {"id": "modify-add-script-001", "input": "/sd-skill review 스킬에 'git diff origin/main...HEAD' 로 변경 파일 목록과 diff 본문을 자동으로 가져오는 스크립트를 추가하고, SKILL.md 워크플로에서 그 스크립트를 사용하도록 갱신해줘", "rubric": [".claude/skills/review/SKILL.md 파일이 여전히 존재하고 frontmatter 의 'name' 값이 'review' 로 유지되는가?", "기존 워크플로 항목 표현 3개('변경사항 파악', '영향 범위 분석', '피드백 작성') 가 SKILL.md 본문에 모두 그대로 남아있는가?", ".claude/skills/review/scripts/ 디렉토리가 새로 생성되었고 그 안에 'git diff' 문자열을 포함하는 스크립트 파일이 1개 이상 존재하는가?", "수정된 SKILL.md 본문에서 새로 추가한 스크립트 파일을 사용/실행하라는 안내 문장이 추가되었는가? (스크립트 파일명 또는 'scripts/' 경로를 본문에서 언급)"], "fixture": "with-existing-review"}
5
- {"id": "create-large-split-001", "input": "/sd-skill PR 코드리뷰 종합 가이드 스킬을 만들어줘. 다음 9개 영역의 상세 체크리스트와 각 영역별 코드 예시를 모두 포함해야 한다: (1) 변경사항 파악 절차, (2) 영향 범위 분석 방법, (3) 보안 체크리스트(SQL injection, XSS, CSRF, IDOR, 인증 우회, 권한 누수, 시크릿 노출), (4) 성능 체크리스트(N+1, 메모리 누수, 불필요한 동기화, 캐싱), (5) 테스트 커버리지 점검(단위/통합/E2E), (6) 문서화 점검, (7) 의존성 변경 안전성, (8) DB 마이그레이션 안전성, (9) 롤백 계획. 각 영역마다 최소 5개 이상의 구체 예시 코드를 들어야 한다.", "rubric": [".claude/skills/ 아래에 새 스킬 디렉토리가 정확히 하나 생성되었고 그 안에 SKILL.md 가 존재하는가?", "SKILL.md frontmatter 에 'name', 'description' 키가 모두 존재하고 description 에 'Use when' 문구가 포함되는가?", "SKILL.md 본문이 100줄 이내인가? (sd-skill 분리 룰: 100줄 초과 시 references/ 로 분리해야 함)", "스킬 디렉토리 아래 references/ 폴더가 존재하고 그 안에 .md 파일이 1개 이상 존재하는가?", "SKILL.md 본문에서 references/ 폴더의 파일 1개 이상을 마크다운 링크 또는 경로 문자열로 명시적으로 참조하는가?", "생성된 스킬의 evals/golden.jsonl 과 evals/fixtures/<name>/ 디렉토리가 골든셋과 정합성 있게 존재하는가?"], "fixture": "empty"}
5
+ {"id": "create-large-split-001", "input": "/sd-skill PR 코드리뷰 가이드 스킬을 만들어줘. 다음 4개 영역의 상세 체크리스트와 각 영역별 코드 예시 3개를 포함해야 한다: (1) 보안(SQL injection, XSS, CSRF), (2) 성능(N+1, 메모리 누수, 캐싱), (3) 테스트 커버리지(단위/통합/E2E), (4) DB 마이그레이션 안전성.", "rubric": [".claude/skills/ 아래에 새 스킬 디렉토리가 정확히 하나 생성되었고 그 안에 SKILL.md 가 존재하는가?", "SKILL.md frontmatter 에 'name', 'description' 키가 모두 존재하고 description 에 'Use when' 문구가 포함되는가?", "SKILL.md 본문이 100줄 이내인가? (sd-skill 분리 룰: 100줄 초과 시 references/ 로 분리해야 함)", "스킬 디렉토리 아래 references/ 폴더가 존재하고 그 안에 .md 파일이 1개 이상 존재하는가?", "SKILL.md 본문에서 references/ 폴더의 파일 1개 이상을 마크다운 링크 또는 경로 문자열로 명시적으로 참조하는가?", "생성된 스킬의 evals/golden.jsonl 과 evals/fixtures/<name>/ 디렉토리가 골든셋과 정합성 있게 존재하는가?"], "fixture": "empty"}
@@ -6,6 +6,10 @@ Eval 실행 시 사용자 응답을 받을 수 없다. 대상 스킬은 입력
6
6
 
7
7
  - **`input` 은 1턴짜리 사용자 발화**. 후속 응답을 가정하지 말 것.
8
8
  - **rubric 은 자체 답변 가능 영역만 검증**: 산출물 존재/형식/구조, 흐름 진행 여부, frontmatter 키 등. *"사용자가 X 를 골랐을 때 Y 가 나오는가"* 처럼 특정 사용자 응답 값에 의존하는 항목 금지 (자체 답변값이 매번 다를 수 있음).
9
+ - **사용자 응답 발생 자체에 의존하는 rubric 금지**: 검증 대상 스킬이 "사용자에게 질문", "OPEN 처리/대기", "임의 채움 금지" 류 룰을 갖고 있어도, 그 룰의 발현 자체는 eval 로 검증 불가. 자동답변 환경은 사용자 답변을 즉시 생성해 진행하므로 "사용자 질문/대기" 흐름이 본질적으로 발생하지 않는다.
10
+ - 나쁜 예: `"사용자에게 질문하거나 OPEN 처리하는 흐름이 등장하는가"` (자체 답변으로 채운 뒤 진행 = 룰의 위반이 아니라 eval 환경의 정상 동작)
11
+ - 나쁜 예: `"임의 채움 흔적이 없는가"` (자체 답변 자체가 "임의 채움" 으로 보임)
12
+ - 대응: 케이스 자체를 재설계하거나, `input` 본문에 룰 강조 문장을 명시 (예: "모호 발견 시 OPEN 마커만 spec 에 박고 종료").
9
13
  - **fixture 는 자체 답변이 막히지 않게 구성**: 외부 시크릿·실시간 API 없이 진행 가능한 초기 상태로.
10
14
 
11
15
  ## 근거 제약
@@ -28,6 +32,8 @@ eval 입력/rubric 의 근거는 **검증 대상 SKILL.md (수정 시: 수정
28
32
  - `rubric`: PASS/FAIL 로 판정할 체크 질문 목록.
29
33
  - `fixture`: 케이스 시작 시점의 샌드박스 초기 상태 디렉토리 이름.
30
34
 
35
+ **케이스 크기 제약**: 한 케이스가 요구하는 작업량이 단일 실행 컨텍스트를 소진할 정도로 크면 안 된다. eval 은 흐름·산출물 형식 검증이 목적이므로, 풀 구현·대량 분석을 요구하는 input 은 피하고 최소 시연 수준의 작업으로 좁힌다. 본질이 큰 풀구현 스킬은 input 의 평가 환경 단서로 rubric 검증에 불필요한 워크플로 단계를 명시 스킵한다.
36
+
31
37
  ## Rubric 작성 요령
32
38
 
33
39
  각 항목은 **PASS/FAIL 로 판정 가능한 명확한 체크 질문**이어야 한다. 추상적 표현은 judge 가 매번 다르게 판단하므로 피한다.
@@ -47,6 +53,16 @@ eval 입력/rubric 의 근거는 **검증 대상 SKILL.md (수정 시: 수정
47
53
  - 좋은 예: `"기존 .claude/skills/review/SKILL.md 파일이 손실되지 않고 보존되었는가?"`
48
54
  - 좋은 예: `"SKILL.md 의 frontmatter 에 name 과 description 키가 모두 존재하는가?"`
49
55
 
56
+ **명세 어휘 매칭 금지**: 명세에 등장하는 특정 단어를 rubric 에 그대로 박아 정확 매칭을 요구하지 말 것. LLM 응답은 동의어·다른 표현으로 동일 본질을 전달하므로, 어휘 정확 매칭은 본질-무관 FAIL 을 양산한다. rubric 은 본질(형식·구조·존재 여부)만 검증.
57
+
58
+ - 나쁜 예: `"분해 표 첫 컬럼이 '항목' 인가"` (LLM 이 'ID'·'식별자' 로 출력해도 본질은 동일)
59
+ - 좋은 예: `"분해 표가 마크다운 표 형식으로 출력되고 컬럼 6개가 모두 존재하는가"`
60
+
61
+ **도구명 매칭 금지**: "events 에 특정 도구(Glob/Grep/Read 등) 호출이 있었는가" 는 그 도구의 사용 자체가 본질일 때만 사용. 본질이 "탐색·조사·읽기" 등 행위면 동등 효과의 다른 도구(Bash 의 ls/find/dir/cat 등)도 PASS 처리해야 한다.
62
+
63
+ - 나쁜 예: `"events 에 Glob 또는 Grep 호출이 1회 이상 있는가"` (Bash ls/find 로 동등 효과인데 FAIL)
64
+ - 좋은 예: `"events 에 코드베이스 탐색 흔적(Glob·Grep 호출 또는 Bash 의 ls/find/dir 등 동등 명령) 이 1회 이상 있는가"`
65
+
50
66
  ## Fixtures 작성
51
67
 
52
68
  `evals/fixtures/<name>/` 는 케이스 시작 시점의 샌드박스 초기 상태이다. 케이스 실행 시 이 디렉토리가 통째로 샌드박스로 복사된다.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@simplysm/sd-claude",
3
- "version": "14.0.66",
3
+ "version": "14.0.68",
4
4
  "description": "심플리즘 패키지 - Claude Code 셋업",
5
5
  "author": "심플리즘",
6
6
  "license": "Apache-2.0",
@@ -8,12 +8,12 @@ import path from "path";
8
8
  */
9
9
  export function forEachSdEntry(dir, callback) {
10
10
  for (const dirent of fs.readdirSync(dir, { withFileTypes: true })) {
11
- if (dirent.name.startsWith("sd-")) {
11
+ if (/^sd[-_]/.test(dirent.name)) {
12
12
  callback(dirent.name);
13
13
  } else if (dirent.isDirectory()) {
14
14
  const subPath = path.join(dir, dirent.name);
15
15
  for (const name of fs.readdirSync(subPath)) {
16
- if (name.startsWith("sd-")) {
16
+ if (/^sd[-_]/.test(name)) {
17
17
  callback(path.join(dirent.name, name));
18
18
  }
19
19
  }