15 KiB
HMDesign Guard 정확도 수정 결과 — 2026-10-10
RESULT: PARTIAL
TARGET: D:\디자인시스템\hmdesign
범위: Guard 검증 로직·테스트·설명 문서. Runtime: React/Vite. Production과 기존 Storybook Reference를 독립 검사한다. Component/Pattern/Theme/Token/D-01/D-02/대표 Story와 이전 퍼블리셔 통합 보고서는 수정하지 않았다. Git 명령을 실행하지 않았다.
Guard 문제 분석
| 항목 | 원인·판정·수정 |
|---|---|
| Dashboard Sidebar | 이전 Guard는 import graph의 모든 JSX를 실제 render처럼 취급했다. export entry의 DashboardScreen mode="compact" → compact=true → sidebar=undefined와, 사용되지 않는 Reference JSX initializer를 구분하지 못해 NAV-001 FAIL 및 NAV-005를 냈다. 직접 component 호출·기본/literal props·immutable local 값·반환 JSX/slot을 분석하여 현재 entry에서 배제되는 분기만 제외했다. 실제 Chrome DOM의 Sidebar는 0개다. |
| Storybook Scope | 기존 Guard는 Production 전용이므로 Story 변경의 SCOPE-001은 검사 범위 불일치였다. 독립 --profile STORYBOOK을 추가했다. 설정의 literal stories glob으로 63개 Story module을 발견하고, 각 Story graph에 공통 preview를 연결한다. 다른 lazy Story의 CSS를 연결 증거로 사용하지 않는다. |
| CSS Intent | 기존 REUSE-003은 위반 확정 FAIL이 아닌 검토용 NOT VERIFIED였다. Primary 80%·Secondary·Legacy·Dashboard Gradient를 바꿀 근거가 없다. 해당 판정을 유지하고, 누락됐던 내부 tabs-* slot도 검토 대상으로 포함했다. package 내부 Theme CSS는 기존 소비자 replica 검사에서 제외한다. |
| Navigation Policy | GNB_ONLY/DASHBOARD_ONLY의 Sidebar 금지와 혼합 Navigation 금지는 유지한다. LNB_ONLY 정상 사용도 유지한다. 실제 선택되는 Reference Sidebar branch는 FAIL, 동적 조건/spread/mutation/opaque callback은 가능한 위반을 NOT VERIFIED로 남긴다. 여러 호출 중 하나라도 확정 위반이면 FAIL이다. 공식 Sidebar를 component prop으로 전달해 렌더하는 경우도 탐지한다. |
| Production Graph | bootstrap import graph와 공개 package API 경계는 보존한다. Story/helper/reference 소비는 계속 FAIL이다. package Component/Pattern/Theme source는 소비 graph로 강제 포함하지 않는다. 직접 선택한 package CSS는 SCOPE-001 NOT VERIFIED이며 패키지 build/typecheck 및 별도 CSS/실제 렌더 확인으로 구분한다. |
실제 렌더·조건·Reference 구분
- 실제
<DashboardSidebar>또는 금지sidebarslot을 반환하는 literal 경로: FAIL. - 조건이 미확정인 Sidebar: NOT VERIFIED. PASS로 숨기지 않는다.
- 현재 compact literal props로 배제된 분기·반환되지 않는 Reference JSX 값: 현재 Navigation 위반에서만 제외한다. import/export/CSS 검사는 유지한다.
- Reference라는 주석·파일명·Sidebar 문자열만으로 Production 사용을 허용하지 않는다. 같은 보존 분기를 선택하면 FAIL이다.
- Storybook Reference의 Navigation API는 mode 미지정 시 NOT APPLICABLE이다. 명시 mode를 주면 기존 정적 금지 규칙을 검사한다. Story별 대표/verification 분류·모든 상태의 혼합 Navigation 의도를 자동 승인하지 않는다. 신규 업무 화면의 Story 등록 금지는 그대로다.
원인 분류
실제 위반: 이번 제공된 Production entry에서 확정한 신규 디자인 시스템 위반은 없다. 회귀 fixture의 실제 Sidebar·혼합 Navigation·비공개 import·위조 public slot·Production의 Story 의존은 FAIL을 유지한다.
오탐: Dashboard compact에서 mount되지 않는 legacy Sidebar branch의 NAV-001. 현재 mode로 빈 slot을 증명할 수 있는데 NAV-005를 내던 분석 한계. Story 변경의 SCOPE-001은 기존 전용 범위 불일치이며 독립 Storybook 검사로 해결했다.
검증 불가: CSS override의 승인/복제 의도, native control의 합법적 사용 의도, opaque/dynamic render flow, 독립 package source를 소비 Guard로 검사하는 범위, 전 Story/모든 browser/state의 runtime 회귀.
전체 Storybook의 src/patterns/gnb.stories.tsx:406은 공개 컴포넌트가 없는 내부 lnb-mobile-nav wrapper를 사용한다. 기존 GNB Composition 계약에도 있는 Reference이며 소비자 복제로 확정할 수 없다. Storybook에서만 이 종류를 REUSE-001 NOT VERIFIED로 분류한다. 같은 코드의 Production 사용은 FAIL이며, Storybook에서도 공개 component slot을 기본 HTML로 위조하면 FAIL이다. 파일별 허용 목록·무조건 PASS는 추가하지 않았다.
수정 파일
| 파일 | 변경 내용·이유 |
|---|---|
| Guard | 독립 Storybook profile/preview 연결·진단 범위, Navigation 분석 연결, 내부 Reference wrapper의 검토 판정, tabs slot intent 인식, 검사 파일 목록. Production 규칙을 삭제하지 않고 근거의 확실성을 구분한다. |
| Navigation 분석기 (신규) | 소비 코드를 실행하지 않는 제한된 render-value 분석. immutable literal props/locals만 absent를 증명한다. 미지원 흐름·callback·spread·mutation·alias·비원시 identity에는 불확실성을 유지한다. |
| 회귀 테스트 | 기존 14개 본문을 그대로 보존하고 22개 test를 추가한다. |
| Guard 정책 문서 | 두 profile과 Component/Pattern 경계, 조건부 Navigation, Reference wrapper, CSS intent/utility 제한, exit 0 ≠ PASS 설명. |
| 이 보고서 (신규) | 분석·명령·결과·보존·미검증 근거 기록. 이전 보고서를 덮어쓰지 않는다. |
추가 테스트
- 기존 테스트: 14개, 기존 본문 byte 내용(개행 정규화 대조) 유지, 14/14 PASS.
- 신규 테스트: 22개. compact/default/literal/alias/barrel props, 실제 Reference 선택, 미확정 조건, 다중 호출, literal ternary/logical, spread·mutation·callback·destructuring·객체 alias, 혼합 Navigation 및 PARTIAL, Storybook discovery·공개 export·CSS entry·lazy CSS 격리, Reference wrapper, 정상 Gradient 파싱, malformed CSS·위조 slot, raw CSS import, package scope, component prop Sidebar 전달을 포함한다.
- 전체 테스트: 36/36 PASS.
- 실패 테스트: 0. 개발 중 테스트가 드러낸 누락은 최종 코드에서 수정했다. 성공한 최종 검증은 추가 변경이 없으면 반복하지 않았다.
최종 검증
| 항목 | 결과·실제 실행 근거 |
|---|---|
| GUARD_TEST | PASS — node --test scripts/ai-generation-guard.test.mjs, 36/36. |
| GUARD_FULL_SCREEN | NOT VERIFIED — 운영 GNB_ONLY, Dashboard/Recruit DASHBOARD_ONLY 모두 FAIL 0. 각 Navigation·Production 격리·CSS entry·공개 import 그룹은 PASS. 각 11건의 잔여는 REUSE-003 10건 + RENDER-002 1건이다. |
| GUARD_PARTIAL | NOT VERIFIED — 운영 CSS와 Dashboard composition 각각 RENDER-002 1건. Publisher 두 Story는 독립 profile에서 PASS. package Tabs CSS는 SCOPE-001 1건으로 독립 소비 검사가 아님을 명시한다. |
| GUARD_STORYBOOK | NOT VERIFIED — 전체 63개 Story module의 graph 검사, FAIL 0. 공개 import·격리 profile·CSS entry 그룹 PASS, Navigation NOT APPLICABLE. 내부 Reference wrapper 1건, CSS intent 16건, native control 19건을 유지한다. Publisher 두 Story PARTIAL은 PASS. |
| TYPECHECK | PASS — npm run typecheck, 사전 Theme/package 검사 및 루트·workspace TypeScript 검사 exit 0. |
| UI_BUILD | PASS — 위 pretypecheck의 npm run build:packages가 UI/Center Graphic build를 수행했다. 동일 package build를 다시 실행하지 않았다. |
| PRODUCTION_BUILD | PASS — npm run build --ignore-scripts; Dashboard 기존 Vite config build + node scripts/finalize-dashboard-export.mjs; Recruit 기존 Vite config build. 모두 exit 0. 이미 끝난 사전 package/Theme 검사는 중복하지 않았다. |
| STORYBOOK_BUILD | PASS — npm run build-storybook --ignore-scripts, exit 0, 291개 Story ID 산출물. |
| TEST | NOT VERIFIED — 일반 test script/Component unit runner가 없다. 지원되는 Guard suite는 GUARD_TEST에 별도로 기록한다. |
| CSS_IMPORTS | PASS — source CSS 78개·import 63건, 미해결 0. index.css → tailwind.css, 공개 UI Tailwind/Theme/status entry, compiled UI @source "./index.js" 존재, flex/grid/min-w-0/px-0/py-6 생성 및 관련 React 계산값 확인. |
| EXPORTS | PASS — runtime 공개 import 688건, 누락 0; 공개 export 산출물 16개 모두 존재. source barrel/API는 미변경. |
지원되지 않는 전용 Component/Pattern Guard profile, 전체 Story별 runtime/state/포인터 검사와 과거 pixel diff는 NOT VERIFIED다. 존재하지 않는 명령을 통과로 기록하지 않는다. 기존 Tailwind bg-[var(...)] 최적화 경고와 production 500kB 초과 chunk 경고는 그대로이며 build 실패가 아니다.
실제 Guard 명령
node scripts/ai-generation-guard.mjs --target . --scope FULL_SCREEN --mode GNB_ONLY --result index.html --json
node scripts/ai-generation-guard.mjs --target . --scope FULL_SCREEN --mode DASHBOARD_ONLY --result src/exports/dashboard/index.html --json
node scripts/ai-generation-guard.mjs --target . --scope FULL_SCREEN --mode DASHBOARD_ONLY --result src/exports/recruit/index.html --json
node scripts/ai-generation-guard.mjs --target . --scope PARTIAL --mode GNB_ONLY --files src/index.css,tailwind.css --result index.html --json
node scripts/ai-generation-guard.mjs --target . --scope PARTIAL --mode DASHBOARD_ONLY --files src/patterns/dashboard-composition.tsx --result src/exports/dashboard/index.html --json
node scripts/ai-generation-guard.mjs --target . --profile STORYBOOK --scope FULL_SCREEN --json
node scripts/ai-generation-guard.mjs --target . --profile STORYBOOK --scope PARTIAL --files src/components/tabs.stories.tsx,src/patterns/page-header.stories.tsx --json
node scripts/ai-generation-guard.mjs --target . --scope PARTIAL --files packages/ui/src/theme/tabs.css --json
실제 React 확인
로컬 Chrome에서 실제 build 산출물을 확인했다. Dashboard/Tabs/PageHeader의 대표 확인 범위이며 전체 291개 Story를 다시 렌더했다는 주장이 아니다.
- Dashboard: Sidebar 0개, Header 48px, layout min-width 960px, body flex. Token 기반 20/50/80% gradient 유지. 완료 필터 클릭으로
완료 업무 12건과 선택 상태·Table 갱신 확인. 390px에서 document 390px, frame client 390/scroll 960, overflow-x auto. Console error/warn 0. - Tabs 1280/390px: Primary
color(srgb 1 1 1 / 0.8) → rgb(245,240,229), opacity 1. Secondary White→White. Fill active panel 7개 모두 24px 0 / transparent / border 0 / radius 0. Card 탭 전환 후 입력 초안 보존. document width 1265/375px(세로 scrollbar 제외), 가로 넘침 없음. Console error/warn 0. - Legacy Compatibility: 기존 non-fill 2개가 gradient none / White / panel border 1px / padding 16px. surface-only Secondary Fill은 평면 패널 유지.
- PageHeader 1280/390px: 설명 margin-top 8px, Header margin-bottom 20px, panel 24px 0, Primary alpha .8.
완료 업무클릭 시 완료 Table로 전환, 문서 폭 1280/390px. - 브라우저 임시 viewport를 복원하고 검증 탭과 loopback 서버를 종료했다. source 화면/API를 바꾸지 않았다.
보존 확인
| 항목 | 결과 |
|---|---|
| D-01/D-02 | PASS — Tabs CSS/Story·PageHeader Story source hash 동일. 공식 Tabs source/dist CSS 동일. 실제 위 패널·Gradient·Legacy 렌더 보존. |
| Component/API | PASS — 기존 Component/Pattern TSX·공개 barrel·package.json·lockfile hash 동일. |
| Theme/Token | PASS — Theme JSON/계약/CSS source hash 동일, 기존 check:theme-defaults의 71색/73 defaults 일치. |
| Storybook ID | PASS — Story source/export 미변경, 291개 현재 ID 산출물 및 기존 inventory 288개 ID 모두 보존. |
| 참고 원본 | PASS — 3개 파일 SHA-256 동일, 읽기 전용 유지. |
| 기존 파일 | PASS — 시작 source 504개 중 Guard·테스트·Guard 문서 3개만 변경, 나머지 501개 동일. 분석기·이 보고서는 신규다. 이전 통합 보고서/기존 작업을 보존했다. |
파일 목록·SHA-256·수정 전 사본은 _local/guard-accuracy-2026-10-10/: _local/guard-accuracy-2026-10-10/ (당시 로컬 보관 증거, Git Clone 미포함)에 보존했다. node_modules·빌드 산출물·tsbuildinfo·기존 _local·Git metadata는 source baseline에서 제외했다. 빌드 산출물은 지원되는 기존 명령으로 재생성했고 source 보존과 구분한다. 해당 경로의 baseline.json, reference-baseline.json, before/, tests-final.log, guard-summary.json, guard-*.json, 각 build log, static-audit.json, browser-evidence.json, preservation-final.json이 이번 증거다. 이전 _local/publisher-* 로그/사본은 덮어쓰지 않았다.
남은 문제
- REUSE-003/004와 내부 Reference wrapper는 의도를 정적 코드만으로 확정할 수 없다. 실제 fixture·문서·사용 화면별 검토가 필요하다. 전체 Guard PASS로 표기하지 않았다.
- RENDER-002는 tool의 브라우저 확인 요구를 나타낸다. 이번 대표 실제 렌더 증거와 원본 JSON 상태를 따로 기록한다. 브라우저 증거를 근거로 JSON을 임의 PASS로 덮어쓰지 않는다.
- package source의 독립 Guard 범위는 지원하지 않는다. 패키지 typecheck/build/CSS declaration/hash/관련 렌더 검증은 별도 수행했다.
- 일반 Component unit runner, 전 Story/Props/브라우저/state 회귀, 외부 소비 앱·배포·역사적 pixel diff는 NOT VERIFIED.
.git이 없는 폴더다. Git status/diff/HEAD 및 미커밋 구분은 NOT VERIFIED이며 파일 baseline으로 기존 작업을 보존했다.
Git
Git Init: NOT EXECUTED
Git Clone: NOT EXECUTED
Local Commit: NOT EXECUTED
Remote Push: NOT EXECUTED
Git commands / remote changes: NOT EXECUTED
최종 판단
- 기존 Dashboard Guard FAIL은 해결했다. 금지 Sidebar를 실제 선택하는 fixture는 계속 FAIL이다.
- 실제 위반 탐지 능력은 기존 14개+신규 22개로 검증했다. 미확정 경로를 PASS로 숨기지 않는다.
- 정상 D-01/D-02·Component/Pattern/Theme/Storybook source를 수정하지 않았고 지원되는 build/typecheck 및 대표 실제 렌더에서 회귀를 발견하지 않았다. 전수 runtime 회귀는 NOT VERIFIED다.
- 로컬 Git 커밋은 보류한다. Git metadata 부재와 잔여 NOT VERIFIED 검토를 다음 단계에서 별도로 판단해야 한다. 이번에는 Git 작업을 수행하지 않았다.
작업 시간 (Asia/Seoul)
- Started At: 2026-10-10 00:14:14 KST
- Completed At: 2026-10-10 00:48:42 KST
- Actual Duration: 34분 28초
- Estimated Duration: 45–65분
- Variance: 예상보다 10분 32초–30분 32초 단축