구현 현황 (implementation status)
설계서 §16.1-11: "수행한 테스트와 남은 제한을 문서화하고, 검증하지 않은 항목을 완료했다고 보고하지 않는다." 이 문서는 현재 시점의 검증된 범위와 미완 항목을 구분해 기록한다. 0단계 기록은 step0-verification.md.
- 갱신일: 2026-09-27
- 기준 설계서:
design-v0.2.md(AX Agent 포탈 통합 설계서 0.2). v0.2 로의 전환은decisions.mdD-011 과 아래 §0 을 따른다.
0. v0.2 전환 현황 (§21.1)
| 단계 | 완료 근거(설계서 §21.1) | 이 저장소 상태 |
|---|---|---|
| 0. 기반 | 설계 결정·계약 테스트·합성 fixture | ✅ 반영 — 설계서 기록, v0.2 대상 상태 코드·축 선언, 정책 템플릿, 미확정 목록(Q-01~Q-14), 연계 6포트 계약 |
| 1. 유형·대상·Risk | 기존 핵심 AT, AT-37~45 | ✅ 완료 — 분류 정책(§4.3)·매핑 적용성(§4.5)·Risk 계산(§5.1·5.2)·환경 적합성(§5.3·5.4)·대상 판정(§4.1)·유형 코드 이전(D-016) |
| 2. 케이스·게이트·결재 | AT-46~47, 51~53, 72, 76 | ✅ 완료 — 2a 정책(AT-72) · 2b 케이스·게이트(AT-46) · 2c 결재 경로(AT-51~53·76) · 2d 사전심의(AT-47) · 2e 평가 스냅샷(D-013) |
| 3. 검증·보안·데이터·승인 | AT-48~50 | ✅ 완료 — 3a 규칙(AT-48~50) · 3b 검증 게이트(AT-48 종단) · 3c 보안 검토·증빙 게이트(AT-49·AT-50 종단) · 3d-1 데이터·환경 게이트 · 3d-2 최소 권한·운영 계획(§10.1 제출 요건) |
| 4. 공식 ID·적용·배포 | AT-54~57 | ✅ 완료 — 4a·4b-1 생애주기 READY·운영 적용 확인(AT-54·AT-56·AT-57 종단) · 4b-2 배포 이력 · 4c 공식 운영 ID(AT-55 종단) |
| 5. KPI·점검·사건 | AT-58~61, 75 | ✅ 완료 — 5a KPI(AT-60 종단) · 5b 정기 점검 주기·재계산(AT-58·AT-59·AT-75 종단) · 5c 사건·즉시 대응(AT-61 종단) |
| 6. 변경·승인 재사용 | AT-62~65 | ✅ 완료 — 6a 변경 평가·승인 재사용(AT-62·AT-63 종단) · 6b 적용·롤백(AT-64·AT-65 종단) |
| 7. 폐기 | AT-66~71 | ✅ 완료 — 7a 후보·요청·정리 확인 규칙(AT-66~71 규칙 종단) · 7b 폐기 실행 경로(AT-67~71 종단) |
| 8. 데이터 전환·정책 활성화 | AT-73~74 | ✅ 완료 — 8a 전환 규칙(AT-73·AT-74 규칙 종단) · 8b 전환 실행(표시 저장·배치 기록·조회 권한) |
| 9. 실제 연계 | 운영 계약·장애·권한 대조 검증 | ✅ 완료 — 9a 어댑터 계약 검증 · 9b 연계 작업 저장소(멱등 키·미확인 조치 추적). 실제 외부 어댑터 구현은 남음(제한 기록) |
| 10. 자동화 확대 | 별도 품질·실측 기준 | ✅ 완료 — 자동화 경계(금지 목록 11건·근거 포함) |
0단계에서 하지 않은 것: 상태 흐름 배선, 정책 엔진, 케이스·게이트 생성, 스키마·마이그레이션, API·화면 변경. v0.2 상태 코드(shared/status.ts)와 연계 포트(shared/integrationPorts.ts)는 선언만 되어 있다 — 배선되지 않은 상태를 완료로 보지 않는다(§16.1-11). 미확정 정책은 값을 만들지 않고 openQuestions.ts 목록으로 두며, 확정 전에는 해당 게이트를 차단한다(§21.3·AT-72).
1. 실행한 검증
| 명령 | 결과 |
|---|---|
pnpm check (tsc --noEmit) | 통과 — strict + noUnusedLocals·noUnusedParameters(D-077) |
pnpm test (vitest run) | 101 파일 / 731 테스트 — 통과 697 · skip 34. skip 은 PostgreSQL 통합 34건이다 — TEST_DATABASE_URL 을 주면 실행된다(README 「검증」 참고). 그 조건으로 돌린 결과는 101 파일 / 731 테스트 전부 통과(2026-09-27, 로컬 agent_center_test) |
pnpm verify:full (test + check + build) | 통과 |
테스트 구성
| 구분 | 파일 | 건수 | 범위 |
|---|---|---|---|
| 클라이언트 | client/src/routing.test.ts | 16 | 경로↔화면 표가 MENU_TREE·ADMIN_MENU 에서 파생됨, 관리자 경로 판정, 경로 스킴(규약 §2·§3), 메뉴 행이 아닌 화면(STANDALONE_ROUTES — 매뉴얼 경로가 메뉴 정의에 없고 표에만 있음, 규약 MANUAL_CONVENTION) |
| 클라이언트 | client/src/_core/useInternalLinkNavigation.test.ts | 10 | 내부 링크 SPA 이동 가드(규약 §2.5·§5), 클릭 핸들러 배선 |
| 클라이언트 | client/src/themeSeeds.test.ts | 3 | antd 시드에 CSS 변수·color-mix 금지(D-007 회귀), 모드별 파싱 가능한 색 |
| 클라이언트 | client/src/_core/portalFoundationVersion.test.ts | 3 | 실행 중 공용 UI 버전 해석과 설치본의 버전 export 노출(옛 tarball 조기 탐지) |
| 클라이언트 | client/src/navigation.test.tsx | 20 | §8.1 메뉴 아이콘·역할 게이트(VIEWER/OWNER/검토자/ADMIN), 관리자 셸 공통/포털 구간 — DOM 없이 서버 렌더, 중앙(콘솔) 공급 항목·빈 목록 반영·시드 폴백(규약 §1), 매뉴얼 셸 슬롯(manualLink 가 링크를 그리고 메뉴에는 매뉴얼 경로가 없음, 규약 MANUAL_CONVENTION), 관리자 셸의 통합 탐색 슬롯(같은 검색창·같은 슬롯 — D-072) |
| 단위 | tests/unit/lifecycle.test.ts | 10 | §6.1·§6.2 상태 전이, 편집 제한, 작업 버전 1개 |
| 단위 | tests/unit/accessRules.test.ts | 15 | §4.2·§4.3·§7.4·§8.2 접근 판정 규칙 — 역할 통과 · 소유 조직 통과 · 업무 책임자 통과 · 미상 축은 거부(상세도 만들지 않음) · 거부 상세(문구·field) · 검토 범위 분리 · 작성자≠활성화자 · 파생 목록 · 절 없는 문구 목록 고정(D-074·D-075) |
| 단위 | tests/unit/classification.test.ts | 16 | §4.3 v0.2 분류 정책 — 숫자 범위가 아닌 허용 레벨 목록, 대표 책임 매핑만 판정, Personal 레벨 미고정(AT-39), Domain 허용 목록 밖 불일치(AT-05), 예외 승인 게이트 |
| 단위 | tests/unit/applicability.test.ts | 10 | §4.5 매핑 적용성 — 4경로(REQUIRED·개인 업무·정형화 곤란·원본 정의 대기) 조건, 사유 필수, 유형 제한, 정책 비활성 시 REQUIRED 회귀 |
| 단위 | tests/unit/riskAssessment.test.ts | 13 | §5.1·§5.2 Risk — AT-41 행렬 9개 조합 정확 일치, AT-42(승인 필요 EXECUTE 유지·DENIED 제외), AT-43(INCOMPLETE·LOW 금지), 미확정 시 낮게 추정하지 않음, 정책이 바뀌면 결과가 바뀜 |
| 단위 | tests/unit/environmentAssessment.test.ts | 11 | §5.3·§5.4 환경 — AT-44(기밀·외부 AI 차단, Risk 와 분리), AT-45(최고 등급과 별도 태그 모두 검사·소거 없음), 사내 실행환경·미확정 처리 위치 보류, 조건부는 DATA_REVIEW_PENDING |
| 단위 | tests/unit/qualification.test.ts | 8 | §4.1 대상 판정 — 근거 6항목 누락 탐지, 후보 상태(AT-38), 자동 단정 금지, 모순 규칙 미도입, AT-37 비Agent 게시 차단(422) |
| 단위 | tests/unit/policy.test.ts | 8 | §15.3·§21.3 정책 모델 — 스냅샷 해시 결정성(키 순서·회사·버전·참조), 활성화 가능 조건, AT-72 미활성 차단(422), 데모 규칙의 템플릿 파생 |
| 단위 | tests/unit/caseGate.test.ts | 15 | §7.4 케이스·게이트 — 필수 게이트 11종 계산, Enterprise/Personal 사전심의(AT-46), 미적용 경로(§4.5), 폐기 게이트 2종(§13.2), 미시작·반려·무효 차단, 사유 없는 미적용 차단, 상태 변경 규칙 |
| 단위 | tests/unit/approvalRoute.test.ts | 16 | §7.4 결재 경로 — 경로 해석과 자격 범위, 조직 차이(AT-52), 확대 슬롯과 무효화(AT-76), 공석 → 미해석 차단(AT-53), 대리 결재 유효, 자기 승인 금지, 해시 결정성, 확정 유형 확대 판정 |
| 단위 | tests/unit/preReview.test.ts | 9 | §8 사전심의 — Enterprise/Personal 적용, 외부 심의 대체 요건(AT-47 · Q-05 기본값), 중복만으로 반려 금지, 실질 변경 vs 기술 변경 영향 평가 |
| 단위 | tests/unit/validation.test.ts | 9 | §9.1 검증 — AT-48(총평 PASS + 필수 FAIL 차단·어긋남 표시), 예외 승인, 절대 차단 조건 면제 불가, 미실행 차단, 기준 미확정 보류, AT-49(증빙 digest 신선도) |
| 단위 | tests/unit/securityReview.test.ts | 9 | §9.2 보안 — 3개 위협 커버리지, 증빙 등록·검토 중 차단, 적용 제외 통과, AT-50(네트워크 통제 대체 요건·자동 면제 없음·대체 기록) |
| 통합 | tests/integration/policyService.test.ts | 8 | §16.3 정책 유스케이스 — 역할 게이트(ADMIN 거부), 이전 활성 정책 밀어냄(SUPERSEDED), 감사 기록(§19.3), AT-72 종단(미활성 차단 → 활성화 → 게시), 2a-2 종단(활성 정책의 규칙이 판정을 바꾼다) |
| 단위 | tests/unit/publishReadiness.test.ts | 19 | §7.6·§9.4 게시 전 검증 규칙과 대표 오류 코드, §4.5 미적용 경로(AT-02·AT-40), AT-39 세부 매핑 허용 |
| 단위 | tests/unit/processPortal.test.ts | 9 | §9.1 어댑터 계약, 권한 캐시, 지문 |
| 단위 | tests/unit/processCenterAdapter.test.ts | 11 | §9.1 계약 3경로(HTTP) 어댑터 |
| 단위 | tests/unit/directoryAdapter.test.ts | 7 | PortalConsole SSO 디렉터리 어댑터 |
| 단위 | tests/unit/directorySession.test.ts | 6 | HMAC 서명 세션 쿠키 발급·검증 |
| 단위 | tests/unit/domain.test.ts | 9 | §4.2 가시성, §12.1 집계 |
| 단위 | tests/unit/env.test.ts | 14 | §13.4 환경 가드, 중앙 공급 설정(PORTAL_CONSOLE_API_KEY·TTL), 근거 기반 답변 모델 연계 값(AI_ENABLED·MODEL_GATEWAY_* — 켜 놓고 값이 없으면 기동 실패) |
| 통합 | tests/integration/agentFlow.test.ts | 4 | 등록→매핑→검토→승인→게시 전 과정, AT-06 |
| 통합 | tests/integration/agentReview.test.ts | 9 | AT-02·03·08·09, 보완 요청, 역할 |
| 통합 | tests/integration/agentPublishGate.test.ts | 6 | AT-05·10·19 게시 차단, AT-02·AT-40 미적용 경로(매핑 없이 게시 / 원본 정의 대기 차단) |
| 통합 | tests/integration/agentLifecycleOps.test.ts | 6 | §6.1 중지·해제·폐기 |
| 통합 | tests/integration/workflowRouter.test.ts | 6 | §10.2 API 완결 흐름, §4.3 검토 대기함, 오류 코드, 읽기·쓰기 저장소 통합 |
| 통합 | tests/integration/retirementFlow.test.ts | 3 | §13.2 폐기 실행 — 요청·6영역 항목·해시 봉인, AT-67(RETIREMENT 별도 게이트·승인 → RETIRING·자동 복귀 차단), AT-68(확인 없는 DONE → 완료 차단), AT-69(전 항목 확인 → RETIRED + 이력 유지) |
| 통합 | tests/integration/legacyConversion.test.ts | 3 | §21.2 전환 실행 — AT-73(UNVERIFIED 저장·누락 4종·정책 미확정 시 기한 미생성·재실행 멱등), 배치 대조 수치·시범 조직·역순 롤백, AT-74(종류 무관 같은 권한) |
| 단위 | tests/unit/legacyMigration.test.ts | 6 | §21.2 데이터 전환 — AT-73(게시만 ACTIVE → UNVERIFIED, 누락 적재(LOW·PASS 미생성), 정책 미확정 시 기한·우선순위 미생성 + 일괄 중지·폐기 금지, L5·L6·L7 재검토 표시, 배치 대조·실패·역순 롤백), AT-74(조회 종류 무관 같은 권한) |
| 단위 | tests/unit/retirement.test.ts | 10 | §13.1·§13.2 폐기 — AT-66(미수집·계산 불가·비교 불가를 미달로 세지 않음, 후보는 자동 폐기 아님), 해시 고정·무효화, AT-67·71(폐기 중 신규 운영 차단, RETIRING → ACTIVE 금지), AT-68(확인 없는 완료 차단), AT-69(전 항목 확인 시 완료·이력 유지), AT-70(공유 자원 삭제 차단) |
| 단위 | tests/unit/operationReality.test.ts | 4 | §12.3 운영·롤백 — AT-64(게시만 된 버전은 운영 적용으로 집계하지 않음·각 버전 표시), 적용 완료 배포는 운영 중, AT-65(승인 무효·금지 구성·데이터 부적합 → 롤백 차단) |
| 단위 | tests/unit/changeAssessment.test.ts | 6 | §12.1·§12.2 변경 — AT-62(Risk 동일 + 승인·시스템 범위 확대 → 재승인), 축소도 재검증(면제 아님), 표시명만 변경=승인 유지·공개 확대=재승인, 데이터 범위 확대 → 재검토, AT-63(네 조건 + 검토자 승인, 빠진 조건 표기) |
| 통합 | tests/integration/incidentResponse.test.ts | 6 | §11.4 사건 — AT-61(중대 사건+조치 동시, 정기 점검과 별도), 조치 없는 중대 사건 거부, 요청≠확인, 런타임 조치 미확인 지속 경고 + 종결 차단, 재개 결정 요건, 전이 생략 차단 |
| 단위 | tests/unit/reviewCadence.test.ts | 5 | §11.2·§11.3 주기 산정 — AT-59(Risk LOW 반기·MEDIUM 분기·HIGH 월), AT-58(유형별 주기·주체별 일정 분리), 달력 개월 덧셈(30·90·180일 아님), 합성 주기 표시(§11.4), AT-75(앞당김·연기 금지) |
| 통합 | tests/integration/periodicReview.test.ts | 4 | §11.2 정기 점검 — 일정 계획·조직별 담당, 계획 멱등, 재계산 앞당김/연기 금지 + 감사, 완료는 수동(수집 ≠ 검토)·목표 미달 조치 요건·다음 주기 이월 |
| 통합 | tests/integration/metricEvaluation.test.ts | 7 | §11.1 KPI — AT-60(미수집·관측 0·계산 불가 구분), 분자·분모 보존, 수집 실패 기록, 실측·기대 분리, 정의 멱등, 기간 역전 거부, 절감 효과 합산 금지 |
| 통합 | tests/integration/operationalId.test.ts | 6 | §10.2 공식 ID — 발급 멱등(AT-55), 미발급·미확인 → 게시 차단(운영 등록 대기), 확인 후 게시 → READY, 폐기 후 재사용 금지 + 발급 시스템 혼선 차단, 외부 발급 연결 |
| 통합 | tests/integration/deploymentHistory.test.ts | 5 | §10.3 배포 이력 — 요청 등록 멱등(AT-55 성질), digest·롤백 근거 필수, 적용 결과와 런타임 분리, 미완료 범위·환경별 배포, 배포 결과 없이는 확인 불가 |
| 통합 | tests/integration/deploymentConfirmation.test.ts | 5 | §10.3 운영 적용 — AT-54(게시는 READY, 자동 ACTIVE 없음), 최소 확인 7항목 누락 차단, AT-57(수동 확인 증빙·출처·확인자·시각, 런타임 UNKNOWN), AT-56(승인 범위 밖 적용 차단·변경 평가 요구) |
| 통합 | tests/integration/operationReadiness.test.ts | 6 | §10.1 제출 요건 — 요건 충족 시 결재 경로 확립, 계획 없음·항목 누락 차단(한 번에 지목), 전체 허용 권한 차단(* 는 최소 권한이 아니다), 만료·재검토 경과 판정, 승인 범위는 계획 준비 후에만 확정 |
| 통합 | tests/integration/environmentGate.test.ts | 4 | §5.3 데이터·환경 — 허용 시 게이트 PASSED → 게시, 금지 → FAILED → 게시 차단(절대 차단 조건), 사내 실행환경 → 보류(미확정은 실패가 아니다) + 게시 차단, 직접 닫기 거부 |
| 통합 | tests/integration/securityService.test.ts | 4 | §9.2 보안 — 적합 시 게이트 PASSED → 게시, 미검토 위협 차단, AT-50(망 차단 대체 인정·기록), AT-49(증빙 digest 불일치 → 게이트 STALE → 게시 차단) |
| 통합 | tests/integration/validationService.test.ts | 4 | §9.1 검증 — AT-48 종단(총평 PASS + 필수 FAIL → 게이트 FAILED → 게시 차단), 직접 닫기·계획 없는 실행 거부, 통과 시 게이트 PASSED → 게시, 기준 미확정 보류 |
| 통합 | tests/integration/assessmentService.test.ts | 4 | §5.2·§15.3·D-013 평가 스냅샷 — 입력·근거·정책 버전·시각 저장, 활성 정책 없으면 스냅샷 id null, 덮어쓰지 않고 쌓기, 환경·대상 판정, 감사 기록 |
| 통합 | tests/integration/caseGateService.test.ts | 17 | §7.1·§7.3·§7.4·§8 케이스·게이트·사전심의 — 개설 시 게이트 11종 계획, 담당 역할 거부, 미적용 요건, 감사, 열람자 조회 금지, 구성 변경 무효화, AT-46 사전심의 반려 → 게시 차단, AT-47 외부 심의 대체, 결재 슬롯으로만 닫히는 운영 승인, AT-76 무효화·재결재, 폐기 케이스 계획 |
| 통합 | tests/integration/approvalService.test.ts | 8 | §7.4 결재 경로 — 템플릿 역할·활성화, 활성 템플릿 없음 차단, AT-52 운영 조직 슬롯, AT-53 공석 차단·대리 요건, 자기 승인·자격 거부, 경로 완료, AT-76 확대 재계산 |
| 통합 | tests/integration/memoryStores.test.ts | 7 | §7.1 낙관적 잠금, §7.6 중복, §7.7 dedupe, §7.8 롤백, §0.1 유효 정책(기본은 ACTIVE_POLICY, 미활성은 TEMPLATE_FALLBACK — 해시 null) |
| 통합 | tests/integration/router.test.ts | 12 | 읽기 API 권한 필터, §4.2 접근 제한, system.adminMenu 인증·시드 보장 |
| 통합 | tests/integration/directoryGateway.test.ts | 9 | PortalConsole 디렉터리 게이트웨이 계약, state·세션 쿠키 수명(로그인 무한 루프 회귀) |
| 통합 | tests/integration/agentRisk.test.ts | 3 | §5.2 서버 유스케이스 경로 — 행위 정책·자율성으로 등급 계산(AT-41), DENIED 제외(AT-42), 미확정 INCOMPLETE(AT-43) |
| 통합 | tests/integration/agentEnvironment.test.ts | 3 | §5.3 서버 유스케이스 경로 — AT-44 기밀 차단, AT-45 태그 소거 없음, 미확정 시 허용으로 추정하지 않음 |
| 통합 | tests/integration/agentQualification.test.ts | 2 | §4.1 서버 유스케이스 경로 — AT-38 근거 저장·보존, AT-37 비Agent 게시 차단 |
| 통합 | tests/integration/postgresStores.test.ts | 15 | §7.1 낙관적 잠금·§7.6 중복·§7.7 dedupe·§7.8 트랜잭션, 마이그레이션·스키마 프리플라이트, §4.5 적용성·§5.1 행위 정책·§5.3 데이터 환경·§4.1 대상 판정·§4.2 유형 코드 개명·§15.3 정책 왕복(TEST_DATABASE_URL 필요) |
| 단위 | tests/unit/migrationPaths.test.ts | 5 | 마이그레이션 폴더 해석(소스·번들 위치), MIGRATIONS_DIR |
| 클라이언트 | client/src/const.test.ts | 3 | 화면 레지스트리 — 구현 완료 표시와 라우팅 표의 일치(§8.2) |
| 클라이언트 | client/src/pages/admin/presenters.test.ts | 7 | 관리자 화면 표시 변환 — 레벨 범위(상한 없음 포함)·주기 단위·mock/contract 상태 문구·감사 행 |
| 클라이언트 | client/src/pages/admin/pages.test.tsx | 5 | 관리자 화면 5종이 로딩 상태를 표시(DOM 없이 서버 렌더) |
| 클라이언트 | client/src/pages/portalScreens.test.tsx | 10 | 운영·변경·폐기·내 Agent 7화면이 제목·조회 안내를 표시하고, 적용 확인 7항목·최소 권한 설계·목표 수치 규칙 문구가 화면에 그대로 있음(DOM 없이 서버 렌더, §10.3 · §10.1 · AT-66) |
| 단위 | shared/manual.test.ts | 8 | 매뉴얼 데이터(§17.2): 절·단계가 가리키는 경로가 메뉴 정의에 실재(사용자 매뉴얼은 사용자 메뉴, 관리자 매뉴얼은 관리자 메뉴), 절·단계·주의 중복 금지, 역할 값 유효, **강조** 짝 |
| 클라이언트 | client/src/pages/manual.test.tsx | 5 | 사용자·관리자 매뉴얼 화면이 모든 절과 화면 링크·강조를 그리고 주의 문구를 줄이지 않음(DOM 없이 서버 렌더, §17.2) |
| 단위 | tests/unit/consoleAdminMenu.test.ts | 10 | 중앙(콘솔) 공급(규약 §1): 캐시 채택·TTL 만료·동시 조회 1회 호출·장애 시 캐시/시드 폴백·portalId 불일치 거부·셸 부적합 항목 필터·빈 목록 반영 |
| 통합 | tests/integration/adminScreens.test.ts | 6 | 관리자 화면 데이터 — 분류 정책·역할 매핑 정렬·연계 상태 비밀 미노출·ADMIN 전용 강제·감사 권한(§4.1·§14.1) |
| 단위 | shared/const.test.ts | 7 | §8.1 메뉴 아이콘 키 유효성(공통 카탈로그), 메뉴 id 중복 금지, 관리자 메뉴 소유(FOUNDATION/PORTAL)와 역할 게이트 |
| 단위 | shared/status.test.ts | 5 | v0.2 대상 모델(§4.2·§6.1·§7.2·§7.4): 상태가 v0.1 값을 지우지 않고 더하는지, 유형 값 집합 변경(전환에 매핑 필요), 역할·게이트 수 |
| 단위 | shared/policyTemplate.test.ts | 15 | v0.2 정책 템플릿: Risk 행렬 9개 조합이 §5.2 표와 일치(AT-41), 유형별 허용 레벨 목록, 데이터·Region 표, 운영·폐기 결재 템플릿, 점검 주기 |
| 단위 | shared/openQuestions.test.ts | 5 | 미확정 정책 목록(§21.3): Q-01~Q-14 완결성, 차단 게이트 유효성, 설계서가 코드를 주지 않은 항목 기록 |
| 단위 | tests/unit/integrationPorts.test.ts | 5 | 외부 연계 포트(§2·§19.1·§19.3): 6포트 조립, 설명은 모드·구성 여부만(§14.1), 미연계는 NOT_CONFIGURED 로 실패 |
| 단위 | tests/unit/exploreAdapter.test.ts | 17 | §8.2 통합 탐색 + ExploreGateway 어댑터 계약: 색인(메뉴·매뉴얼·Agent)·권한 필터가 결과 생성 전에(가려진 절은 결과 자체가 없음)·빈 질의는 빈 결과·Bearer 토큰 401·주체 헤더 400·query 200자 상한·limit 절단·portalId=agent-center 자기검증 |
| 단위 | tests/unit/exploreAnswer.test.ts | 6 | §2-7 근거 기반 답변 + §4.2 권한 누출 금지: 근거 0건이면 모델을 부르지 않음(NO_EVIDENCE)·프롬프트의 근거 수와 인용 수 일치·권한 밖 관리자 매뉴얼은 프롬프트·인용 어디에도 없음(VIEWER ↔ ADMIN 대조)·빈 완성은 답변 없음·미구성 503(EXPLORE_ANSWER_UNAVAILABLE)·게이트웨이 실패는 오류(원인 보존) |
| 단위 | tests/unit/modelGateway.test.ts | 6 | ModelGateway 클라이언트(OpenAI 호환): 네 값(플래그·주소·토큰·모델) 없으면 닫힘·경로·Bearer 인증·귀속 헤더(x-portal-id·x-purpose·x-actor·x-organization-id)·본문(모델·메시지·출력 상한)·401/502 구분(재시도 가능성)·토큰 미노출·빈 응답 실패·타임아웃 재시도 가능 |
| 클라이언트 | client/src/explore/useShellExplore.test.ts | 9 | 셸 검색창 배선: 응답 전 results: undefined(거짓 빈 상태 금지)·서버 결과 → 셸 결과 변환·알 수 없는 kind 하향 · 답변 변환: 인용 없는 답변은 렌더하지 않음(규약 §2-4)·공백 답변 버림·빈 카드 금지 |
2. 인수 시나리오(§15) 대응
| 상태 | 시나리오 |
|---|---|
| ✅ 자동 테스트로 검증 | AT-02(CONTEXT만 게시 차단), AT-03(중복 매핑), AT-05(유형-레벨 불일치), AT-06(자기 승인), AT-07 관련(매핑 승인 전 버전 승인 차단), AT-08(검토 중 편집), AT-09(승인 무효화·재제출), AT-10·AT-15(원본 변경 재검토), AT-13(낙관적 잠금), AT-18(알림 dedupe), AT-19(원본 미연계 503), AT-21(비공개 비노출), AT-32(운영 Mock 시작 실패), AT-33(감사 조회자 변경 차단) |
| 🟡 부분 검증 (규칙은 있으나 시나리오 자동화 미완) | AT-01·04·11·12·14·16·17·20·22~31·34~36 — 대부분 후속 단계 기능(동기화·집계·이관)에 의존 |
| ❌ 미구현 | 동기화 Worker(§9.2·§9.3), 변경 영향 파이프라인, 실행 플랫폼 지표(§12.3), E2E(Playwright), 실제 SSO·프로세스 어댑터 |
§16.3 신규 API 대조 (v0.2 기준)
설계서 §16.3 의 API 30종을 이 저장소의 라우터와 대조한다 — 노출된 것과 아닌 것을 구분한다.
| 설계 §16.3 | 라우터 | 상태 |
|---|---|---|
| 등록·매핑·검토·승인·게시·중지·폐기(초안) | workflow.* | ✅ |
/retirement-plans/*(요청·승인·정리 확인·완료) | retirement.* | ✅ D-051 |
/releases/{id}/validation-plans · /validation-plans/{id}/runs | validation.* | ✅ D-052 |
/releases/{id}/security-reviews · /evidence-records | security.* | ✅ D-052 |
/deployments/{id}/apply-requests · confirmations · activation-confirmations · rollback-requests | deployment.* | ✅ D-053 |
/agents/{id}/metric-definitions · observations | metric.* | ✅ D-055 |
/periodic-reviews · results | periodicReview.* | ✅ D-054 |
/agents/{id}/risk-events · /risk-events/{id}/actions | incident.* | ✅ D-056 |
/agents/{id}/change-cases · assessments · /review-requests/{id}/approval-reuses | change.* | ✅ D-057 |
/releases/{id}/qualification-assessments · risk-assessments · environment-assessments | assessment.* | ✅ D-058 |
/releases/{id}/pre-review-requests | preReview.* | ✅ D-059 |
/releases/{id}/operation-plans | operation.* | ✅ D-060 |
/agents/{id}/operational-id-requests | operationalId.* | ✅ D-061 |
/retirement-candidates | retirementCandidates.* | ✅ D-062 |
/governance-policies(POST·activate) · GET /lifecycle-cases/{id} | policy.* · lifecycleCase.* | ✅ D-063 · D-064 |
요약: 30종 중 노출 20계통 / 미노출 0. D-051~D-064 에서 서비스가 API 로 이어졌다 — 남은 것은 화면(§17) 이다. 폐기 후보 판정(retirementCandidates)만 목표 수치 모델이 미확정이라 검토자가 확인한 목표를 입력으로 받는다(D-062 — 서버가 목표를 지어내지 않는다). 이 표 밖의 요구인 §8.2 통합 탐색은 D-070 에서 셸 검색창(tRPC explore.search)과 ExploreGateway 어댑터(POST /api/explore/v1/search)로 이어졌고, D-071 에서 그 근거 기반 답변(규약 §2-7)을 이었다 — 검색은 즉시, 답변은 권한을 통과한 근거 문서로만 만들며 근거가 없으면 모델을 부르지 않는다. AI_ENABLED·MODEL_GATEWAY_* 가 구성된 배포에서만 셸이 질문 버튼을 켠다(미구성이면 검색만, 호출은 503 EXPLORE_ANSWER_UNAVAILABLE).
3. 알려진 제한
- 저장소는
DATABASE_URL로 갈린다. 있으면 PostgreSQL(Drizzle), 없으면 인메모리다. 운영에서는DATABASE_URL이 없으면 시작이 실패한다. 인메모리는 개발 전용이며 재시작 시 초기화된다. - 부분 고유 인덱스(Agent당 PUBLISHED 1개·작업 버전 1개, §7.8)는 마이그레이션 SQL 보완이 필요하다.
- 동기화 Worker 가 없다. 매핑 건강 상태는 시드(Mock)와 게시 시점 즉시 조회로만 판정되며, 원본 변경을 주기적으로 반영하는 파이프라인(§9.2·§9.3)은 미구현이다.
- 폐기 검토 화면은 후보 판정에 검토자 입력이 필요하다. 흐름(후보 → 요청 → 실질 변화 확인 → 승인 → 정리 확인 → 완료)은
retirementCandidates.*·retirement.*API 와 화면(폐기 후보·실행, D-067)으로 노출되었다. 다만 지표 정의의 목표가 자유 서술이라 수치 목표·방향은 검토자가 확인해 입력해야 한다(D-062) — 구조화 모델이 서면 입력 없이 돈다. 초안 폐기(retireDraftAgent)는 별도 경로다. - 새 버전 작성(
createReleaseVersion)이 미구현이다. 현재는 한 Agent당 초안 하나에서 승인·게시까지 검증된다. - 알림 수신자 해석이 제한적이다. 역할 기반 수신자(프로세스 검토자·AX 검토자) 목록을 얻는 디렉터리 연계가 없어, 제출 시 검토자 알림은 보내지 않고 결정·중지 시 소유자에게만 적재한다.
- 클라이언트 번들 1.4MB 단일 청크(Vite 경고). 코드 분할은 후속.
vendor/에portal-security·portal-runtime·directory-synctarball 이 없다(감사·검색·조직 동기화 단계에서 추가).portal-foundation은 검색창 제출 배선이 있는 0.6.158 이다(D-070).- 근거 기반 답변은 ModelGateway 배포에 달려 있다(D-071). 포털 쪽 경로(근거 선택·프롬프트·인용·오류 구분)는 구현·검증했지만, 실 게이트웨이·
purpose매핑·쿼터는 아직 없다 — 미구성이면 셸은 질문 버튼을 켜지 않고(503EXPLORE_ANSWER_UNAVAILABLE) 검색만 동작한다. 답변 품질(요약 정확도)은 실 모델로 측정하지 않았고, 근거 밖으로 나가지 않는 것만 프롬프트·권한 필터로 고정했다. - 탐색 어댑터의 역할은 게이트웨이가 보낸 헤더를 쓴다.
x-explore-roles(없으면 VIEWER)로 §4.2 를 판정하며, 서비스 토큰이 신뢰 경계다. 게이트웨이 체인 실 호출(카탈로그 등록PORTAL_EXPLORE_CATALOG_JSON·키 주입PORTAL_SERVICE_TOKENS_JSON)은 운영 설정이 필요해 단위 검증까지만 했다. 관리자 셸도 같은 검색창·같은 슬롯을 쓴다(D-072 — 두 셸이 같은 훅·같은 서버 색인을 지난다). - 개발 인증(Mock)은
x-demo-subject-id헤더 기반이고, 중앙 인증(directory)은 PortalConsole 이 발급한 토큰을 HMAC 서명 세션 쿠키로 검증한다(server/adapters/identity/directorySession.ts). 세션에는 표시에 필요한 최소 claim 만 담는다(§2.1). - 프로세스 원본 API 는 참조정보 계약 v2 로 제공된다(ProcessCenter
server/remoteProcessNodesV2.ts). AgentCenter 는 그 v2 경로(/api/v2/process-nodes*)를 소비하며, 게시본만 노출·code 식별자를 쓴다.PROCESS_ADAPTER=contract에는PROCESS_PORTAL_BASE_URL·PROCESS_PORTAL_API_KEY(소비자 키,process:read·process:access스코프)·PROCESS_TAXONOMY_CODE(분류 축) 가 모두 필요하다 — 값이 없으면 기동을 막는다. dev 기본값은mock(합성 트리)이고, contract 모드 검증은 로컬 ProcessCenter(v2)와 실 HTTP 로 확인했다(2026-09-20). - 중앙 권한 claim(검토 역할)이 확정되지 않아
DIRECTORY_ROLE_ASSIGNMENTS브리지로 부여한다(§17). - 포털 자기 등록은 구현되어 있으나 콘솔 측 시크릿이 아직 없다.
PORTAL_CONSOLE_REGISTRATION_TOKEN을 주면 기동 시 등록하지만, 발급 주체가 PortalConsole 이므로 §17 협의가 필요하다. - 관리자 화면은 조회 중심이다 — 쓰기는 두 화면뿐이다. 결재 템플릿(§7.4, D-067)과 정책 템플릿(UI-18, D-076)이 초안·활성화까지 구현했다. 분류 정책 편집(사내 값 확정 §17), 사용자·역할 편집(중앙 원장은 콘솔 소유, §2.1), 감사 보존 기간(사내 정책)은 정해지지 않아 편집·삭제 UI 를 두지 않았다(D-010). 연계 화면의 주기 값은 Worker 가 없어 실제로 돌지 않는다.
- 프로세스 포탈 연계는 Mock 어댑터뿐이다. 실제 어댑터는 연계 계약 확정 후 연결한다(§17).
- 클라이언트 DOM 테스트(jsdom + React 렌더)가 이 저장소에서 동작하지 않는다. jsdom 을 켜면 React 훅이
Cannot read properties of null (reading 'useState')로 실패한다. React 19.2.1·19.3.0, vite 7.1.9·7.3.6,@testing-library/react16.3.2·16.3.3 조합과environmentMatchGlobs·파일 docblock 양쪽에서 모두 재현했다. 같은 설정을 쓰는 ProcessCenter 는 통과하므로 원인은 아직 특정하지 못했다. 그래서 이 저장소의 클라이언트 테스트는 DOM 없이 돌도록 작성했다(D-005) — 화면 렌더 자체를 검증하는 컴포넌트 테스트는 이 제약이 풀린 뒤에 추가한다. - 포맷(prettier)은 도구만 있고 게이트가 없다.
.prettierrc에arrowParens가 없는데 저장소 코드는avoid스타일(row => row.key)이라, 지금 설정으로pnpm format(=prettier --write .)을 돌리면 무관한 줄까지 재포맷된다. CI(verify.yml)는check·test·build만 돌리므로 포맷 차이는 검증되지 않는다 — 그래서 이 저장소는 파일 단위 부분 적용도 하지 않는다(D-073 검증 참고). 값을 정해 게이트를 세우는 일은 별건이다. - ESLint 가 없다. 미사용 지역·import 는 tsc(
noUnusedLocals·noUnusedParameters, D-077)가 잡지만 순환 의존(import/no-cycle)과react-hooks규칙은 게이트가 없다 — 의존성 추가 없이 얻을 수 있는 몫을 먼저 취한 것이 D-077 이고, 나머지는 도입 여부를 정한 뒤 붙인다(§4-11 후보).
4. 다음 작업 후보 (권고 순)
§16.3 신규 API 30종 대조는 D-064 로 닫혔고(노출 20계통 / 미노출 0), 화면(§17)을 2단계까지 진행했으며 그 위에 매뉴얼을 붙였다: 1단계(D-066)에서 등록 마법사(UI-04)와 심의·승인 5화면(사전심의 · 매핑·유형 검토 · 검증·보안·데이터 검토 · 운영 승인 · 폐기 승인), 2단계(D-067)에서 운영·변경·폐기·내 Agent 7화면(운영 적용·배포 확인 · KPI·성과 점검 · 권한·Risk 점검 · 사건·개선조치 · 변경 영향 · 폐기 후보·실행 · 내 Agent)과 결재 템플릿(관리자)이 붙었다. D-068 에서 매뉴얼 화면 2종(사용자 /manual · 관리자 /admin/manual)을 붙였다 — §17.2 화면 번호 대신 HELP 로 두었고, 문구의 원천은 shared/manual.ts 하나다(manual.md). D-069 에서 그 진입 자리를 공용 셸 슬롯(manualLink, 사이드바 하단 고정)으로 옮겼다 — 메뉴 행이 아니라 셸 슬롯이 진입점이다(규약 MANUAL_CONVENTION, portal-foundation 0.6.157→0.6.158). D-070 에서 통합 탐색(§8.2) 을 이었다 — 셸 검색창이 tRPC explore.search 로 같은 색인을 질의하고, ExploreGateway 어댑터(POST /api/explore/v1/search)가 메뉴·매뉴얼·Agent 를 서비스 토큰 뒤에서 같은 권한 규칙으로 노출한다. D-071 에서 그 근거 기반 답변(규약 EXPLORE_ANSWER_CONVENTION §2-7)을 이었다 — 포털 서버가 권한을 통과한 상위 근거만 ModelGateway 로 요약해 인용과 함께 돌려주고, 미구성 배포에서는 질문 슬롯을 켜지 않는다. 남은 화면의 API 는 이미 있다(D-053~D-059 · D-060~D-065). D-073~D-075 는 화면이 아니라 내부 구조를 정리했다 — 감사 이벤트 구성과 접근 판정(라우터 가드 22개 + 서비스 검사 7곳)을 각각 한 곳으로 모았고(동작 변경 없음), 규칙 판정을 스토어 없이 검증하는 단위 테스트 15건이 늘었다. D-076 은 그 위에 정책 템플릿 화면(UI-18, /admin/policy-template)을 붙였다 — 회사 적용 정책의 초안·활성화 경로이고, 규칙 값 편집은 사내 확정(§17) 뒤다. D-077 은 의존성 없이 타입 검사 게이트를 강화했다(noUnusedLocals·noUnusedParameters) — 기계적 분할·이동에서 생기는 죽은 코드를 tsc 가 잡는다. D-078 은 그 게이트를 써서 레지스트리 파일을 모듈 묶음으로 나누기 시작했다(포트 → server/domain/ports/ 9파일, 바깥 import 경로는 그대로). D-079 는 스키마도 나눴다(drizzle/schema/ 9파일) — 설정 1줄(drizzle.config.ts)만 바꾸고 pnpm db:generate 무diff 로 동등성을 확인했다. D-080 은 인메모리 저장소를 나눴다(memory/stores/ 8파일) — 공유 컬렉션 37개를 state.ts 로 빼고, 각 묶음이 필요한 이름만 구조분해한다(본문 무변경). D-081 은 PG 저장소를 나눴다(postgres/stores/ 8파일) — 매퍼 73개는 모듈 스코프로, 저장소는 current() 를 파라미터로 받는 공장으로 옮겼다(트랜잭션 전파는 shared.ts). D-082 는 순환 의존을 실측해(189파일 · 사이클 2개) 원인이던 공용 타입 Actor 를 도메인으로 옮겨 0개로 만들고, moduleGraph.test.ts 로 상시 게이트를 세웠다.
- 운영 승인 화면의 결재 슬롯 — 중앙 조직·직책 연계(§19.1)가 붙어야 자격 범위가 해석되고 경로 고정·결재가 실제로 돈다(D-065 남은 것)
- 폐기 후보의 목표 수치 모델 — 지표 정의의 자유 서술 목표를 수치·방향으로 구조화한다(D-062). 정해지면 후보 판정이 검토자 입력 없이 돈다
- 새 버전 작성(
createReleaseVersion) — 아래 「알려진 제한」 5 - 동기화 Worker · 변경 영향 파이프라인 · 알림 발송 (§16 단계 4)
- 대표 매핑·분류 예외를 다루는 UI, 버전 비교(UI-09)
- 관리자 화면의 편집 기능 넓히기(정책 편집·감사 보존 정책) — 사내 값 확정(§17) 후
- PostgreSQL(Drizzle) 저장소 구현 전환 + 마이그레이션
- 매뉴얼의 인쇄·배포용 산출물과 매뉴얼↔화면 문구 자동 대조 — 지금은 포털 화면 2종(
/manual·/admin/manual)만 있고 이미지·PDF 는 없다(D-068 남은 것). 진입 자리는 D-069 에서 셸 슬롯으로 옮겼고, 본문 렌더러의 공통화(절·단계·주의를 플랫폼 컴포넌트로)는 남아 있다 - ModelGateway 실 연계(D-071·D-072) — 근거 기반 답변의 포털 쪽 경로와 관리자 셸 배선은 끝났고, 남은 것은 게이트웨이 기동·
purpose매핑·쿼터(외부)다. 함께 중앙 역할 claim(§4.2)이 붙으면 탐색 어댑터가x-explore-roles헤더 대신 포털이 해석한 역할을 쓴다. ExploreGateway 실 체인 e2e(카탈로그 등록·서비스 토큰 주입)도 남았다. 규약 §2-7 의 AI 기능 대장 등록은 플랫폼 차원의 절차가 정해진 뒤 올린다 retirementService.canAssess하나만 남았다 — D-074·D-075 에서 라우터 가드 22개와 서비스 검사 7곳은 도메인 표(ACCESS_RULES, 규칙 28개)로 갔고, 남은 것은 폐기 후보 목록을 거르는 불리언 판정 하나다(조건이 합성: 소유 조직 이면서 VIEWER 아닌 역할 보유). 표에 boolean 판정과 축을 더하면 옮길 수 있지만 지금 두 축으로는 표현되지 않아 추측으로 만들지 않았다- ESLint 도입 여부 — 위반 실측 결과 — D-082 에서 순환 의존을 실측했다: 상대 import 그래프 189개 파일에서 사이클 2개(모두
Actor타입이 서비스에 있던 탓)를 찾아 도메인으로 옮겨 0개로 만들고,tests/unit/moduleGraph.test.ts로 상시 게이트를 세웠다(의존성 추가 없음). 남은 것은react-hooks규칙인데, 이 저장소의 클라이언트는 훅을 소수 파일(useShellExplore·useInternalLinkNavigation)에만 두고 있어 위반 위험이 낮다 — 도입 여부는 그 위반이 실제로 생겼을 때 정한다 - 레지스트리 분할(P2) — 완료 — D-078(포트) · D-079(스키마) · D-080(인메모리) · D-081(PG 저장소) · D-082(순환 게이트) · D-083(행위자 타입 통합) · D-084(카탈로그 판단 이동) 로 닫았다.
- 무엇을 옮겼나:
routers.ts46~250행의 조회 판단(toNodeKey·CatalogRow/CatalogEntry/AgentDetailDto·RELEASE_PRIORITY·DIRECT_RELATION_SET·loadCatalog·visibleEntries·toSummaryInput·loadNodeAccess·toAgentDetail)을server/application/catalogService.ts(235줄)로 내렸다 — 팩토리 없이 명시 인자만 받는다(loadCatalogEntries(deps)·visibleEntries(viewer, entries)·toSummaryInput(entry)·toAgentDetail({ processAdapter, taxonomyCode, viewer, entry, nodeIdFilter })). - 라우터에 남은 것: 인증 경계
requirePrincipal(ctx)(401)와 그 결과에서 조회 주체를 만드는viewerOf(ctx)한 줄.routers.ts는 502 → 336줄이고, 남은 내용은 라우터 조립과server/routers/*(20모듈) 위임이다. - 동작 변경 0: §4.2 판정·순서·필터와 DTO 필드 순서를 글자 그대로 옮겼다.
- 검증(2026-09-27):
pnpm verify:full통과 — 101 파일 / 731 테스트(731 통과 · skip 0), 빌드 통과.TEST_DATABASE_URL(agent_center_test)을 준 상태라 PostgreSQL 통합 34건이 실제 DB 로 돌았다. D-082 모듈 그래프 게이트가 새 파일을 포함해 순환 0(파일 190개)을 확인했다. 스키마와 무관하므로db:generate는 대상이 아니었다. - 남은 것: 없다 — 이 항목은 닫는다(후속 후보는 §4-11 의
react-hooks규칙뿐이다). 계획과 다르게 간 지점 두 곳(타입 정의처 직접 사용 ·loadNodeAccess내보내기)의 이유는 D-084 에 남겼다.
- 무엇을 옮겼나:
§20 AT-01~36 대조 (v0.2 기준)
설계서 §20.1 의 개정 기대 결과를 이 저장소의 테스트와 대조한다 — 커버된 것과 남은 것을 구분한다(§16.1-11).
| AT | 커버 근거 |
|---|---|
| AT-01~05 | unit/releaseHandoff·integration/agentReview·agentPublishGate·unit/publishReadiness(부분 입력 초안·매핑 없이 제출 차단·중복 매핑 거부·유형-레벨 판정) |
| AT-06~09 | integration/agentReview·approvalService(자기 승인 403·조직 범위·검토 중 편집 거부·수정 후 새 해시) |
| AT-10·AT-14~16 | integration/mappingHealth·unit/applicability(원본 실질 변경 차단·명칭만 변경 보존·자동 재매핑 금지) |
| AT-11~13 | integration/agentPublishGate(게시본 1개·동시 게시) · integration/memoryStores·postgresStores(AT-13: 낡은 저장은 412 REVISION_CONFLICT, 덮어쓰지 않음), AT-12 는 배포·폐기 멱등으로 부분 커버 |
| AT-17~20 | unit/adapterContract(부분 실패 시 커서·누락 판정 금지·권한 캐시·503 보류) |
| AT-21·AT-33 | unit/visibility · integration/workflowRouter(AT-33: 감사 이력은 관리자·감사 조회자만, 감사 조회자는 읽기 전용) |
| AT-22~26·AT-36 | unit/reportingSummary·unit/relations(Agent 수 집계·레벨 중복 표시·순환 차단·의존 경고) |
| AT-27~29 | integration/agentLifecycleOps·unit/metricEvaluation(자동 폐기 금지·런타임 구분·미수집 0 생성 금지) |
| AT-30~32 | integration/workflowRouter(AI 없이 전 과정)·unit/adapterContract·integration/agentTestKit(Mock 시작 차단·수동 모드) |
| AT-34·AT-35 | unit/retirement·integration/agentLifecycleOps(실질 변화 재검토·SUSPENDED 유지) |
실측으로 드러난 결함 1건은 닫았다: AT-13(동시 수정 시 412) — D-049 에서 미충족으로 남겼던 것을 D-050 에서 고쳤다. 원인은 두 가지였다: ① ReviewRequest 에 버전이 없어 저장소가 비교할 대상 자체가 없었고, ② RevisionConflictError 가 ApiError 가 아니어서 라우터가 412 가 아니라 500 으로 옮겼다(모든 저장소의 충돌이 그랬다). 나머지: AT-12 의 연계 재시도 멱등은 배포·폐기 멱등으로 부분 커버.