engines.mappers Engines observed

Mappers (계정 정규화)

Mappers 는 DART/EDGAR 원문 계정명을 공통 snake_id 로 정규화하는 *내부 모듈* 이다. 사용자 직접 호출 기능 가 아니라, Company.panel / scan 결과 안에서 자동 적용. 본 skill 은 매핑 규칙을 *AI 가 컬럼 정규화에 활용* 할 때 참조한다. 트리거 — '항목 매핑', '컬럼 정규화', 'snake_id 변환'.

이 스킬

Mappers (계정 정규화)

Mappers 는 DART/EDGAR 원문 계정명을 공통 snake_id 로 정규화하는 *내부 모듈* 이다. 사용자 직접 호출 기능 가 아니라, Company.panel / scan 결과 안에서 자동 적용. 본 skill 은 매핑 규칙을 *AI 가 컬럼 정규화에 활용* 할 때 참조한다. 트리거 — '항목 매핑', '컬럼 정규화', 'snake_id 변환'.

Engines observed engines.mappers

이어 가기

절차

실행 순서

  1. 1

    RunPython prelude 의 `normalizeColumn(topic, hint)` 사용 — 한글/snake/alias → 표준 snake_id.

  2. 2

    가능 컬럼 목록은 `columnsFor(topic)` — snake_id · label · aliases.

  3. 3

    topic 자체는 `availableTopics()` (BS/IS/CF/CIS/SCE).

  4. 4

    매핑 정의는 `src/dartlab/reference/data/accountMappings.json` 단일 SSOT (DART mappings/layers + EDGAR edgar 구획 통합).

  5. 5

    신규 매핑 추가는 운영자 트리거 발화 ("매퍼 정리"/"mapping refresh") → `src/dartlab/skills/specs/operation/mappingRefresh.md` 4 단계 — 관측 ledger → `src/dartlab/reference/mapping/mappingLedgerCompact.py` → `src/dartlab/reference/mapping/mappingReview.py` confirm/reject/alias/defer → `src/dartlab/reference/mapping/mappingPromote.py` apply.

  6. 6

    prod JSON 단독 권한 진입점은 `src/dartlab/reference/mapping/mappingPromote.py` 만. atomic write + `_metadata.{lastUpdate,addedCount,promoteCommit}` 갱신 + `AccountMapper.release()` 자동 호출.

예시

이런 질문이 들어오면 이 skill 을 쓴다

  • 총자산 → total_assets 정규화
  • 당기순이익 (topic=IS) → net_income
  • normalizeColumn 으로 RunPython 안에서 동적 정규화
  • 새 사업보고서 항목 매핑 추가

출력

기대 결과

  • 정규화된 snake_id
  • 매핑 신뢰도 (정확/부분/실패)

엔진 역할

mappers 는 사용자 capability 가 아니라 내부 모듈 이다. DART 사업보고서·재무제표·주석의 한글 계정명을 dartlab 공통 snake_id 로 정규화한다. EDGAR 측은 SEC GAAP 태그 → 같은 snake_id (양쪽 SSOT 동등).

AI 가 직접 쓸 자리는 RunPython 안의 prelude 헬퍼 — normalizeColumn(topic, hint), columnsFor(topic), availableTopics(). 매핑 자체 편집은 운영자 절차 (src/dartlab/mappers/{@html String.fromCharCode(123)}topic{@html String.fromCharCode(125)}.json 직접 수정).

공개 호출 방식

# RunPython 안에서 — prelude 자동 노출
import dartlab
c = dartlab.Company("005930")
bs = c.panel("BS", freq="Q")

# 한글 → snake_id 정규화 (추측 금지)
col = normalizeColumn("BS", "총자산")        # → "total_assets"
col2 = normalizeColumn("IS", "영업")          # → "operating_profit"

# 가능 컬럼 목록 (snake_id · label · aliases)
cols = columnsFor("BS")
print(cols)

# 가능 topic
print(availableTopics())   # BS / IS / CF / CIS / SCE

강행 호출 룰 (agent 답변 품질 회귀 차단)

mappers 는 내부 정규화 모듈 — Company.panel / scan 결과 안에서 자동 적용. 다음 3 룰 강행:

  1. mappers 단독 EngineCall 금지EngineCall(apiRef="mappers") 호출 없음. Company.panel / scan 결과의 snake_id 컬럼은 이미 정규화 완료.
  2. snake_id 임의 추측 금지normalizeColumn(topic, hint) 또는 columnsFor(topic) RunPython 안에서 호출해 정확 매칭 후 사용. “total_equity” 같은 추측 키로 dict 접근 시 KeyError (P5 RunPython 회귀 사례).
  3. -표준계정코드 미사용-|... fallback 데이터는 표준화 후보로 표기 — Company.panel 결과 dict 의 nonstd_ 컬럼은 매핑 미완. 답변 본문에 “표준화 미완 N 건” 명시 + 임의 합산 금지.

