# 20 · 기반 + 접근 정책 문서 (MVP)

> **부모 PRD**: `.claude/prds/insuniverse-policy-docs.prd.md`
> **선행조건**: `10-index-git` · `11-index-code` · `12-index-runtime` · **`13-relation-contract`** 4개 종료 (우산 §PRD 분할 맵 158행). 앞 셋은 **사실 선행**(인덱스), 13 은 **형식 선행**이다 — 13 이 `policy-doc@1` 의 필드·절·연혁 열 계약을 확정하며 그 전에는 이 PRD 가 쓸 형식이 없다.
> **형식 정본**: `.claude/templates/doc-kit/` · **추출 규약 정본**: `.claude/meta/05-final-spec.md` · **소유권 정본**: `docs/_meta/ownership.md` · **프로젝트 고유값**: `docs/_meta/template-config.yaml`.
> **병렬 형제**: `30-contracts-limits`, `40-runtime-vendor-legal`, `50-domain`, `60-history-deprecated`
> **이 PRD가 MVP다.** 신입 합류 전에 이것만 끝나도 온보딩이 가능해야 한다.
> **특수 책임 2건**: `docs/01-foundation/01-glossary.md` 의 **유일한 소유자** — 형제 PRD의 용어 요청을 병합한다. 그리고 그 정본이 생기면 `docs/_meta/template-config.yaml` 의 `actors:` 를 정정한다 (아래 §config `actors` 정정 책임).
> **개정 · 2026-08-24** — `13-relation-contract` 종료(마일스톤 1~8 complete)로 형식 계약이 바뀌었고, `05-final-spec.md` §6-2 의 권한 DB 전제가 2026-08-12 에 정정됐다. 이 PRD 본문의 옛 문면 2자리(`docs/_meta/findings/13-relation-contract.md` F-04 가 지목)를 정정하고, 새 계약 5건을 §형식 계약 증분 으로 수용한다. 초판 판단은 취소선으로 남긴다.

## Problem

신입이 도메인 코드를 읽기 시작하면 첫 화면에서 `ANS001`, `E0401`, `agcRole`, `orgCanWrite`, `corpAnalysisViewLevel` 을 만난다. 이것들이 무엇인지 모르면 그 아래 어떤 문서도 읽을 수 없다. 지금은 코드에서 직접 역추적하는 방법밖에 없다.

그리고 실무에서 가장 자주 나오는 질문이 **"이 역할이 이 화면/API를 쓸 수 있는가"** 인데, 답이 세 곳에 흩어져 있다 — 코드 데코레이터(`@Roles`), 코드 상수(`agcRole`), DB 테이블(`tn_menu_auth_map`). 마지막 것은 스냅샷이 없어서 코드만으로는 답할 수 없다.

여기에 실제 오분류 전례가 있다: 사전 분석 라운드 2가 `CORP_FORBIDDEN`(에러 상수)과 `CORP_ANALYSIS_VIEW_KEY`(메타데이터 키)를 "기업 역할"로 기록했다. 4개 개념을 한 목록에 섞으면 권한 매트릭스 자체가 틀린다.

## Evidence

- **3계층 관통 실증** — `ANS001` 등 59종이 server 발행 → site·admin 소비. `server analyze-where.builder.ts:99` / `site AdminViewB2cAnalysisPage.tsx:327` / `admin features/analysis/ui/ANS001/detail.tsx:18`.
- **개념 혼동 실사례** — 기업 역할 4종 → **2종**(`CORP_SUPER`/`CORP_ORG`) 정정. `auth.service.ts:132/192`. 근거: `04-round3-adjudication.md` §1-1.
- **인증이 커밋 언급 최다 주제** — server 74 / site 120건.
- **권한 3중 표면** — `@Roles()` 136개소(재측정 137) + `agcRole` 상수 + DB `tn_auth`/`tn_menu`/`tn_menu_auth_map`.
- ~~**권한 DB 스냅샷 미제공 확정**~~ → **제공 가능 확정 · 이 저장소 기준 수령 대기** — `05-final-spec.md` §6-2 (2026-08-12 전제 정정). 바뀐 것은 *"영구히 받을 수 없다"* 가 *"수령 대기"* 라는 것이며, **`data-dependent-unknown` 판정은 그대로 유지한다.** 게이트가 읽는 것은 산문이 아니라 표식 둘이다 — `snapshot_state=pending` · `receipt_route=ops-40-db-snapshot`. 상세는 아래 §권한 DB — 승격 조건.
- **actor 별 메뉴 트리 소스 (2026-08-05 정정)** — ~~영업대리점 메뉴만 하드코딩이라 코드로 확인 가능.~~ 영업대리점(`salesMenus`)**과 기업(`corpMenus` 5코드) 둘 다** 하드코딩이다. DB 조회는 **admin actor 전용**이며(`AdminLayout.tsx:242`), sales·corp 는 메뉴 트리를 아예 조회하지 않고 고정 화면으로 진입한다(`useLoginForm.ts:111,118,121`). 미확보는 **admin 그룹별 배분뿐**. 근거: `.claude/meta/06-access-model-findings.md`
- **`salesMenus` 14 와 `salesCode` 10 은 둘 다 사실이다** — 트리의 `code` 출현이 14(그중 `SUB004` 가 2회 중복 → 고유 13)이고 필터 배열이 10이며, 차이는 중복 1 + 필터 미포함 `B2C*` 3 으로 **규명됐다**(실효 10종). 근거: `06-access-model-findings.md` §1-1. **한쪽만 쓰면 문서가 자기 표와 어긋난다** — 이 PRD 초판이 Evidence 에 14, 표에 10 을 적어 실제로 그랬다.
- **메뉴 코드 네임스페이스가 actor 별로 갈린다 (신규 실측)** — `corpMenus` 는 `CRP_ORG001`·`CRP_STL001` 등 **`tn_menu.mnu_code` 에 없는 별도 네임스페이스**를 쓴다. `salesMenus` 는 `tn_menu` 와 같은 네임스페이스. `02-identifier-namespaces.md` 의 5 namespace 목록에 `CRP_*` 가 포함되는지 확인 필요.
- **서브레벨 존재** — site에 `ANS003A`/`ANS003B`. 59종 목록에 없음 → 코드 사전은 계층 필요.

## Users

