본문으로 건너뛰기

ADR 0044 — 한 줄 본질 가시화 layer 정형화

Context

너홀로프로의 한 줄 본질: "법률 사무소가 자기 데이터로 자기 AI 를 학습·활용해, 소송을 더 빠르고 정확하게 관리" (CLAUDE.md SSoT). 모든 기능·결정의 우선순위는 이 한 줄에 기여하는가로 판정.

이 본질을 사용자/운영자에게 시각적으로 전달하는 layer 가 ADR 0043 v2.67 ~ v2.71 (5 PR) 동안 점진 추가됐다:

  • v2.67 dashboard "학습 회귀 통과율" stale indicator (마지막 갱신 시각 + 10분 amber)
  • v2.68 dashboard 14일 RAG history line chart (recall + precision + trend label)
  • v2.69 per-tenant chart (tenants/[tid] 새 "학습 회귀" tab) + hook SSoT 분리
  • v2.70 web 사용자 dashboard "사무소 AI 학습 효과" 카드 (chart 없는 trend 텍스트)
  • v2.71 anomaly hypothesis history toggle (latest 1 + previous 9)

이 5 PR 의 공통 패턴이 재사용 가능한 layer 디자인 임을 확인. 향후 한 줄 본질 직결되는 새 데이터 source (예: 변호사 finalize 후 학습 효과 측정, exemplar selection 적중률, refinementFeedback 누적) 가 추가될 때 동일 layer 패턴을 따라야 일관성 + 사용자 학습 비용 0.

본 ADR 은 그 5 단계를 정형화한 가이드라인 + 신설 본질 source 추가 시 invariant 강제.

Decision

1. layer 5단계 표준

본질 가시화가 필요한 새 데이터 source 는 다음 5 layer 중 source-audience 매트릭스에 따라 강제 layer 를 ship 해야 본 줄 본질에 정합.

v1.1 amendment (2026-05-11) — source 의 audience 별 강제/선택 layer 분리:

audience의미L1L2L3L4L5예시
사용자 가치사무소 owner/staff 가 본인 dashboard 에서 직접 가치 인지강제강제강제강제강제ragMergeQuality (학습 효과)
운영자 도구ops 콘솔 에서만 의미, 사용자 노출 안 됨강제강제강제skip OK강제anomalyHypotheses (가설 진단)
운영자 알림 (tenant-aware)tenant 별 분류 가능한 production 결함강제skip OK강제skip OK강제(예정)
운영자 알림 (global)tenant-agnostic 전역 결함 (v1.2 추가)강제skip OKskip OKskip OK강제active alerts (config/opsAnnouncements)

audience 분류 규칙:

  • 사용자가 메뉴에서 직접 클릭해서 보는 카드인가? → 사용자 가치
  • 운영자가 정확도/품질 trend 를 비교하는가? → 운영자 도구
  • production 사고 catch 가 본질이고 dashboard 보다 알림이 우선인가? → 운영자 알림

본질 source 신설 시 audience 분류 → 강제 layer 만 ship → invariant 추가. L4 강제가 적용되는 source 만 apps/web 변경 필요 (의존 규칙 비용 절감).

layer위치의도예시 (v2.67~v2.71)
L1 stale indicatorlatest 1 건 표시 옆 inline운영자가 데이터 신선도 즉시 인지 (10분 amber + pulse)dashboard 학습 회귀 axis (v2.67)
L2 시계열 chart14일 line/area chart"측정 시작 후 어떻게 변하고 있나?" 시각 답 (recharts ChartContainer + var(--chart-N) 색역)dashboard RagHistoryChart (v2.68)
L3 per-tenant viewtenants/[tid] 의 새 tab 또는 카드ops 가 사무소별 trend 비교 가능 (hook SSoT 분리, drift 0)tenants/[tid] "학습 회귀" tab (v2.69)
L4 사용자 가시 시그널apps/web dashboard "학습·리서치" 그룹사무소 owner/staff 본인이 자기 사무소 학습 trend 직접 확인DashboardLearningEffectCard (v2.70)
L5 latest + history토글로 expand운영자 cross-time 비교 (이번 vs 이전 N개)anomaly hypothesis history (v2.71)

2. 강제 invariant