호출 동작

normalizeColumn(topic, hint)topic 안에서 hint 와 매칭되는 표준 snake_id 반환. 매칭 실패 시 None (또는 ValueError, 구현 따라). 한글 풀네임 · 부분 키워드 · snake_id 자기 자신 모두 받음.

columnsFor(topic) — 해당 topic 의 모든 표준 컬럼 list. 각 항목은 snake_id · label (한글) · aliases (한글/영문 변형) · category · type.

매핑 데이터는 src/dartlab/mappers/{@html String.fromCharCode(123)}topic{@html String.fromCharCode(125)}.json_metadata.description + key:value (한글 → 영문 canonical) + category/type 분류.

6 매퍼 (topic 별)

topic파일책임
BSbs.json재무상태표 — 자산·부채·자본 계정
ISis.json손익계산서 — 매출·비용·이익 계정
CFcf.json현금흐름표 — 영업·투자·재무 활동
CIScis.json포괄손익계산서 — OCI 항목
SCEsce.json자본변동표 — 자본 구성 변동
ratiosratios.json재무비율 — ROE · 부채비율 등 파생

공통 유틸 (mappers/common.py) 가 모든 파서·매퍼에서 공유. 한자/영문/공백/괄호 변형 정규화.

대표 반환 형태

normalizeColumn("BS", "총자산")
→ "total_assets"  (str)

columnsFor("BS")
→ list[dict]
   snake_id : str
   label : str         # 한글 표시명
   aliases : list[str] # 변형 ("총 자산", "자산총계", "Total Assets")
   category : str      # "asset" / "liability" / "equity"
   type : str          # "current" / "non-current" / "total"

evidence 기준

매핑 결과는 topic · rawName · snakeId · confidence · source (DART/EDGAR) 를 남긴다. confidence 낮으면 답변에 명시.

기본 검증

매핑 정의 변경은 본 skill 의 6 매퍼 표 동시 갱신. 신규 매핑 추가 시 category · type 메타 함께 — AI 가 새 항목을 자동 분류하는 학습 데이터로 작동.

학습 파이프라인 (반자동 사이클)

저장 위치 (SSOT 인덱스)

자산경로내용갱신 방식
계정 매핑 SSOT (DART+EDGAR)src/dartlab/reference/data/accountMappings.jsonstandardAccounts + mappings + layers(5) + edgarmappingPromote.py --layer 또는 직접 편집 + release()
단일 소유 엔진src/dartlab/core/accounts/data·normalize·edgar·labels·aliases (L0)
Notes 구조 학습src/dartlab/reference/data/notesStructure.json2,700 종목 notes 항목 {@html String.fromCharCode(123)}type, category, frequency{@html String.fromCharCode(125)}scanAll() 자동 갱신
로더src/dartlab/core/accounts/data.py::loadAccounts (옛 labels._loadAccountMappings 위임)SSOT 단일 로더 (lru_cache)
캐시 무효화src/dartlab/core/accounts/data.py::release (옛 AccountMapper.release 위임)JSON 직접 편집 후 호출

2026-06 통합: DART·EDGAR 매핑이 단일 파일 accountMappings.json + 단일 소유 엔진 core/accounts/ 로 통합 (옛 EDGAR 별도 mapperData/ 흡수, 5 in-code dict 흡수). 옛 mapper.py·labels.py 는 위임 facade. 구조·관리 정본은 operation.mappingRefresh §0.

사이클 4 단계 — 운영자 트리거 발동 (cron 없음, 직접 박는 정공)

본 절차의 핵심: mapper 의 34,000+ 매핑은 모두 운영자가 미커버 한글명을 보고 직접 standardAccounts.snakeId 와 짝지어 박은 결과. 자동 학습 X. 파이프라인은 그 수동 박기를 효율화하는 도구이며 최종 매핑 결정은 사람.

1. polars lazy + anti-join 전수 미커버 추출 (Bash inline, ~2.5 초)
   pl.scan_parquet('data/dart/finance/*.parquet').filter(...)
     .with_columns(nm_n=norm(account_nm), id_n=stripPrefix(account_id))
     .join(mappingsKeys, on='account_id', how='anti')
     .join(mappingsKeys, on='id_n',       how='anti')
     .join(mappingsKeys, on='account_nm', how='anti')
     .join(mappingsKeys, on='nm_n',       how='anti')
     .group_by(['account_id','account_nm','sj_div']).agg(occ, stockCodes)
   → 미커버 그룹 ≈ 33k (false-positive 약 33% 포함)