부모 PRD 상속. **이 PRD의 성공은 Primary 사용자(신규 합류 개발자)에게 직접 측정된다** — `onboarding-questions.yaml` 중 `20-foundation-access` 태그가 붙은 질문을 문서만으로 답할 수 있어야 한다.

## Hypothesis

We believe **용어·식별자·오류코드를 선행 개념으로 먼저 확정하고, 권한을 역할/능력/DB/에러 4개 절로 분리 서술하는 것**이
**신입이 도메인 코드를 읽기 전에 필요한 전부를 제공**하고 **권한 판정 질문에 문서만으로 답할 수 있게** 만들 것이라 믿는다.

We'll know we're right when **해당 태그 온보딩 질문 100% 답변 가능하고, 유지보수자 리뷰 불일치가 2라운드 연속 0건일 때**.

## Scope

### MVP — 산출 문서 8종

```
docs/01-foundation/
  01-glossary.md                 용어 · actor · 서비스 경계        ← 이 PRD가 유일 소유자
  02-identifier-namespaces.md    코드 사전 5 namespace + 계층(ANS003A/B)
  03-error-codes.md              E 코드 기능 블록 규칙 — 선언 범위 E0001~E1002 + E9999, 같은 표에 비-E 코드 공존

docs/02-access/
  01-authn.md                    인증
  02-authz-roles.md              역할 — @Roles 매트릭스 (admin·sales·corp)
  03-authz-capabilities.md       agcRole 2종 + orgCanWrite + corpAnalysisViewLevel
  04-authz-db-menu.md            메뉴 권한 — actor 3종을 각각 절로 (아래 참조)
  05-admin-view-token.md         관리자 열람 단명토큰 (IDOR 차단)
```

전 문서가 `.claude/templates/doc-kit/policy-doc.template.md` 형식 준수 — `## 정책 (기획)` / `## 강제 지점 (개발)` 2절 분리 필수. *(2026-08-05 정정: 구 경로 `docs/_meta/doc-template.md` 는 존재하지 않는 파일이었다. 형식 정본은 doc-kit.)*

### 형식 계약 증분 — `13-relation-contract` 종료로 늘어난 것

**이 PRD 착수 시점의 `policy-doc@1` 은 초판이 전제한 것보다 넓다.** 아래 5건은 전부 lint 규칙이 붙어 있어 지키지 않으면 산출물이 거부된다. 규칙 이름은 `lint-docs.mjs` 의 것을 그대로 적는다.

| # | 계약 | 이 PRD 에 미치는 것 | 규칙 |
|---|---|---|---|
| C1 | `statuses` 가 `id`·`label`·**`placement`** 3필드 맵으로 승격 | `data-dependent-unknown` · `conditional-unknown` 은 **`## 부록`** 배치다. 본문에 두면 위반, 부록에 둘 것을 본문에 둬도 위반 — **양방향**이다 | `placement` |
| C2 | `-unknown` 접미 status 는 `unknown_reason` 필수 | `04-authz-db-menu.md` 의 admin 그룹별 배분 정책에 사유를 적는다 | `unknown-reason` |
| C3 | `## 연혁` 에 열 계약 신설 | `릴리스 \| 날짜 \| SHA \| 변경 요약` **4열 고정** · 날짜 `YYYY-MM-DD` · SHA hex 7~40자리 또는 `—` · 헤더만 있는 표 거부. 초판이 Out of scope 에 *"각 문서의 `## 연혁` 절은 여기서 씀"* 이라 적은 그 절이 이제 기계 검사 대상이다 | `history-columns` |
| C4 | `evidence_grades` 16종 (`O-ops` · `S-route` · `S-component` 신설) | 우산 제약 #3(2개 이상 서로 다른 등급)은 그대로. **`O-ops` 는 이 PRD 가 쓰지 않는다** — 아래 §권한 DB — 승격 조건 | `evidence-domain` |
| C5 | `policies[].supersedes`(활성→폐기 단방향) · `limitations` · `## 부록` 절 신설 | 유예 목록의 현행 원소는 `../fixtures/superseded-placeholder.md#LEGACY_ADMIN_VIEW_TOKEN` 이며 키트 fixture 전용이다. ~~`05-admin-view-token.md` 가 폐기 토큰을 승계할 자리가 `deferred_ref_targets` 에 **이미 예약**돼 있다 — `../99-deprecated/legacy-admin-view.md#LEGACY_ADMIN_VIEW_TOKEN`. 대상은 `60-history-deprecated` 가 회부 R-4 를 수용해야 생긴다~~ — 초판 문면이며 `60-history-deprecated` 마일스톤 2 의 재지정으로 거짓이 됐다 | `supersedes` |

~~**C5 의 순서를 지킨다.** 대상이 없는 동안 `supersedes` 는 `deferred_ref_targets` 덕에 비승격 notice 로 지나가지만, **목록에 있는 참조의 대상이 이미 존재하면 그 자체가 위반**이다. 60 이 R-4 를 수용한 뒤에는 유예가 만료되므로 `05-admin-view-token.md` 는 그 시점에 재검증이 필요하다.~~

**정정 (2026-08-27 · 마일스톤 5).** 위 순서 지시는 `05-admin-view-token.md` 가 `supersedes` 를 쓴다는 전제 위에 있었고 그 전제가 §Open Questions 에서 닫혔다 — 이 PRD 의 산출 문서 어디에도 `supersedes` 가 없으므로 유예 만료가 이 PRD 의 산출물을 건드리지 않는다. 유예 목록 자체의 관리는 `60-history-deprecated` 소관이다.

**`auth_layers` 5층과 이 PRD 의 5문서가 1:1 이다.** `template-config.yaml` 의 `auth_layers: [인증, 계정 종류, 쓰기 스코프, 기업 노출 등급, 메뉴 노출]` 은 `flow-doc@1` 전용 계약이지만 그 어휘가 `06-access-model-findings.md` §6 실측(차단 4층 + 비차단 1층)에서 나왔고, `docs/02-access/` 5문서가 정확히 그 층들을 나눠 맡는다.

| config `auth_layers` | 이 PRD 문서 | 차단 여부 |
|---|---|---|
| 인증 | `01-authn.md` | 차단 (401) |
| 계정 종류 | `02-authz-roles.md` | 차단 (403) |
| 쓰기 스코프 · 기업 노출 등급 | `03-authz-capabilities.md` | 차단 (403) |
| 메뉴 노출 | `04-authz-db-menu.md` | **비차단** |

