유닛 맵 — 요구사항 · 화면 · 게이트가 어느 유닛에 걸리나
여기 스토리는 없다. 파일 이름은 v1 의 것을 그대로 썼고(경로를 바꾸면 뒤
단계가 읽는 자리와 갈린다), 안에 들어간 것은 셋이다.
FR-1 ~ FR-29 requirements.md 4절의 추적표
화면 일곱 S0 · S0b · S1 · S1b · S2 · S3 · S5
조각 게이트 여섯 CP0 ~ CP5
FR-26 ~ FR-29 와 CP5 는 2026-09-05 에 들어왔다 — Mediator MCP 의 이월을
진행자가 되돌렸다 (requirements/decisions.md 5절). 화면은 안 는다: MCP 가
화면을 안 만든다.
User Stories 를 건너뛴 근거는 aidlc-state.md 실행 계획 3절이다 — 요약하면
scene-gates.md §1 이 이미 페르소나 둘(dhseo · taeels)의 장면이고 §2 가
조각마다 수용 기준을, §2.1 이 화면 검증을 갖고 있다. 스토리를 새로 내면
같은 것의 두 번째 정본이 생긴다. 그래서 묶는 축이 스토리가 아니라 장면이다.
1. 장면 -> 조각 -> 유닛
dhseo 장면 하나를 다섯 조각으로 자른 것이 scene-gates.md 이고, 조각마다
그것을 초록으로 만드는 유닛이 있다.
장면의 순간 조각 유닛
────────────────────────────────────────────── ──── ────────────
(기동이 안 깨졌다 — 장면 밖의 바닥) CP0 U-바닥
① 보드가 함대에 있다. 현황판에 보인다 CP1 U-관측API
② 계약이 온다. 보드가 잡힌다 CP1 U-관측API
③ 둘째 계약이 QUEUED. 둘 다 보인다 CP2 U-대기열
④ 제어판에서 at-boundary 로 drain 을 건다 CP3/CP4 U-drain / U-제어판
⑤ 경계에서 임대가 풀린다. draining 이 보인다 CP3 U-drain
⑥ dhseo 가 보드를 쓴다. LED 가 새 패턴이다 CP4 전부
⑦ drain 을 푼다. 둘째 계약이 보드를 집는다 CP3/CP4 U-drain / U-제어판
④ 와 ⑦ 이 조각 둘에 걸치는 것은 같은 일을 두 표면이 한다는 뜻이다.
CP3 은 정책 파일로 걸고 풀고, CP4 는 같은 것을 제어판 버튼으로 한다.
scene-gates.md §2.1 이 CP3 을 「화면 없음」으로 둔 이유가 이것이다.
2. FR -> 유닛
requirements.md §4 의 추적표를 유닛 쪽으로 뒤집었다. FR-1 ~ FR-25 가
빠짐없이 어느 유닛엔가 걸린다.
U-바닥 (CP0)
FR-1 GET /v1/nodes 의 저장 쪽 — ListNodes
FR-2 GET /v1/runs 의 저장 쪽 — ListRuns
FR-3 StepView.chosen. DB 에 있고 뷰에 없었다
FR-6 runs.state 어휘에 QUEUED (상수와 자리)
FR-13 정책 자리 — nodes 열과 UpsertAdvert 시그니처
U-관측API (CP1)
FR-1 GET /v1/nodes 라우트
FR-2 GET /v1/runs 라우트 + current[] + reject
FR-4 임대는 GET /v1/nodes 에 내장. 별도 표면 없음
FR-5 중앙 현황판 정적 파일 — S0 · S0b · S1 · S1b · S2
FR-16 화면 몫 — draining 배지 두 국면
U-대기열 (CP2)
FR-6 409 -> QUEUED, 제출 응답 202. 422 는 그대로 FAILED
FR-7 QUEUED Run 의 steps 를 제출 시점에 만든다
FR-8 승격 — WakeQueued 가 도착 순서로 전부 훑는다
FR-9 깨우기 다섯 지점 (여섯째는 U-drain)
FR-10 기동 시 WakeQueued 한 번
FR-11 중앙 쪽 — submit 이 busy 에 DrainingNodes 를 합친다
U-drain (CP3)
FR-9 여섯째 깨우기 — drain 해제를 받은 광고 처리
FR-11 노드 쪽 — 매칭에서 draining 노드 제외
FR-12 정책 자리. 정본은 노드의 파일. 위치와 형식은 Functional Design
FR-13 경로 — 읽기 · 싣기 · 복사 · 되돌리기 · Worker 에 넘기기
FR-14 두 모드. graceful 과 at-boundary
FR-15 해제는 소유자 명시
FR-16 drain 중에도 광고를 계속 보낸다
U-제어판 (CP4)
FR-17 enodectl serve [name]. 이 기계의 노드를 전부 서브한다
FR-18 프로세스 제어 — status · start · stop · logs
FR-19 신원 — node_id · label · principal · instance
FR-20 탐지 능력 읽기 전용
FR-21 현재 작업. 출처는 Mediator 조회
FR-22 drain 토글 — 걸기 · 모드 고르기 · 풀기
FR-23 Mediator 연결 상태와 마지막 응답 시각
FR-24 호스트 화면 S3 · S5
FR-25 마지막 관측 캐시. observed 와 stale
U-MCP (CP5)
FR-26 runctl mcp — stdio JSON-RPC 하나. 새 실행파일 없음
FR-27 토큰은 환경변수. 도구 인자로 안 받는다
FR-28 도구 일곱. 전부 기존 REST 를 감싼다
FR-29 runctl.Client 에 Nodes · Runs 두 메서드
셈
유닛에 한 번 이상 걸린 FR 29
어느 유닛에도 안 걸린 FR 0
유닛 둘에 걸린 FR FR-1 · FR-2 · FR-6 · FR-9 · FR-11 · FR-13 · FR-16
일곱. 전부 저장 쪽과 표면 쪽으로 갈린 것이다
유닛 하나에만 걸린 새 넷 FR-26 ~ FR-29 는 전부 U-MCP 다. 저장 쪽이 없다 —
이 유닛이 DB 도 Mediator 도 안 건드리기 때문이다
3. NFR -> 유닛
기능이 아닌 요구는 완료 조건으로 걸린다. unit-of-work.md 의 유닛마다
완료 조건에 번호가 박혀 있고, 여기는 그 반대 방향의 색인이다.
| 묶음 | 유닛 |
|---|---|
| NFR-S1 · S2 · S3 · S7 · S8 (바인딩 · 토큰 · 파일 권한) | U-제어판 |
| NFR-S4 · S5 (라우트 토큰 · 입력 검증) | U-관측API |
| NFR-S6 (HTML 표면 헤더 넷) | U-관측API · U-제어판 |
| NFR-S9 (오류 문구) | U-관측API · U-제어판 |
NFR-I1 · I2 (불변식 · READY 안 만들기) |
U-바닥 · U-대기열 |
| NFR-I3 (중앙 drain 라우트 없음) | U-drain |
NFR-I4 (match.Match 안 고침) |
U-바닥 · U-대기열 |
| NFR-I5 (단계 도중에 안 끊음) | U-drain |
| NFR-I6 (dry-run 응답 불변) | U-대기열 · U-drain |
NFR-I7 (재제출 200) |
U-대기열 |
| NFR-P1 ~ P6 (패키지 경계) | U-바닥이 검사기를 내고 U-제어판 · U-관측API 가 지킨다 |
| NFR-O1 ~ O6 (폴링 · 갱신 · 배지) | U-관측API · U-제어판 |
| NFR-Q1 ~ Q5 (품질 게이트) | 전부. CP0 ~ CP4 마다 돈다 |
4. 화면 -> 유닛 -> 게이트
화면이 있는 유닛의 완료 조건은 그 화면의 버튼을 전부 나열한다
(scene-gates.md §2.1 · design/README.md §7). 목록은 unit-of-work.md
안에 있고 여기는 어느 화면이 어디에 속하는지만 적는다.
| 화면 | 무엇 | 유닛 | 파일 | 검증 게이트 |
|---|---|---|---|---|
| S0 | 토큰 입력 | U-관측API | internal/api/ui/ |
CP1 |
| S0b | 토큰 거절 (401 인라인) | U-관측API | internal/api/ui/ |
CP1 |
| S1 | 함대 격자 + Run 목록 | U-관측API | internal/api/ui/ |
CP1 · CP2 · CP4 |
| S1b | 갱신 실패 | U-관측API | internal/api/ui/ |
CP1 |
| S2 | Run 상세 · 작업 그래프 | U-관측API | internal/api/ui/ |
CP1 |
| S3 | 호스트 제어판 (도는 노드) | U-제어판 | internal/panel/ui/ |
CP4 |
| S5 | 호스트 제어판 (멈춘 노드) | U-제어판 | internal/panel/ui/ |
CP4 |
| S4 | 트랜스크립트 | 없음 | — | — |
S4 는 자리만이다 — constraints.md §5 가 범위 밖으로 뒀고 S3 의 트랜스크립트
카드는 비활성으로 그린다.
S1 이 게이트 셋에 걸리는 것이 이 표의 요점이다. CP1 이 카드와 임대를,
CP2 가 QUEUED 행을, CP4 가 draining 배지 두 국면을 본다. 화면을 U-관측API
에 합쳤어도 검증은 세 조각에 흩어진 채로 남는다.
5. 게이트 -> 유닛 요약
| 조각 | 무엇을 확인하나 | 딛는 유닛 | 화면 검증 |
|---|---|---|---|
| CP0 | 기동이 안 깨졌다. 경계 검사 초록 | U-바닥 | 없음 |
| CP1 | 보인다. 두 라우트가 실데이터 JSON | U-관측API | S0 · S0b · S1 · S1b · S2 |
| CP2 | 기다린다. 202 · QUEUED · 승격 |
U-대기열 | S1 의 QUEUED 행 |
| CP3 | 돌려받는다. 경계에서 놓고 풀면 돌아온다 | U-drain | 없음 — 정책 파일과 GET /v1/nodes 로 닫는다 |
| CP4 | 한 장면. ① ~ ⑦ 을 끝까지. LED 가 새 패턴 | 전부 | S3 · S5 · S1 의 배지 |
| CP5 | 감싼다. tools/list 가 일곱. 같은 자료가 MCP 로 나간다 |
U-MCP | 없음 — MCP 가 화면을 안 만든다 |
CP5 는 CP4 의 조건이 아니다. dhseo 장면에 MCP 가 안 나오므로 CP5 가
빨개도 CP4 는 초록일 수 있고, 반대로 CP5 는 CP1 만 초록이면 언제든 돈다.
게이트 사슬에 안 들어가는 유일한 조각이다.
CP4 는 유닛 하나의 게이트가 아니다. U-제어판이 마지막에 오지만 초록으로
만드는 것은 다섯 전부이고, 그래서 앞의 넷 중 하나라도 보류면 CP4 가 못 닫힌다
(scene-gates.md §4).