2. mapper.map() Python 더블체크 (~0.2 초)
   AccountMapper.get().map(accountId, accountNm) 12 단계 fallback 호출
   (사전 hit 우선 → synonym 정규화 → 공백/괄호/하이픈 역인덱스 → 액 suffix).
   None 반환 행만 진짜 미커버 — anti-join 으로 못 잡은 synonym/정규화 단계
   false-positive 제거.
   → 진짜 미커버 ≈ 22k.
   sj_div 분포: SCE 4,107 (별도 buildSceMatrix 흐름이라 무시),
                BS/IS/CF/CIS 18,000+ 그룹.

3. SA korName substring 매칭 후보 추출
   강한 후보 filter (occ ≥ 5, disp ≥ 3) ≈ 1.8k.
   각 후보의 account_nm 정규화 → standardAccounts.korName 정규화와
   양방향 substring + 길이 비율 score 계산. score ≥ 0.70 후보 top 1 추출.

4. 운영자 박기 — 액션 단어 보존 검토 후 batch JSON patch
   stdout 후보 list 사람이 한 줄씩 검토:
     OK 패턴 — prefix (유동·장기·외화), 숫자 (1./V.), suffix (조정·등·순액),
               오타 (지배지업 ← 지배기업), 잘림 (당기손익측정금융자)
     SKIP 패턴 — 액션 빠진 환각 (자산 처분손실 → 자산 자체),
                의미 반대 (장기사채 → 단기사채)
   확정 매핑을 accountMappings.json::mappings 에 batch 추가 (atomic write,
   single-line 보존 separators=(',', ':')). _metadata.addedCount 누적.
   AccountMapper.release() + lru_cache.cache_clear() 호출.

운영자 트리거 발화 (“매퍼 정리해줘” / “nonstd 정리” / “mapping refresh”) 시 운영 SSOT src/dartlab/skills/specs/operation/mappingRefresh.md 절차서가 4 단계 inline Bash 실행. 각 단계 사이 운영자 결정 필수 — 어떤 자동화도 prod JSON 을 직접 수정하지 않는다. cycle 당 30~80 매핑 추가, 추가율은 cycle 마다 둔화 (신중도 증가). 본 사이클 138 매핑 박은 결과 카카오 035720 nonstd 행 66 → 28 (58% 감소).

안전 자동학습의 정의 (5 신호)

“자동 적용 가능” 의 객관 기준은 mapping_signals.evaluate 의 5 신호 모두 통과 (autoEligible: true):

신호기준거부 시그널
S1 빈도occurrenceCount ≥ 5< 5 = singleton 노이즈
S2 회사 분산고유 stockCode ≥ 31 사 전용 = 사내 계정
S3 한글 정규화 매칭standardAccounts.korName Levenshtein 유사도 ≥ 0.85< 0.85 = 의미 모호
S4 IFRS 동의어 1 hopaccountId/accountNm 정규화 후 mappings 직 hit1 hop 안에 없음
S5 오타 거부jamo 분해 → 1 자모 차이 IFRS korName 존재 시 거부오타 의심 = false + suggestedFix 노출

autoEligible=True자동 반영 이 아니다 — 운영자 mappingReview.py confirmmappingPromote.py apply 까지 사람 결정 2 번 필요.

사용자 호출 (학습은 내부, 호출은 prelude)

학습 결과 활용은 위 “공개 호출 방식” 의 normalizeColumn(topic, hint) / columnsFor(topic) — RunPython prelude 자동 노출. 직접 JSON 편집은 운영자 절차.

검증

from dartlab.reference.mappers.accountMapper import AccountMapper
mapper = AccountMapper()
print(mapper.stats())  # MapperStats(name='account', totalEntries=34249, coverage=1.0, lastUpdated='2026-03-09')
print(mapper.lookup("매출액"))  # {'snakeId': 'sales', ...}
# 본 lookup() 은 본진 providers/dart/finance/mapper.py::AccountMapper.map() 위임 —
# 12 단계 fallback (사전 hit 우선 + synonym + 변형 흡수) 일관 적용. SSOT 단일화.

런타임

실행 환경별 호환성

환경상태비고 / 제한
Local Python supported·
Server supported·
MCP supported·
Web AI supported·
Pyodide limited·

실패 회피

흔한 실패 · 절대 금지

흔한 실패
  • snake_id 추측 (반드시 `normalizeColumn(topic, hint)` 또는 `columnsFor(topic)` 결과 인용)
  • topic 누락 — 같은 한글 이름이 BS/IS/CF 에 다 있을 수 있음 ("당기순이익" 등)
  • rawName 의 한자/영문 변형 (`(주)` · `(연결)` · ` ` 공백) 미정규화
절대 금지
  • 매핑 결과 없이 한글 계정명을 직접 컬럼명으로 사용 금지.
  • 매핑 신뢰도 낮을 때 (`confidence < 0.8`) 답변에 그대로 쓰지 않는다.