`05-admin-view-token.md` 는 이 5층 축 밖이다 — 층이 아니라 개별 guard 다.
**다른 축분할을 쓰지 않는다.** 쓰면 `50-domain` 의 flow 문서가 같은 대상을 다른 어휘로 부르고, 두 축이 계산으로 이어지지 않는다.

### config `actors` 정정 책임 (신규)

`docs/_meta/template-config.yaml` 의 `actors:` 는 **미검증 fixture 값**이다. 그 파일 주석이 명시한다 — *"정본은 `docs/01-foundation/01-glossary.md` 이며 아직 작성 전이다 … 정본이 생기면 `20-foundation-access` 가 이 목록을 정정한다."*

| 항목 | 값 |
|---|---|
| 착수 시점 값 | ~~`[비회원, 회원, 기업담당자, 대리점, 관리자, 영업관리자]` — 6종, 승격 전 fixture 그대로~~ |
| 정정 후 값 (2026-08-25 · 마일스톤 1) | `[관리자, 영업대리점, 기업담당자, 일반회원, 기업회원]` — 5종, `01-glossary.md` A축 표의 용어 열 순서 |
| glossary A 축 | `admin` / `sales` / `corp` · 일반회원(`MEM001`) / 기업회원(`MEM002`) |
| 상태 | ~~**축이 다르다.** … 어느 쪽이 `actors` 의 뜻인지 정본이 없어 판정 불가~~ → **해소 (2026-08-25 · 마일스톤 1): 로그인 주체 축이다.** 판정 근거 3건은 아래 §Open Questions 해소문에 있고, 하네스 검사 `#3` 이 config ↔ glossary A축을 순서 포함으로 대조한다 |
| 소유 | `00-protocol`(archived). 개정 위임은 `13`(archived) 앞으로 **완료** 처리됨 |

**절차.** 이 PRD 는 `docs/_meta/ownership.md` §개정 위임 표에 자기 행 3개를 추가한 뒤 정정한다 (우산 §핵심 제약 6 의 *예외 — archived PRD 의 소유 경로 개정*). 대상 경로는 셋이다.

- `docs/_meta/template-config.yaml` — `actors` 를 fixture 6종에서 `01-glossary.md` A축 정본으로 정정한다
- `docs/_meta/verify/**` — 위 정정이 golden 을 붉히므로 마일스톤 1 산출물 반영으로 재생성하고, `--bootstrap` 만료 진단 2자리의 `printf` 선두 `--` 결함을 함께 정정한다
- `docs/_meta/term-requests/12-index-runtime.md` — `T-01`·`T-02` 판정을 상태 행에 되돌려 적는다

**소유 표 둘(§PRD별 배타 소유 경로 · §승계 시 추가)은 건드리지 않는다** — 거기 적으면 위임이 소유가 된다.

**자리는 마일스톤 1 종료 직후다.** 정본(`01-glossary.md`)이 나온 뒤여야 하고, 정정하면 `golden.txt` 의 `template_config.actors` 행이 붉어져 명시적 `--update` 를 강제한다 — 설계된 경로이며 조용한 발산이 아니다.

### 반드시 지킬 것

- **개념 4축을 절로 분리한다.** 역할(`admin`/`sales`/`corp`) · 기업역할(`CORP_SUPER`/`CORP_ORG`) · 능력(`orgCanWrite`, `corpAnalysisViewLevel`) · 에러상수(`CORP_FORBIDDEN`=`E0401`). 한 목록에 섞으면 틀린다.
- **`04-authz-db-menu.md` 는 actor 3종을 각각 절로 쓴다.** (2026-08-05 확정 · 근거 `.claude/meta/06-access-model-findings.md` §1)

  | 절 | 대상 | 트리 소스 | 코드 체계 | status |
  |---|---|---|---|---|
  | 1 | **admin** | DB `tn_menu` 런타임 조회 (`AdminLayout.tsx:242`) | `mnu_code` — 79 (2단계) | 구조 확정 / **그룹별 배분만 `data-dependent-unknown`** |
  | 2 | **sales** | 프론트 상수 `salesMenus` (`constants/menu.ts:7`) | `mnu_code` 와 **같은 체계** — 10코드(`salesCode`) | **확정** — 코드로 100% |
  | 3 | **corp** | 프론트 상수 `corpMenus` (`:190`) + `agcRole` 필터 | **`CRP_*` 별도 체계** — 5코드(`corpCode`) | **확정** — 코드로 100% |

  문서를 쪼개지 않고 한 파일 안 3절로 가는 이유: 셋을 나란히 놓아야 "메뉴 권한 = DB" 오독이 깨진다. 8종 상한도 유지된다.
  각 절 첫 줄에 **트리 소스·코드 체계·확정 여부**를 먼저 쓴다 — 이 셋이 actor마다 다르다는 것이 이 문서의 핵심 정보다.
  ~~구 서술: "DB 권한은 구조만 … 하드코딩된 영업대리점 메뉴는 예외"~~ — 배분 unknown 범위를 메뉴 권한 전반으로 넓게 잡았고 corp 하드코딩을 누락했다.

- **admin 을 정책 2건으로 쪼갠다** (형식 계약 증분 C1 의 귀결 · 2026-08-24 신설). `placement` 규칙이 `data-dependent-unknown` 정책을 **`## 부록`** 으로 강제하므로, admin 절 전체를 unknown 으로 두면 위 3절 나란히 놓기가 문서 안에서 깨진다. **status 를 문서 단위가 아니라 정책 단위로 잡는다.**

  | `policies[].id` | 무엇 | status | placement |
  |---|---|---|---|
  | admin 트리 구조 | `tn_menu` 1단계·2단계 구성과 런타임 조회 경로 (`AdminLayout.tsx:242`) | `active-prod` | 본문 |
  | admin 그룹별 배분 | `tn_menu_auth_map` 의 권한그룹 → 메뉴 배분 | `data-dependent-unknown` | **부록** |
  | sales 트리 | `salesMenus` + `salesCode` 필터 | `active-prod` | 본문 |
  | corp 트리 | `corpMenus` + `agcRole` 필터 · `CRP_*` 별도 네임스페이스 | `active-prod` | 본문 |

  **본문 3절(admin·sales·corp)은 그대로 나란히 선다.** 부록으로 격리되는 것은 배분 1건뿐이며, 그것이 실제로 미확보인 유일한 항목이다(`05-final-spec.md` §6-2 정정표). `unknown_reason` 은 C2 가 필수로 요구한다.
  **문서를 2개로 쪼개지 않는 이유**: 8종 상한이 9종이 되고 `00-index.md` 문서 트리 개정(3단계 절차 + `golden --update`)이 붙는다. 정책 단위 분리로 같은 효과가 나온다.