각 layer 마다 정적 grep 회귀 가드 (apps/ops/__tests__/*-invariants.test.ts 또는 apps/web/__tests__/*-invariants.test.ts):

  • L1 stale: STALE_THRESHOLD_MS = 10 * 60 * 1000 + setInterval(..., 60 * 1000) + bg-amber-500 animate-pulse
  • L2 chart: ChartContainer + recharts LineChart 또는 AreaChart + Y 축 percent 또는 적절 unit + trend label (🟢/🔴/⚪ 또는 동등)
  • L3 per-tenant: hook 이 tenantId: string arg 받음 + tenants/${tenantId}/{collection} path 사용 (cross-tenant 격리)
  • L4 web 카드: useTenant().tenantId 로 자기 사무소 격리 + handleListenerError SSoT (ADR 0029 fail-loud 정합)
  • L5 history: latest 1 + previous N toggle + aria-expanded + 부트스트랩 모드 (data < 2) 비표시

3. 부트스트랩 모드 (필수)

production 데이터 0 건 시 모든 layer 가 noise 0 으로 silent (사용자에게 빈 카드/혼란 X). 데이터 N 건 누적 후 자동 노출:

  • L1 — lastFetchedAt === null 시 indicator 비표시
  • L2 — series.length < 2 시 chart 비표시
  • L3 — per-tenant 데이터 없으면 "측정 대기" 안내 표시
  • L4 — series.length < 2 시 카드 비표시
  • L5 — history.length < 2 시 toggle 비표시

4. SSoT 분리 강제

같은 hook/컴포넌트가 ops + web 또는 dashboard + per-tenant 양쪽에 쓰이면 _lib/{name}.ts 또는 _lib/use-{name}.ts SSoT 분리 (drift 0). 의존 규칙 위반 시만 복제.

예 (v2.69 패턴):

  • apps/ops/app/(ops)/dashboard/_lib/rag-merge-history.ts (pure data: 상수 + type)
  • apps/ops/app/(ops)/dashboard/_lib/use-rag-merge-history.ts (hook: useCollectionSnapshot SSoT)
  • apps/ops/app/(ops)/dashboard/_components/RagHistoryChart.tsx (UI 컴포넌트)
  • 호출자 (dashboard/page.tsx + tenants/[tid]/page.tsx) 모두 위 SSoT import

5. ADR 0029 fail-loud 정합

L1~L5 모든 hook 은 useCollectionSnapshot / useDocumentSnapshot SSoT 사용 (apps/ops/lib/realtime/use-firestore-snapshot.ts 또는 apps/web/lib/firebase/listener-error.ts). 자체 onSnapshot 직접 호출 + silent error handler 금지 (PR #1885 + Block 1 sweep + Block A sweep 정합).

Consequences

긍정

  • 사용자 학습 비용 0 — 새 본질 source 가 추가돼도 layer 패턴 동일이라 사용자가 새로 배울 게 없음
  • drift 0 — SSoT 분리 + invariant 정적 가드로 dashboard/tenants/web 간 표시 불일치 차단
  • 부트스트랩 noise 0 — production 데이터 0 건 시 빈 카드 보이지 않음 (메모리 feedback_no_pilot_mock_only 정합)
  • fail-loud 자동 정합 — useCollectionSnapshot SSoT 사용 강제로 silent swallow 회귀 방지

부정

  • 5 layer ship 의 PR 부담 — 새 본질 source 는 5 PR (≈10시간) 필요. trade-off: 일관성 vs 빠른 ship
  • chart 비용 — recharts 가 web/ops 양쪽에 있어 번들 크기 영향. 단 sparkline 같은 경량 형태로 mitigation 가능
  • ops + web 양쪽 변경 — 의존 규칙 (apps/* 간 import 금지) 으로 컴포넌트 복제 발생. SSoT 분리는 _lib 단위까지만 가능

회귀 가드 invariant 신설

  • apps/ops/__tests__/essence-layer-checklist-invariants.test.ts — 신규 본질 source 가 5 layer 모두 ship 했는지 정적 체크리스트 (L1~L5 패턴 grep)
  • apps/web/__tests__/essence-layer-web-invariants.test.ts — apps/web 측 L4 카드 패턴 (useTenant + handleListenerError + 부트스트랩 분기) 정적 검증

적용 사례 — 현 ship 본질 source

v1.1 amendment 정합 후 표 (audience 컬럼 추가):

sourceaudienceL1L2L3L4L5강제 layer 정합
ragMergeQuality사용자 가치v2.67 ✓v2.68 ✓ + v2.72 sparkline ✓v2.69 ✓v2.70 ✓ + v2.72 sparkline ✓v2.73 ✓100% (5/5)
anomalyHypotheses운영자 도구v2.74 ✓v2.75 ✓v2.74 ✓n/a (skip)v2.71 ✓100% (4/4)
active alerts운영자 알림 (global)v2.83 ✓n/an/an/av2.83 ✓100% (2/2)
draftDiffs (편집률)사용자 가치v2.76 ✓v2.76 ✓v2.77 ✓이미 ship (DashboardFirmLearningCard)v2.78 ✓100% (5/5)
docgenEvents (성공률)사용자 가치v2.79 ✓v2.80 ✓v2.80 ✓v2.81 ✓v2.80 ✓100% (5/5)
refinementFeedback (exemplar)사용자 가치v2.82 ✓v2.82 ✓v2.82 ✓v2.82 ✓v2.82 ✓100% (5/5)
draftDiffs.citation (AI 인용 보존율)사용자 가치cycle 7 ✓cycle 7 v2 ✓cycle 7 v3 ✓cycle 7 v3 ✓cycle 7 v2 ✓100% (5/5) — finalize-document-action 자동 캡처 + ops dashboard 5번째 axis + sparkline + L5 history list + 사용자 가시 DashboardCitationPreservationCard + per-tenant TenantHealthCard 통합.

v1.3 추가 (자율 세션 #9 cycle 7, 2026-05-12): 5번째 source draftDiffs.citation (AI 인용 보존율) — computeDraftCitationDiff pure function 으로 변호사의 AI 인용 채택 비율 측정. finalize-document-action 이 자동 캡처. 한 줄 본질 학습 루프 quality 의 새 차원 — RAG hallucination 자동 catch.

cycle 7 v2 (2026-05-12 후속): L2 sparkline + L5 history list ship — color: ratio < 0.3 rose / ratio < 0.7 amber / ratio ≥ 0.7 emerald (anomaly 후보 자동 시각화).

cycle 7 v3 (2026-05-12 후속): L3 + L4 ship — DashboardCitationPreservationCard (web 사용자 가시) + TenantHealthCard 통합 (ops per-tenant 분포). draftDiffs.citation 100% (5/5) 정합 달성 — 5번째 source 가 4 source 와 동등 layer 정형 보유.

적용 사례 — ragMergeQuality 100% 정합 (2026-05-11 v2.73): 5 layer 모두 ship 완료된 첫 source. dashboard latest + stale + 14일 chart + per-tenant + 사용자 가시 카드 + sparkline + history list 토글까지 누락 없음. 본 source 가 후속 source 의 layer 정형 모범.

v1.4 status (자율 세션 #9 cycle 14, 2026-05-12): 7 source 표 전체 정합 종합 — 7/7 source 100% layer 정형 달성. 한 줄 본질의 4 axis (편집률·docgen 성공률·exemplar selection·학습 회귀) + 5번째 axis (AI 인용 보존율) + 운영자 도구 (anomalyHypotheses) + 운영자 알림 (active alerts) 모두 ship.

다음 단계 후보:

  1. 6번째 axis 후보 — citation accuracy (인용 정확도, citation-existence verify 결합), draftDiffs heavy-edit 비율, 또는 portal 사용자 만족도 (의뢰인 측 axis)
  2. CI 통합 — adr-0044-source-hook-sync invariant 가 7 source 모두 정합 검증, 신규 source 추가 시 invariant 와 hook + dashboard 4곳 (L1·L2·L3·L4·L5) + CLAUDE.md ADR 동기화 강제
  3. 사용자 onboarding — 5 axis section header collapse panel (cycle 7 v3-2) 의 다국어화 또는 영구 표시 옵션

관련 ADR

  • ADR 0029 fail-loud 정책 (precondition)
  • ADR 0040 ops 재정의 (4 axis 이론)
  • ADR 0042 anomaly closed-loop (L5 패턴 source)
  • ADR 0043 v2.67~v2.71 (본 ADR 의 ship 사례)