- **메뉴 권한 ≠ API 인가.** 메뉴 권한은 사이드바 렌더링과 로그인 직후 진입 화면만 정한다. 서버 API 차단은 `@Roles` + 개별 guard 다. `04-authz-db-menu.md` 와 `02-authz-roles.md` 가 각각 다른 축을 맡으며, 어느 쪽도 상대의 역할을 대신 서술하지 않는다.
- **근거 2개 이상.** `evidence:` 프론트매터에 최소 2개 서로 다른 등급. 주석 단독 금지.

### glossary 구조 — 3표 분할 (2026-08-11 확정)

Open Question("코드 심볼 전부인가 기획 용어만인가")의 답이다. **둘 다 담되 축을 섞지 않는다.**

```markdown
## A. actor 축 — 시스템에 로그인하는 주체
   admin / sales / corp · 일반회원(MEM001) / 기업회원(MEM002)
   열: 용어 | 코드 심볼 | 로그인 표면 | 관련 문서

## B. 제공 단위 축 — 계약·수익이 귀속되는 주체
   영업대리점 / 채널 · 기업 / 조직 · 고객사
   열: 용어 | 코드 표면 | 계약 소재 | 데이터 범위 | 관련 문서

## C. 코드 심볼 — 02-identifier-namespaces.md 로 링크만 (여기서 정의하지 않는다)
```

**A 와 B 는 교차하지 포함하지 않는다.** 이것이 이 문서의 핵심 정보다. 실측 근거:
`modules/sales-agency/channel`(채널) · `modules/agency`+`corp`(기업) · `modules/client/**`(고객사)가
각각 별도 계약·과금 표면을 갖는데, **고객사는 관리자 콘솔의 actor 가 아니다.** A 축만으로 문서를
짜면 고객사가 통째로 빠진다 — 실제로 구 계획서 50문서에 client 축이 0건이었다.
근거: `.claude/meta/07-domain-knowledge-gap.md` §3. 고객사 계약 각론은
`03-contracts/05-external-client-api.md`(`30-contracts-limits` 소유)로 링크한다.

**용어 행 목록의 1차 입력**은 `.claude/meta/10-user-oral-source.md`(등급 U) `[용어]` 절이다.
행 목록만 가져오고 **정의문은 코드에서 다시 쓴다.** 그 원문에는 코드와 어긋난 항목이 3건 있다
(고객사 · 머니 · 대상선정기준 — `07` §2). `planning/**`(등급 L)은 용어 **존재 확인**에만 쓰고
값·문장을 옮기지 않는다(`05-final-spec.md` §6-4).

저장소 근거가 전혀 없는 용어는 **`GA`(법인대리점) 1건**이다 — ~~코드 등장이 약관 수탁사 나열문
1곳(`B2cPersonalInfoPage.tsx:12`)뿐이라~~ **2026-08-25 실측 정정: 3파일 4행**이다
(`insuniverse-site/front/src/pages/terms/B2cPersonalInfoPage.tsx:12` ·
`insuniverse-site/front/src/pages/terms/B2cSensitiveInfoPage.tsx:12` ·
`insuniverse-site/front/src/features/agreementForm/constants/b2cAgreementContents.const.tsx:16` ·
같은 파일 `insuniverse-site/front/src/features/agreementForm/constants/b2cAgreementContents.const.tsx:70`.
`insuniverse-server`·`insuniverse-admin` 은 0행). 넷 다 약관 수탁사 나열문이라 정의로 쓸 수 없다는
판단은 그대로다 — 바뀐 것은 등장 계수뿐이다. 이 항목만 `출처: 구술` 표기를 단다.

> 실측 기준은 동결 SHA 3종(server `4d798f55` · site `767d1e44` · admin `fb001e1d`)에서
> `git grep -I -n -w GA` 를 manifest `exclude_pathspec` 14항목과 함께 돌린 것이다. `01-glossary.md`
> 각주 표가 같은 집합을 인용하고, 마일스톤 1 하네스의 검사 `#4` 가 두 집합을 매 실행 대조한다.

### 형제 PRD를 위한 책임

`docs/_meta/term-requests/*.md` 를 주기적으로 읽어 `01-glossary.md` 에 병합한다. **형제는 glossary를 직접 편집하지 않는다** — 이 PRD만 쓴다.

**착수 시점 대기분 (2026-08-24 실측).** `10-index-git` 은 **0건**을 명시적으로 선언한 파일이다 — *"0건과 파일 만드는 것을 잊었다를 구별하기 위해"*. `12-index-runtime` 은 `T-01`(진료수집 외부 연동 주체 표기 3종 — `vendor`/`provider`/`scraper`, 제안 정본 `vendor`) · `T-02`(`철회` 가 동의 철회와 업무 취소 두 대상에 쓰임) **둘 다 상태 `요청`** 이다. 마일스톤 1 이 이 둘을 판정한다 — 판정 결과를 `요청` → `확정`/`반려` 로 되돌려 적는 것까지가 병합이다.

### 권한 DB — 승격 조건 (2026-08-24 신설)

**전제는 열렸고 데이터는 만들어졌으나, 이 PRD 가 값을 본문에 쓸 문은 아직 잠겨 있다.** 셋을 구별한다.

| 사실 | 값 | 근거 |
|---|---|---|
| 제공 가능 여부 | **확정** | 사용자 확정 2026-08-12 · `05-final-spec.md` §6-2 |
| ops 축의 수령·정규화 | **완료** — `ops-40-db-snapshot` M0·M1·M2 complete. 스냅샷 `prod-2026-08-12`, 행별 `row_sha` 핀 | 그 PRD §Delivery Milestones · `ops/db/snapshot.lock` |
| **이 저장소(main) 기준 존재 여부** | **없다** — `git ls-tree -r origin/main -- ops/` **0파일.** ops 축 전체가 미병합 브랜치에만 있다 | 실측 2026-08-24 |

그래서 `snapshot_state=pending` 은 낡은 표식이 아니라 **병합 저장소 기준으로 정확하다.**

**본문 승격에 필요한 게이트 4개 중 3개가 이 PRD 소유 밖이다.**

| # | 게이트 | 현재 | 소관 |
|---|---|---|---|
| G1 | `ops-40-db-snapshot` M3 (리포트 · 회부 O-6 상신) | pending | ops-40 |
| G2 | `ops-30-reconcile` 의 verdict 가 `agree` — 등급 O 는 `agree` 만 값 인용 가능하고 `ops-only` 는 **정책 본문 금지**다 | 미착수. **대조 상대인 `04-authz-db-menu.md` 가 아직 없다** | ops-30 |
| G3 | 등급 O 의 `assignment_scope=unassigned` 해제 — 어느 정책이 등급 O 를 받는지 판정 | 미해제 | `ops-doc-reconcile` 우산 (사용자) |
| G4 | `snapshot_state` · `receipt_route` 표식 전환 (`05-final-spec.md` §6-2 · §0 요약표 두 자리) | pending | `00-protocol`(archived) — 위임받은 `13` 도 archived 라 **새 위임행이 필요하다** |

**판정: 이 PRD 는 `data-dependent-unknown` 으로 착수하고 승격은 후속으로 남긴다.**

- G2 가 결정적이다 — 대조 상대가 없어 verdict 가 나올 수 없다. **이 PRD 가 `04-authz-db-menu.md` 를 부록 배치로 먼저 내는 것이 오히려 G2 의 선행조건이다.**
- 값을 미리 쓰면 우산 **제약 #5**(수치는 `extraction-manifest.yaml` 통해서만) 위반이다. 그 예외를 여는 유일한 문이 등급 O 인데 G3 이 잠겨 있다.
- **축도 다르다.** DB 는 `prod-2026-08-12` 실측, 이 PRD 의 코드 앵커는 manifest `repos[].head` = stg 동결 SHA(`insuniverse-server 4d798f55`, 2026-08-05). `snapshot.lock` 의 `code_baseline.note` 가 그 비대칭을 이미 적어 두었다 — **두 축의 차이는 값이 아니라 대조 대상이다.**
- 승격 조건은 산문이 아니라 **표식 둘**이다: `snapshot_state` 와 `assignment_scope`. 둘 다 뒤집힌 뒤에 별도 후속이 부록→본문 승격과 status 전환(`data-dependent-unknown` → `active-prod`)을 한다. 이 PRD 의 종료 판정은 그 후속을 기다리지 않는다.

### Out of scope

- 입력 검증·API 계약·데이터 모델 → `30-contracts-limits`
- 도메인별 권한 각론 → `50-domain`
- 권한 변경 연혁 서술 → `60-history-deprecated` *(단, 각 문서의 `## 연혁` 절은 여기서 씀 — 열 계약은 형식 계약 증분 C3)*
- ~~권한 DB 실제 배분 — 스냅샷 미제공 확정~~ → **권한 DB 실제 배분의 본문 승격.** 전제는 열렸으나 게이트 G1~G4 가 닫혀 있다 (위 §권한 DB — 승격 조건). 이 PRD 는 부록에 `data-dependent-unknown` 으로 기록하고 승격은 하지 않는다
- `evidence: [O-ops]` 사용 — 등급 O 의 `assignment_scope=unassigned` 가 해제되기 전까지 이 PRD 는 그 등급을 쓰지 않는다
- ops 축 산출물(`ops/**`) 인용 — 이 저장소 main 에 0파일이다

## 배타 소유 경로

```
docs/01-foundation/**
docs/02-access/**
docs/_meta/findings/20-foundation-access.md
```
`docs/_meta/term-requests/**` 은 **읽기**(병합용). 자기 요청 파일만 쓴다.

## Success Metrics

| Metric | Target | 측정자 | 측정 시점 | 판정 규칙 |
|---|---|---|---|---|
| 온보딩 질문 통과 | 100% | 유지보수자 | 종료 판정 시 | `onboarding-questions.yaml` 중 `20-foundation-access` 태그 질문 전부 O. X 1건이면 미종료 |
| 리뷰 불일치 수렴 | 2라운드 연속 0건 | 유지보수자 | 리뷰 라운드마다 | `policy-candidates.*.jsonl` 행 단위 "사실과 다름/빠짐" 표기 건수 |
| 근거 2중화 | 위반 0 | 자동 | 종료 판정 시 | `evidence:` 항목 1개 이하인 정책 문서 0. 주석 단독(`[A-comment]`만) 0 |
| 템플릿 준수 | 위반 0 | 자동 | 종료 판정 시 | `node .claude/templates/doc-kit/lint-docs.mjs` 와 `--strict-refs` **양쪽** exit 0. 8개 문서 전부 (우산 제약 #7) |
| 배치 계약 준수 | 위반 0 | 자동 | 종료 판정 시 | `placement` 규칙 exit 0. `data-dependent-unknown` 정책이 `## 부록` 에, 그 밖이 본문에 — **양방향** |
| 연혁 열 계약 | 위반 0 | 자동 | 종료 판정 시 | `history-columns` 규칙 exit 0. 8개 문서 전부 |
| 저장소 게이트 무손상 | exit 0 | 자동 | 마일스톤 1 · 종료 판정 시 | `bash docs/_meta/verify/verify.sh --check` 가 **`--bootstrap` 없이** exit 0. 이 PRD 가 DRAFT 를 벗어나는 순간 그 플래그가 저장소 전체에서 거부되므로, 첫 문서가 lint 대상을 실제로 만들었는지를 이 검사가 본다 |
| 개념 4축 분리 | 위반 0 | 유지보수자 | 종료 판정 시 | 역할 목록에 `CORP_FORBIDDEN`/`CORP_ANALYSIS_VIEW_KEY` 부재 |
| `auth_layers` 축 정렬 | 위반 0 | 유지보수자 | 종료 판정 시 | `docs/02-access/` 5문서가 `template-config.yaml` `auth_layers` 5층과 §형식 계약 증분 표대로 대응하고, 그 밖의 축분할을 쓰지 않는다 |

## Delivery Milestones

| # | Milestone | Outcome | Status | Plan |
|---|---|---|---|---|
| 1 | `01-glossary.md` + `term-requests` 병합 + config `actors` 정정 | 용어·actor·서비스 경계가 한 곳에. 형제 PRD가 참조 시작 가능. `T-01`·`T-02` 가 판정되고 `template-config.yaml` `actors:` 가 fixture 값에서 정본으로 바뀐다 | complete | `.claude/plans/insuniverse-docs-20-foundation-access-m1.plan.md` |
| 2 | `02-identifier-namespaces.md` + `03-error-codes.md` | 신입이 `ANS001`·`E0401` 을 문서로 안다 | complete | `.claude/plans/insuniverse-docs-20-foundation-access-m2.plan.md` |
| 3 | `01-authn.md` | 인증 흐름과 만료·갱신 정책을 안다 | complete | `.claude/plans/insuniverse-docs-20-foundation-access-m3.plan.md` |
| 4 | `02-authz-roles.md` + `03-authz-capabilities.md` | "이 역할이 이 API를 쓸 수 있는가"에 답 가능 | complete | `.claude/plans/insuniverse-docs-20-foundation-access-m4.plan.md` |
| 5 | `04-authz-db-menu.md` + `05-admin-view-token.md` | 메뉴 권한의 actor 3분기가 본문에 나란히 서고 미확보분(admin 그룹별 배분)만 부록으로 격리된다. 열람토큰 IDOR 차단이 문서화됨 | complete | `.claude/plans/insuniverse-docs-20-foundation-access-m5.plan.md` |
| 6 | 리뷰 2라운드 수렴 | 담당자 이해와 일치 확인 | complete | `.claude/plans/insuniverse-docs-20-foundation-access-m6.plan.md` |
| 7 | 종결 후 잔여 — 하네스 3결함 · closure 해시 축 · 위임 슬롯 | PR-Codex 라운드 1 지적 3건이 검사로 닫히고, closure 해시가 체크아웃 EOL 과 무관해지며, 위임 슬롯 드리프트가 게이트에 잡힌다 | complete | `.claude/plans/insuniverse-docs-20-foundation-access-m7.plan.md` |

**마일스톤 1 이 저장소 전체의 게이트 상태를 바꾼다.** 이 PRD 의 `*Status:` 가 DRAFT 를 벗어나면 `verify.sh --check --bootstrap` 이 거부되고 `--check` 가 실문서를 요구하기 시작한다. 마일스톤 1 종료 판정에 플래그 없는 `--check` 를 넣는 이유가 그것이다 (§Success Metrics · §Risks).

## Open Questions

- [x] ~~`01-glossary.md` 의 용어 수집 범위 — 코드 심볼 전부인가, 기획 용어만인가. 전자면 코드 사전과 중복된다.~~
  **해소 (2026-08-11): 둘 다이되 표를 3개로 나눈다.** 아래 §glossary 구조 참조.
- [x] ~~권한 매트릭스를 표로 전개하면 `@Roles` 137개소 × 3역할이 된다. 요약 축(모듈 단위)을 어디로 잡을 것인가.~~
  **해소 (2026-08-26 · 마일스톤 4): 모듈 단위 합집합 표로 잡고 처리기 단위 전수는 생성 인덱스에 위임한다.** `docs/02-access/02-authz-roles.md` 의 `ROLE_MODULE_MATRIX` 가 모듈 축 표를 싣고, 각 행은 그 모듈이 관측한 역할의 합집합이다. 처리기 단위 전수는 `docs/_meta/index/policy-anchors.yaml` 이 이미 정본으로 들고 있어 문서가 전사하면 정본이 둘 생겨 드리프트한다. 모집단은 역할 선언도 가드 결선도 아니라 **콘솔 표면 전건**이며, 그래서 표에 `역할무제한 표면` 열이 셋째로 붙는다 — 그 열은 "역할 층은 걸었는데 선언이 0건" 과 "역할 층을 아예 안 걸었다" 를 합친 값이다. 이 표는 셋째 열이 빈 모듈에서만 **필요조건**이다 — 그 모듈에 한해 역할이 합집합 밖이면 어느 처리기도 통과시키지 않고, 안이면 처리기 확인이 남는다(표면 클래스 선언과 처리기 선언이 섞여 합집합이 개별 처리기보다 넓다). 하네스 검사 `#6` 이 행 집합과 행별 역할집합을 동결 SHA 재유도와 대조하고 `#7` 이 셋째 열과 그 열이 여는 표면 자리를 함께 묶는다.

  **모집단 정정 (2026-08-26 · 코드리뷰 흡수).** 종전 모집단은 가드 결선이었고 그 상태에서 필요조건을 무조건으로 적었다. 역할 층을 걸지 않은 콘솔 표면이 모집단 밖이라 두 모듈에서 그 주장이 거짓이었다 — 셋째 열이 비어 있는데 실제로는 인증만으로 통과하는 표면이 함께 있었다. 검사는 문서와 유도의 일치만 봤으므로 통과했다. 모집단을 콘솔 표면으로 넓히고 필요조건을 셋째 열에 걸어 닫았다.
- [x] ~~`corpAnalysisViewLevel` 의 레벨값 목록이 코드에 열거돼 있는가, DB 의존인가. 후자면 `data-dependent-unknown`.~~
  **해소 (2026-08-26 · 마일스톤 4): 둘 다이므로 정책을 둘로 쪼갠다.** 척도를 **적는 자리**는 코드에 있다 — 열 머리 주석·판정 층 머리 주석·계약 설명문 둘, 넷이 같은 세 단계를 적는다. 다만 넷 중 어느 것도 값을 제약하지 않는다(열에 범위 제약 없음 · 판정이 크기 비교). 데코레이터가 받는 리터럴 유니온(`insuniverse-server/apps/api/src/modules/auth/admin/corp-analysis-view.guard.ts:16`)이 닫는 것은 **요구할 수 있는 단계**뿐이고, 열 기본값 선언(`insuniverse-server/drizzle/schema.ts:405`)은 새 기업의 시작 등급일 뿐 정의역이 아니다. 그래도 자리가 저장소 안이라 `CORP_ANALYSIS_VIEW_SCALE` 은 `active-prod` 로 본문에 있다. 기업별 **배정값**만 운영 DB 열에 있어 이 저장소로 판정되지 않으므로 그 축을 `CORP_ANALYSIS_VIEW_ASSIGNMENT` 로 갈라 `data-dependent-unknown` 을 주고 `## 부록` 에 격리했다(`unknown_reason` 필수). 쪼개지 않으면 그 정책 하나가 통째로 미상이 되어 판정된 척도까지 부록으로 끌려간다. lint 규칙 `placement` 는 양방향이라 반대 실수도 잡히고, 하네스 검사 `#11` 이 척도 열거 자리 넷·열 기본값·요구 단계 형·통과 분기 둘·차단 비교와 본문·부록 앵커를 함께 보며 예외·폴백 행 셋을 그 분기 자리에 결박한다.
- [x] ~~인증 정책 중 앱(웹뷰) 차이 — `useAppVersionCheck.ts` 의 최소버전 강제를 `01-authn.md` 의 `## 플랫폼 차이` 절에 넣을 것인가, 별도로 뺄 것인가.~~
  **해소 (2026-08-26 · 마일스톤 3): `01-authn.md` 의 `## 플랫폼 차이 (웹 / 웹뷰)` 절에 넣는다.** 근거는 축이 같다는 것이다 — 갱신 토큰 발급이 앱 환경 분기 **안에만** 있고 최소버전 강제도 앱 환경에서만 발동하므로, 둘은 같은 조건(앱 환경)에 걸린 형제 항목이다. 별도로 빼면 그 조건이 두 자리로 갈리고 독자가 앱 차이를 한 곳에서 읽지 못한다. 그 절에는 셋이 함께 실렸다 — 갱신 토큰 발급 분기 · 앱 최소버전 강제 · 쿠키 미전송 기기의 헤더 폴백. 최소버전 강제가 인증 층이 아니라 화면 층이라는 사실은 그 절이 명시한다.
- [x] ~~`template-config.yaml` `actors:` 의 뜻이 **로그인 주체**(glossary A 축)인가 **업무 호칭**(현재 fixture 6종)인가. 정본이 없어 판정 불가이며 `01-glossary.md` 확정이 답을 낸다.~~
  **해소 (2026-08-25 · 마일스톤 1): 로그인 주체 축이다.** 값은 `[관리자, 영업대리점, 기업담당자, 일반회원, 기업회원]` 5종이며 `01-glossary.md` A축 표의 용어 열을 표 순서대로 옮긴 것이다. 근거 셋 — (1) fixture 의 `영업관리자` 는 세 저장소 어디에도 없다(동결 SHA 실측 0건), (2) `회원` 은 `MEM001`·`MEM002` 두 로그인 타입을 하나로 접는다, (3) `대리점` 은 코드 표기 `영업대리점` 과 어긋난다. `비회원` 이 빠진 것도 같은 판정의 귀결이다 — 로그인하지 않는 표면은 이 축의 원소가 아니라 그 여집합이며 정본에서 각주 행으로 내려갔다. 하네스 검사 `#3` 이 config 와 glossary A축을 순서 포함으로 대조하고, 각 용어가 강제 지점 앵커를 갖는지까지 본다.
- [x] ~~`05-admin-view-token.md` 가 `supersedes` 로 폐기 토큰을 승계할 것인가. 대상 `../99-deprecated/legacy-admin-view.md#LEGACY_ADMIN_VIEW_TOKEN` 은 `deferred_ref_targets` 에 예약돼 있으나 실체는 `60-history-deprecated` 의 R-4 수용 뒤에 생긴다. **대상이 생기는 순간 유예가 만료되므로** 그 시점 재검증이 필요하다.~~
  **해소 (2026-08-27 · 마일스톤 5): 승계하지 않는다. `supersedes` 를 어느 정책에도 두지 않는다.** 근거 셋이다 — (1) **유예 원소가 재지정됐다.** `60-history-deprecated` 마일스톤 2 가 2026-08-25 에 `deferred_ref_targets` 의 그 원소를 키트 자기완결 스펠링 `../fixtures/superseded-placeholder.md#LEGACY_ADMIN_VIEW_TOKEN` 으로 교체했다. 이 질문과 아래 §형식 계약 증분 C5 행이 적은 경로는 그 재지정 **이전** 값이라 지금은 어느 config 에도 없다. (2) **같은 창이 `legacy-admin-view.md` 를 placeholder 로 판정했다.** 정본 트리의 `99-deprecated/` 는 두 문서뿐이고 키트 fixture `good-supersedes-absent.md` 가 그 파일의 **부재**를 정상 경로로 단언한다 — 실 후보로 발행하면 그 fixture 가 뒤집힌다. (3) **승계 대상이 될 폐기 배치 정책이 저장소에 없고 이 PRD 가 만들 수도 없다.** `docs/99-deprecated/**` 는 `60-history-deprecated` 의 배타 소유 경로이며 여기서 만들면 소유 경로 위반이다. 코드 안에 남은 구판 토큰 호환은 폐기 문서가 아니라 `05-admin-view-token.md` 의 `## 예외·폴백` 행으로 적었다.

## Risks

| Risk | 확률 | 영향 | 발동 신호 | 완화책 |
|---|---|---|---|---|
| 개념 4축이 다시 섞임 | 중 | **매우 높음** | 리뷰에서 권한 목록에 에러상수 등장 | `11-index-code` 의 `policy-anchors.yaml` 4축 분리를 그대로 계승. 자체 재분류 금지 |
| DB 권한 미확보로 문서가 반쪽 | **확정** | 높음 | — (이미 발생) | 한계를 문서 최상단에 명시. "이 문서로는 답할 수 없는 질문" 절을 둔다. 온보딩 질문에서 해당 항목 제외. **2026-08-05 범위 축소**: 미확보는 **admin actor 의 그룹별 배분뿐**이다. sales·corp 트리는 코드 하드코딩이라 100% 확정된다 (`06-access-model-findings.md`). **2026-08-24 추가**: 그 배분마저 ops 축에서는 이미 관측됐다 — 남은 것은 데이터가 아니라 인용 경로다 (§권한 DB — 승격 조건 G1~G4) |
| **이 PRD 착수가 저장소 전체의 `--bootstrap` 을 만료시킨다** | **확정** | 중 | 이 PRD 의 `*Status:` 가 DRAFT 를 벗어나는 즉시 | `verify.sh` `bootstrap_permitted()` 가 lint glob 과 교집합인 문서 PRD 의 `*Status:` 를 감시하고 하나라도 DRAFT 를 벗어나면 플래그를 거부한다. 마일스톤 1 이 첫 lint 대상을 만들어 `--check` 단독을 성립시키는 것이 유일한 정상 경로다. **`*Status:` 행은 정확히 1개로 유지한다** — 0개도 2개도 거부다 |
| ops 축이 미병합인 채로 이 PRD 가 종료 | 중 | 낮음 | ops 브랜치 5종이 main 에 안 들어온 상태 | **의도된 상태다.** 이 PRD 의 종료 조건은 ops 병합을 기다리지 않는다. 승격은 표식 둘(`snapshot_state` · `assignment_scope`)이 뒤집힌 뒤 별도 후속이 한다 |
| 형식 계약 증분을 못 따라가 lint 가 빨간불 | 중 | 중 | `placement`·`history-columns`·`unknown-reason` 중 하나라도 위반 | 문서 1건 완성 즉시 `lint-docs.mjs` 와 `--strict-refs` 양쪽 실행. 첫 문서(`01-glossary.md`)에서 형식을 소규모로 먼저 검증한다 (아래 마지막 Risk 와 같은 장치) |
| 메뉴 권한을 API 인가로 오해한 채 서술 | 중 | **높음** | 권한 매트릭스에 `tn_menu_auth_map` 이 차단 수단으로 등장 | 실측 확정: 메뉴 권한은 **사이드바 렌더링과 로그인 직후 진입 화면만** 정하고 서버 API 를 막지 않는다 (`menu.repository.ts:32` · `menu.controller.ts:25`). API 차단은 `@Roles`(`roles.guard.ts:27`) + 개별 guard. `04-authz-db-menu.md` 는 이 둘을 **다른 축으로** 서술한다 |
| actor 3종의 메뉴 모델을 하나로 뭉뚱그려 서술 | **중** | **높음** | `04-authz-db-menu.md` 가 `tn_menu` 만 다루고 `corpMenus`·`salesMenus` 를 누락 | 실측: 메뉴 트리 소스가 actor 마다 다르고 corp 는 **네임스페이스까지 다르다**(`CRP_*`). 셋을 각각 서술한다 (`06-access-model-findings.md` §1) |
| glossary 병합이 병목 | 중 | 중 | `term-requests/` 미처리 항목 10건 초과 | 병합 주기 고정(형제 PRD 종료 시점마다). 미처리분은 `01-glossary.md` 말미에 "검토 대기" 절로 노출 |
| MVP가 신입 합류 전에 안 끝남 | 중 | 높음 | 합류 2주 전에 마일스톤 3 미완 | 마일스톤 1~4까지가 최소선. 5는 합류 후 이월 가능(단명토큰은 온보딩 필수 아님) |
| 기획/개발 2절 분리가 형식만 지켜지고 내용이 섞임 | 중 | 중 | 리뷰에서 개발 절에 기획 서술 혼입 2건 | 첫 문서(`01-glossary.md`) 완성 직후 사용자 확인 1회 — 형식 검증을 소규모로 먼저 |

## Milestone Closure Provenance

<!-- /mccp:milestone-close 가 발행. 마일스톤이 닫힐 때마다 이 표에 한 행. -->

계획서 본문이 아니라 **여기**에 싣는다 — 계획서 본문은 `mccp-plan-codex` ·
`mccp-implement-codex` 두 receipt 의 `plan_hash` 앵커이고, 거기에 절을 덧붙이면 두 게이트가
동시에 stale 로 떨어진다. 재앵커는 봉인된 판정을 사후에 옮기는 것이라 쓰지 않는다.

| Milestone | Verdict | Closure | sha256 | Stamped at |
|---|---|---|---|---|
| 1-01-glossary | done | `.claude/milestone-closures/1-01-glossary.md` | `sha256:b70f8f48419c890ff24ef2a5bedf338507449ecbd816cb37e311070dfd340186` | 2026-08-25T06:11:16.643Z |
| 3-01-authn | done | `.claude/milestone-closures/3-01-authn.md` | `sha256:db8146b3071bf54b99127caeb2c0c4150b9c7f590d97a8ba5914481b6e68ef7f` | 2026-08-26T06:05:44.650Z |
| 4-02-authz-roles | done | `.claude/milestone-closures/4-02-authz-roles.md` | `sha256:a7fac245f7b4502b11e70e5fd08bf2c97f2f7e5522fa2db541e8e0b5d6e346aa` | 2026-08-27T01:19:18.123Z |
| 5-04-authz-db-menu | done | `.claude/milestone-closures/5-04-authz-db-menu.md` | `sha256:e3273d729251f4258b82d815284e1fbfa9bc47e188961c5653bdbc8d09c30ff9` | 2026-08-28T02:09:18.068Z |
| 6-access-review-convergence | done | `.claude/milestone-closures/6-access-review-convergence.md` | `sha256:20d276c2dd10c9e5cf2c2fd9f86e865246b82dcba8be4858e3fc2f65e991b18b` | 2026-08-31T00:35:28.274Z |
| 7-post-closure-residual | done | `.claude/milestone-closures/7-post-closure-residual.md` | `sha256:5237fcc752cb2e8e130cfbf8141ac04f204815e5e940cd09e77edb9717006ced` | 2026-09-02T06:17:18.679Z |


---
*Status: complete — 마일스톤 7 종료 (종결 후 잔여 — PR-Codex 라운드 1 지적 3건을 검사로 닫고, closure 해시를 체크아웃 EOL 과 무관하게 만들며, `20` 앞 위임 슬롯 3건을 푼다). 이 토큰은 §Delivery Milestones 표 7행 Status 와 결박돼 있다(`insuniverse-docs-20-foundation-access-m7.gates.mjs` `check10`) — PRD 전체가 아니라 마일스톤 7 을 가리킨다. 이 마일스톤의 종료 판정은 `.claude/milestone-closures/7-post-closure-residual.md` 가 싣고 그 sha256 은 §Milestone Closure Provenance 행에 있다 — `check10` 은 값을 리터럴로 물지 않고 그 행과 문서에서 유도한다. 앞선 여섯 마일스톤의 판정은 `.claude/milestone-closures/6-access-review-convergence.md` 가 싣는다. Next: `/mccp:pr`*

> **이 행은 기계가 읽는다.** `verify.sh` `bootstrap_permitted()` 가 `^\*Status:` 를 **정확히 1개**로 요구하고 첫 토큰으로 DRAFT 여부를 판정한다. 행을 늘리거나 지우지 않는다 — 0개도 2개도 거부이며, 그 거부는 이 파일이 아니라 저장소 전체의 `--check --bootstrap` 에 떨어진다.

*부모 PRD에서 분할됨 2026-08-03. 2026-08-24 개정 — `13-relation-contract` 형식 계약 수용 + 권한 DB 전제 정정 (`findings/13-relation-contract.md` F-04).*
