넥스트증권
경력근거: 표준화된 모델링을 바탕으로 분석뿐 아니라 서비스에서도 쓸 수 있는 Databricks 기반 마트 변환 파이프라인을 운영합니다.
※ 실제 산출물이 아닌 AI 예측 시안입니다.
'금융 데이터 분석가가 정의한 의미·산출 기준' 이 이 자리가 세울 금융 투자정보 의미 계층의 출발점입니다. 그 위에서 '갱신 주기(SLA)·정확도 기준을 정의하고' 공통 품질 게이트에 적용하며, 'DQ / SLA / Compliance 기준을 마트 단위로 관리' 합니다. 공고는 마트가 '분석뿐 아니라 서비스에서도 쓸 수 있는' 것이어야 하고, 메타·문서화는 '사람이 읽고 LLM이 이해할 수준' 이어야 한다고 적습니다. AI 가 투자정보 마트 값을 받아 대본을 쓰는 숏폼은 그 값을 그대로 투자자에게 내보내는 서비스 쪽 소비처라, 지표 이름이 의미 계층에 있는지, 마트가 SLA 안에 갱신됐는지, 대본 값이 분석가가 정한 소수 자리와 단위로 마트와 같은지가 모두 위 기준에서 나옵니다. 공고 끝에는 이 포지션이 '콘텐츠 관련 자회사 조직으로의 전보 또는 소속 변경이 검토될 수 있습니다' 라는 안내도 있어, 투자정보 데이터가 콘텐츠로 나가는 자리를 주제로 골랐습니다. 이 포트폴리오는 의미 계층과 기준일마다 쌓는 마트 이력을 dbt 모델로 설계하고, SLA·기준일·반올림 규칙을 검수 화면까지 잇는 구현을 보여줍니다. 증권 투자지표 산출이나 금융 콘텐츠 심의의 전문성은 주장하지 않습니다.
첫 주요업무가 금융 투자정보·계정계·거래 같은 도메인의 Semantic Layer 구축이고, 금융 투자정보는 금융 데이터 분석가가 정한 의미·산출 기준을 참조해 모델링한다고 적혀 있습니다. 이 화면은 숏폼이 붙인 지표 이름을 그 의미 계층의 지표명·별칭에 대어, 정의가 있는 수치인지부터 판단합니다.
공고는 처리 로직·품질 규칙·갱신 주기(SLA)·정확도 기준을 정의해 시스템화하고, DQ / SLA / Compliance 기준을 마트 단위로 관리하는 일을 맡깁니다. 다섯 판정 가운데 셋이 이 기준에서 나옵니다. 마트 갱신이 SLA 안에 들어왔는지, 생성 시각에 더 새 기준일이 있었는지, 분석가가 정한 소수 자리로 반올림한 마트 값이 대본과 같은지입니다.
공고는 분석뿐 아니라 서비스에서도 쓸 수 있는 Databricks 기반 마트 변환 파이프라인 운영과, 표준 마트와 소비 마트를 나눈 모델링을 요구합니다. 우대사항에는 Delta Lake·Unity Catalog·Jobs·Databricks SQL 운영 경험이 있습니다. 이 편은 숏폼 대본을 마트 값의 서비스 쪽 소비처로 보고, 기준일마다 쌓는 소비 마트에서 생성 시각의 상태를 dbt 모델로 다시 세워 Databricks SQL 로 화면에 올립니다.
넥스트증권이 개인투자자용 MTS 에 AI 투자 숏폼을 올린다고 가정한 관리자 페이지입니다. T&S(신뢰·안전) 담당자는 장 마감 뒤 생성분을 게시하기 전에 열고, 금융 데이터 분석가는 의미 계층에 없는 지표 이름이 쌓였을 때 엽니다. 숏폼 생성기가 대본에 쓴 수치마다 남긴 지표 이름·값·단위·기준일을 투자정보 의미 계층(Semantic Layer)의 지표 정의와, Databricks 투자정보 마트가 생성 시각에 갖고 있던 줄에 대어 다섯 판정 가운데 하나를 냅니다. 판정마다 그때 마트의 최신 기준일, 마지막 갱신에서 생성까지 지난 분, 분석가가 정한 소수 자리로 반올림한 마트 값이 근거로 나옵니다. 의미 계층에 없는 지표 이름에는 Claude Haiku 가 기존 지표 가운데 별칭 후보를 하나 고르거나 비워 둡니다.
넥스트증권 차세대 MTS 에 올라갈 AI 투자 숏폼을 게시 전에 검수하는 T&S·콘텐츠 검수 담당자와, 투자정보의 의미·산출 기준을 정한 금융 데이터 분석가. 장 마감 뒤 자동 생성된 숏폼이 수백 편이라 대본 속 수치를 한 편씩 마트와 대조할 수 없다. 관리자 페이지에서 어긋난 숏폼만 보고 보류·재생성을 정하고, 정의 없는 지표가 되풀이되면 의미 계층에 넣을지 함께 정한다
대본에 적힌 '5거래일 연속 순매수' 는 그 기준일에는 맞는 말일 수 있습니다. 숏폼을 만든 순간 마트에 더 새 기준일이 있었는지, 마트가 제때 갱신되지 않아 지난 값을 읽은 것인지, 분석가가 정한 소수 자리와 단위로 같은 값인지가 갈려야 판정이 섭니다. 규칙이 없으면 검수 담당자는 종목·지표마다 마트를 조회해 기준일과 값을 눈으로 맞추고, 분석가는 정의에 없는 지표 이름을 따로 모아야 합니다. 마트 이력을 생성 시각 기준으로 다시 세워 SLA·기준일·반올림 값을 정해진 순서로 견주면, 담당자는 걸린 수치가 든 숏폼만 열고 그 사유가 대본 쪽인지 마트 쪽인지를 판정 이름에서 바로 읽습니다.
T&S 담당자가 관리자 페이지에서 10월 14일 생성분을 열면 숏폼 9편의 인용 수치 12개가 다섯 판정으로 나뉩니다. 수치를 펼치면 왼쪽에 대본 문장과 지표 이름·값·단위·기준일이, 오른쪽에 의미 계층에서 정해진 지표의 단위·소수 자리·SLA 와 같은 종목·지표의 마트 줄이 갱신 시각 순서로 나오고, 생성 시각 뒤에 들어온 줄은 흐리게 보입니다. 의미 계층에 없는 이름에는 Claude Haiku 가 고른 별칭 후보가 붙습니다. 담당자는 숏폼마다 게시·보류·재생성 요청을 골라 CSV 로 내려받습니다. 세 표는 Databricks Free Edition 의 Delta 테이블에 더미로 올리고, 판정은 dbt 모델이 냅니다.
작성자가 판정을 직접 매긴 인용 수치 60개를 정답 세트로 두고, 정답과 다른 수치에는 이름 맞추기·시점 조인·SLA·기준일·반올림·단위 가운데 원인 단계를 붙여 모읍니다. 금융 데이터 분석가는 '정의 없는 지표' 탭에서 되풀이되는 이름과 별칭 후보를 보고 별칭이나 새 지표로 넣고, 넣은 이름은 다음 판정부터 마트 값과 견줍니다.
KRX 정보데이터시스템에서 내려받은 투자자별 거래·공매도 잔고·시가총액 CSV 로 표준 마트를 만들고, invest_mart 를 그 위의 소비 마트로 다시 세웁니다. 데이터 담당자가 '마트 갱신 이력' 탭을 열면 지표마다 지난 4주 동안 SLA 를 넘긴 날과 그날 걸린 숏폼 수가 나오고, 판정 화면의 마트 값이 어느 표준 마트에서 왔는지 Unity Catalog 리니지로 따라갑니다.
T&S 담당자가 10월 14일 생성분을 열면 숏폼 9편의 인용 수치 12개가 다섯 판정으로 나뉘고 걸린 숏폼 7편만 남습니다. SF-1014-0455-1 을 펼치면 공매도 잔고 비중의 마지막 갱신이 10월 12일 18:05 이고 생성까지 2,797분이 지나 SLA 1,440분을 넘긴 근거가 나옵니다.
마지막 갱신에서 정확히 1,440분이 지난 시가총액, 생성 뒤 17:40 에 들어온 기준일 줄, 1.315 처럼 반올림할 자리 다음 숫자가 5 인 PBR, 순매도라 음수인 외국인 순매수 금액, 산출하지 않아 값이 비어 있는 선행 PER, '시가 총액'·'공매도 잔고(비중)'·'선행PER' 처럼 띄어쓰기·괄호가 다른 지표 이름을 섞어도 판정이 판정식대로 나옵니다. Claude Haiku 가 metric_name 목록에 없는 별칭 후보를 내면 그 후보는 화면에 나오지 않습니다.
날짜 없이 '16:42' 만 든 generated_at, '2,140억' 처럼 글자로 들어온 claim_value, '10/14' 꼴 base_date, '9.1배' 처럼 글자로 들어온 마트 value, 생성 시각 전에 들어온 마트 줄이 하나도 없는 종목·지표, 이 깨진 입력 5종을 섞어 올리면 판정하지 못한 수치가 든 숏폼은 게시를 고를 수 없는 보류 상태로 시작하고, 그 수치 번호와 깨진 이유가 숏폼 줄에 붙습니다.
작성자가 판정을 손으로 매긴 인용 수치 60개로 화면 판정이 정답과 맞은 개수를 셉니다. 단, 대본 수치·마트·정답을 모두 작성자가 만든 합성 기준이라 성능 검증이 아니라 데모 조건에서의 동작입니다.
위 수치는 작성자가 만든 대본 수치와 마트 이력의 자가채점이며, 판정이 실제로 맞는 비율은 넥스트증권 투자정보 마트의 실제 갱신 이력과 숏폼 생성기가 실제로 남기는 인용 수치, T&S 담당자의 확인이 있어야 잽니다. 이 포트폴리오는 그 측정을 바로 돌릴 수 있는 상태까지 만듭니다.
더미는 대본 수치·의미 계층 정의·마트 이력 셋인데, 3주차에 KRX 공개 CSV 로 바뀌는 것은 마트 이력뿐이고 숏폼 생성기가 남기는 인용 수치와 분석가의 지표 정의는 끝까지 제가 세운 가정입니다. 생성기가 지표 이름·기준일을 어떤 모양으로 남기는지는 생성기 로그를 받아야 압니다. 판정 정답 60개도 제가 매겨서, 맞은 개수가 높게 나와도 성능 증명이 아닙니다.
정확히 1,440분이 지난 SF-1014-0418-2 는 SLA 비교를 '넘으면' 으로 읽는지와 17:40 에 들어온 줄을 빼는지에 따라 판정이 바뀝니다. 1.315 를 1.32 로 올려야 맞는 SF-1014-0493-1, 순매도라 음수인 SF-1014-0402-2, 마트 값이 비어 있는 SF-1014-0471-1, 값은 같고 단위만 % 와 %p 로 다른 SF-1014-0488-1 도 규칙 한 줄이 틀리면 다른 판정으로 넘어갑니다.
SLA 경과 시간은 달력 시간으로 셉니다. 10월 9일 한글날이나 주말처럼 장이 열리지 않은 날을 건너 생성된 숏폼은 마트가 제때 갱신됐어도 SLA 를 넘긴 것으로 나옵니다. 1주차 더미는 평일인 10월 12~14일 갱신분만 두었고, 실제 도입에서는 거래일 달력으로 경과 시간을 다시 셉니다.
'외인 순매수' 처럼 뜻이 분명한 이름도 별칭이 들어가기 전에는 의미 계층에 없는 지표로 걸립니다. 걸린 숏폼을 줄이려고 이름 맞추기를 느슨하게 하지 않고, 분석가가 별칭을 넣는 2주차 탭에서 풉니다.
지표 정의, 소수 자리, SLA 시간, 마트 값은 제가 정한 값입니다. 실제 도입에서는 금융 데이터 분석가가 정한 정의와 Financial Data DE 가 넘기는 표준화 계층을 받아 바꿉니다. 증권 투자지표 산출이나 금융 콘텐츠 심의의 전문성은 주장하지 않습니다.
① 인라인 샘플 · ② seed.json 다운로드 · ③ 증강 프롬프트. 세 층 모두 동일한 schema 에서 파생.
넥스트증권 MTS 에 AI 투자 숏폼이 올라간다고 가정하고, 숏폼 생성기가 대본에 쓴 수치마다 남긴 목록입니다. 숏폼 한 편에 수치가 여럿이라 claim_id 가 판정 단위입니다. 지표 이름은 생성기가 붙인 그대로라 '시가 총액'·'공매도 잔고(비중)'·'선행PER' 처럼 띄어쓰기·괄호가 의미 계층과 다른 이름과 '외인 순매수'·'수주잔고 회전율' 처럼 의미 계층에 없는 이름이 섞여 있고, 순매도는 claim_value 에 음수로 남습니다. 종목은 가명과 999 로 시작하는 가상 코드이고, 대본과 수치는 작성자가 만든 더미입니다.
| claim_id | video_id | ticker | stock_name | script_line | metric_label | claim_value | claim_unit | claim_base_date | generated_at |
|---|---|---|---|---|---|---|---|---|---|
| SF-1014-0371-1 | SF-1014-0371 | 999001 | 가람전자 | 외국인이 5거래일 연속 가람전자를 사들이고 있습니다. | 외국인 연속 순매수 | 5 | 일 | 2026-10-12 | 2026-10-14T16:42:00+09:00 |
| SF-1014-0371-2 | SF-1014-0371 | 999001 | 가람전자 | 오늘 외국인 순매수는 2,140억 원이었습니다. | 외국인 순매수 | 2,140 | 억 원 | 2026-10-14 | 2026-10-14T16:42:00+09:00 |
| SF-1014-0402-1 | SF-1014-0402 | 999002 | 한빛반도체 | 한빛반도체 12개월 선행 PER 은 7.8배입니다. | 12개월 선행 PER | 7.8 | 배 | 2026-10-14 | 2026-10-14T16:55:00+09:00 |
| SF-1014-0402-2 | SF-1014-0402 | 999002 | 한빛반도체 | 외국인은 오늘 한빛반도체를 1,240억 원어치 순매도했습니다. | 외국인 순매수액 | -1,240 | 억 원 | 2026-10-14 | 2026-10-14T16:55:00+09:00 |
| SF-1014-0418-1 | SF-1014-0418 | 999003 | 솔길방산 | 솔길방산 수주잔고 회전율은 3.2회입니다. | 수주잔고 회전율 | 3.2 | 회 | 2026-10-13 | 2026-10-14T17:03:00+09:00 |
아래 JSON Schema 를 그대로 만족하는 AI 투자 숏폼 인용 수치를 숏폼 10편 분량(편마다 수치 1~3개)으로 더 만들어 주세요. {"type":"object","properties":{"claim_id":{"type":"string","description":"숏폼 번호 뒤에 대본 안 순번을 붙인 인용 수치 번호입니다"},"video_id":{"type":"string","description":"AI 숏폼 번호입니다"},"ticker":{"type":"string","description":"가명 종목에 붙인 6자리 가상 코드입니다. 999 로 시작해 실제 상장 종목코드와 겹치지 않습니다"},"stock_name":{"type":"string","description":"지어낸 종목 이름입니다"},"script_line":{"type":"string","description":"수치가 나온 대본 문장 원문입니다"},"metric_label":{"type":"string","description":"숏폼 생성기가 그 수치에 붙인 지표 이름 그대로입니다"},"claim_value":{"type":"number","description":"대본이 말한 값입니다. 순매도는 음수로 남깁니다"},"claim_unit":{"type":"string","description":"대본이 쓴 단위입니다"},"claim_base_date":{"type":"string","description":"대본 수치의 기준일(YYYY-MM-DD)입니다"},"generated_at":{"type":"string","description":"숏폼을 생성한 시각(ISO 8601, +09:00)입니다"}},"required":["claim_id","video_id","ticker","stock_name","script_line","metric_label","claim_value","claim_unit","claim_base_date","generated_at"]} ticker 와 metric_label 은 함께 주는 semantic_metrics·invest_mart 의 종목·지표를 주로 쓰고, 새 종목이 필요하면 실제 상장사가 아닌 지어낸 이름과 999 로 시작하는 6자리 가상 코드를 쓰며, script_line 은 투자 숏폼 대본처럼 짧은 구어체 한 문장으로 쓰세요. claim_id 는 video_id 뒤에 대본 안 순번을 붙이고, 같은 숏폼의 수치는 generated_at 이 같습니다. generated_at 은 2026-10-14 16:30~18:00 사이 장 마감 뒤 시각만 쓰세요. 쉬운 데이터만 만들지 말 것 — 다음 하드 케이스를 의도적으로 섞어라: (1) '시가 총액'·'선행PER' 처럼 띄어쓰기·괄호만 다른 지표 이름, (2) '외인 순매수'·'수주잔고 회전율' 처럼 의미 계층에 없는 이름, (3) 생성 시각에 마트에 더 새 기준일이 있는데 지난 기준일을 쓴 수치, (4) 순매도라 claim_value 가 음수인 수치, (5) 값은 같고 단위만 % 와 %p 로 다른 수치. 생성한 행은 반드시 위 스키마를 통과해야 하며, 형식을 깨뜨리는 시도(generated_at 이 '16:42' 처럼 날짜 없음, claim_value 가 '2,140억' 같은 문자열)는 별도로 3건만 표시해 두세요.{"type":"object","properties":{"claim_id":{"type":"string","description":"숏폼 번호 뒤에 대본 안 순번을 붙인 인용 수치 번호입니다"},"video_id":{"type":"string","description":"AI 숏폼 번호입니다"},"ticker":{"type":"string","description":"가명 종목에 붙인 6자리 가상 코드입니다. 999 로 시작해 실제 상장 종목코드와 겹치지 않습니다"},"stock_name":{"type":"string","description":"지어낸 종목 이름입니다"},"script_line":{"type":"string","description":"수치가 나온 대본 문장 원문입니다"},"metric_label":{"type":"string","description":"숏폼 생성기가 그 수치에 붙인 지표 이름 그대로입니다"},"claim_value":{"type":"number","description":"대본이 말한 값입니다. 순매도는 음수로 남깁니다"},"claim_unit":{"type":"string","description":"대본이 쓴 단위입니다"},"claim_base_date":{"type":"string","description":"대본 수치의 기준일(YYYY-MM-DD)입니다"},"generated_at":{"type":"string","description":"숏폼을 생성한 시각(ISO 8601, +09:00)입니다"}},"required":["claim_id","video_id","ticker","stock_name","script_line","metric_label","claim_value","claim_unit","claim_base_date","generated_at"]}금융 데이터 분석가가 정한 투자정보 의미 계층을 YAML 로 쓰고 Delta 테이블로 올린 표라고 가정합니다. 지표마다 이름·별칭·단위·소수 자리·갱신 SLA·산출 기준이 있고, 그 값은 작성자가 정한 합성 기준입니다. 12개월 선행 PER 에는 추정 기관이 모자라면 산출하지 않는다는 정의를 넣어 마트 값이 비어 있는 날이 생기게 했고, 외국인 지분율은 %, 그 변화는 %p 로 단위를 나눴습니다.
| metric_name | aliases | unit | decimals | refresh_sla_hours | definition |
|---|---|---|---|---|---|
| 외국인 연속 순매수 일수 | ["외국인 연속 순매수","외국인 순매수 연속일수"] | 일 | 0 | 24 | 외국인 일별 순매수 금액이 0 보다 큰 거래일이 기준일부터 거슬러 끊… |
| 외국인 순매수 금액 | ["외국인 순매수","외국인 순매수액"] | 억 원 | 0 | 24 | 기준일 외국인 투자자의 매수 금액에서 매도 금액을 뺀 값입니다. 순매… |
| 외국인 지분율 | ["외국인 보유 비중","외국인 보유율"] | % | 2 | 24 | 기준일 장 마감 기준 외국인 보유 주식 수를 상장 주식 수로 나눈 비… |
| 외국인 지분율 5거래일 변화 | ["외국인 지분율 변화","외국인 보유 비중 변화"] | %p | 2 | 24 | 기준일 외국인 지분율에서 5거래일 전 외국인 지분율을 뺀 값입니다. |
| 12개월 선행 PER | ["선행 PER","Forward PER","12M Fwd PER"] | 배 | 1 | 24 | 기준일 종가를 증권사 12개월 선행 주당순이익 추정치 평균으로 나눈 … |
아래 JSON Schema 를 그대로 만족하는 투자정보 지표 정의를 10개 더 만들어 주세요. {"type":"object","properties":{"metric_name":{"type":"string","description":"금융 데이터 분석가가 정한 지표 이름입니다"},"aliases":{"type":"array","items":{"type":"string"},"description":"같은 지표로 보는 다른 이름입니다. 견줄 때는 공백과 괄호 문자를 지웁니다"},"unit":{"type":"string","description":"대본이 써야 하는 단위입니다"},"decimals":{"type":"integer","minimum":0,"maximum":4,"description":"대본에 쓰는 소수 자리입니다"},"refresh_sla_hours":{"type":"integer","minimum":1,"description":"마트가 이 시간 안에 다시 갱신돼야 합니다"},"definition":{"type":"string","description":"분석가가 쓴 산출 기준입니다"}},"required":["metric_name","aliases","unit","decimals","refresh_sla_hours","definition"]} metric_name 은 수급·밸류에이션·공매도·컨센서스 지표에서 고르고, aliases 에는 투자 콘텐츠에서 실제로 쓰는 줄임말과 띄어쓰기 변형을 넣으세요. definition 은 산출 기준을 한두 문장으로 씁니다. 쉬운 데이터만 만들지 말 것 — 다음 하드 케이스를 의도적으로 섞어라: (1) 글자는 비슷한데 산출 기준이 다른 두 지표(공매도 잔고 비중과 거래대금 가운데 공매도 거래 비중), (2) 단위가 % 인 지표와 그 변화를 %p 로 쓰는 지표, (3) 조건이 맞지 않으면 산출하지 않는다는 정의, (4) 갱신 SLA 가 24시간이 아닌 지표. 생성한 행은 반드시 위 스키마를 통과해야 하며, 형식을 깨뜨리는 시도(decimals 가 -1, aliases 가 문자열 하나)는 별도로 3건만 표시해 두세요.{"type":"object","properties":{"metric_name":{"type":"string","description":"금융 데이터 분석가가 정한 지표 이름입니다"},"aliases":{"type":"array","items":{"type":"string"},"description":"같은 지표로 보는 다른 이름입니다. 견줄 때는 공백과 괄호 문자를 지웁니다"},"unit":{"type":"string","description":"대본이 써야 하는 단위입니다"},"decimals":{"type":"integer","minimum":0,"maximum":4,"description":"대본에 쓰는 소수 자리입니다"},"refresh_sla_hours":{"type":"integer","minimum":1,"description":"마트가 이 시간 안에 다시 갱신돼야 합니다"},"definition":{"type":"string","description":"분석가가 쓴 산출 기준입니다"}},"required":["metric_name","aliases","unit","decimals","refresh_sla_hours","definition"]}투자정보 소비 마트를 종목·지표·기준일 한 줄 꼴로 둔 표입니다. 기준일마다 새 줄을 쌓고 지난 줄은 고치지 않아, refreshed_at 으로 숏폼 생성 시각에 마트가 갖고 있던 줄만 다시 세웁니다. 새봄소재 공매도 잔고 비중은 10월 13일 갱신이 들어오지 않았고, 솔길방산 10월 14일 시가총액은 17:03 생성 뒤인 17:40 에 들어왔으며, 누리바이오 12개월 선행 PER 은 산출하지 않아 value 가 null 입니다. 종목은 가명이고 값은 작성자가 정한 더미입니다.
| ticker | metric_name | base_date | value | refreshed_at |
|---|---|---|---|---|
| 999001 | 외국인 연속 순매수 일수 | 2026-10-12 | 5 | 2026-10-12T16:15:00+09:00 |
| 999001 | 외국인 연속 순매수 일수 | 2026-10-13 | 0 | 2026-10-13T16:12:00+09:00 |
| 999001 | 외국인 연속 순매수 일수 | 2026-10-14 | 1 | 2026-10-14T16:10:00+09:00 |
| 999001 | 외국인 순매수 금액 | 2026-10-14 | 2,140.3 | 2026-10-14T16:10:00+09:00 |
| 999001 | PBR | 2026-10-14 | 1.315 | 2026-10-14T16:20:00+09:00 |
아래 JSON Schema 를 그대로 만족하는 투자정보 마트 줄을, 함께 만든 숏폼 수치의 종목·지표마다 2026-10-12·2026-10-13·2026-10-14 세 기준일씩 만들어 주세요. {"type":"object","properties":{"ticker":{"type":"string","description":"가명 종목에 붙인 6자리 가상 코드입니다. 999 로 시작해 실제 상장 종목코드와 겹치지 않습니다"},"metric_name":{"type":"string","description":"semantic_metrics.metric_name 과 같은 이름입니다"},"base_date":{"type":"string","description":"값의 기준일(YYYY-MM-DD)입니다"},"value":{"type":["number","null"],"description":"DECIMAL(18,4) 로 저장한 값입니다. 산출 기준에 따라 산출하지 않은 날은 null 입니다"},"refreshed_at":{"type":"string","description":"소비 마트에 이 줄이 들어온 시각(ISO 8601, +09:00)입니다. 기준일마다 새 줄을 쌓고 지난 줄은 고치지 않습니다"}},"required":["ticker","metric_name","base_date","value","refreshed_at"]} refreshed_at 은 기준일 당일 16:00~18:30 사이로 두고, 같은 종목·지표 안에서는 기준일이 늦을수록 refreshed_at 도 늦게 하세요. value 는 소수 넷째 자리까지 씁니다. 쉬운 데이터만 만들지 말 것 — 다음 하드 케이스를 의도적으로 섞어라: (1) 하루 갱신이 빠져 다음 기준일 줄이 없는 종목·지표, (2) 숏폼 생성 시각보다 늦게 들어온 기준일 줄, (3) 산출 조건이 맞지 않아 value 가 null 인 12개월 선행 PER, (4) 순매도라 value 가 음수인 외국인 순매수 금액, (5) 1.315 처럼 반올림할 자리 다음 숫자가 5 인 값. 생성한 행은 반드시 위 스키마를 통과해야 하며, 형식을 깨뜨리는 시도(base_date 가 '10/14' 꼴, value 가 '9.1배' 같은 문자열)는 별도로 3건만 표시해 두세요.{"type":"object","properties":{"ticker":{"type":"string","description":"가명 종목에 붙인 6자리 가상 코드입니다. 999 로 시작해 실제 상장 종목코드와 겹치지 않습니다"},"metric_name":{"type":"string","description":"semantic_metrics.metric_name 과 같은 이름입니다"},"base_date":{"type":"string","description":"값의 기준일(YYYY-MM-DD)입니다"},"value":{"type":["number","null"],"description":"DECIMAL(18,4) 로 저장한 값입니다. 산출 기준에 따라 산출하지 않은 날은 null 입니다"},"refreshed_at":{"type":"string","description":"소비 마트에 이 줄이 들어온 시각(ISO 8601, +09:00)입니다. 기준일마다 새 줄을 쌓고 지난 줄은 고치지 않습니다"}},"required":["ticker","metric_name","base_date","value","refreshed_at"]}| SQL | 지표 이름에서 공백·괄호를 지운 키 맞추기, 생성 시각까지 들어온 마트 줄만 남기는 시점 기준 조인, 경과 분 계산, 판정 순서 CASE 를 씁니다. |
| dbt | stg·int·fct 세 층으로 판정 모델을 쌓고, 정확히 1,440분 지난 갱신·1.315 반올림·생성 뒤에 들어온 줄 사례를 dbt 테스트로 고정합니다. 3주차에는 표준 마트에서 invest_mart 를 만드는 모델을 같은 프로젝트에 더합니다. |
| Delta Lake | invest_mart 는 기준일마다 새 줄을 쌓고 지난 줄은 고치지 않아, refreshed_at 으로 생성 시각에 마트가 갖고 있던 상태를 다시 세웁니다. |
| Unity Catalog | 의미 계층 지표의 정의·단위·소수 자리를 컬럼 주석과 태그로 남기고, 3주차에 표준 마트에서 판정까지 이어지는 리니지를 봅니다. |
| Databricks Jobs | 장 마감 뒤 판정 모델 실행을 작업 하나로 걸고, SLA 를 넘긴 마트가 원천 지연인지 변환 실패인지 실행 이력으로 봅니다. |
| Databricks SQL | 관리자 페이지가 SQL 웨어하우스에서 판정 결과를 읽습니다. value 를 DECIMAL(18,4) 로 두고 ROUND 의 사사오입(HALF_UP)으로 1.315 를 1.32 로 올리며, 자릿수는 상수로 넣고 decimals 0·1·2 를 CASE 로 나눕니다. |
| Python (Streamlit) | 판정별 목록, 대본과 마트 줄을 견주는 펼침 칸, 숏폼별 게시·보류·재생성 요청 선택과 CSV 내려받기를 만들고 Databricks Apps 로 띄웁니다. |
| LLM | 의미 계층에 없는 지표 이름 하나와 지표 정의 10개를 넣어 별칭 후보 하나와 이유 한 문장을 받습니다. |
| Claude | Claude Haiku 가 별칭 후보를 고르고, Claude Code 로 dbt 모델과 테스트를 쓰되 AI 가 쓴 판정 SQL 은 1,440분·1.315·생성 뒤 갱신 줄 테스트를 통과할 때만 합칩니다. |
✗ fail → SF-1014-0418-2 가 지난 기준일 값을 씀으로 나오면 생성 시각 뒤에 들어온 줄을 빼지 못한 것이니 시점 기준 조인부터 다시 봅니다.
✓ pass → 여기서 멈춰도 완결입니다. 2주차에는 작성자가 손으로 매긴 정답 60개를 같은 dbt 모델에 돌려 틀린 수치마다 원인 단계를 붙이고, 분석가가 '외인 순매수' 같은 이름을 별칭으로 넣는 탭을 엽니다.
✓ pass → 여기까지도 완결입니다. 3주차에는 KRX 정보데이터시스템에서 내려받은 CSV 로 표준 마트를 쌓고, invest_mart 를 그 위의 소비 마트로 다시 세워 같은 판정을 다시 돌립니다.
위 예측 UI 는 3주차까지 완주했을 때의 화면입니다. 1주차에 실제로 만드는 것은 아래 표시된 화면 하나입니다.
verdict사유 라벨 · claim_id + 한 줄 요약(근거 수치 포함)화면·코드·면접에서 이 단어를 그대로 씁니다. 키는 출력 스키마의 enum 과 같습니다.
마트와 맞음마트와 맞음의미 계층에 없는 지표정의 없는 지표마트 갱신이 SLA 를 넘겨 밀림마트 갱신 지연지난 기준일 값을 씀지난 기준일마트 값과 다름값·단위 다름AI 숏폼 수치 검수 판정입니다. 숏폼 대본의 인용 수치 하나에 판정 하나와 근거(의미 계층에서 정해진 지표, 생성 시각에 마트가 갖고 있던 최신 기준일과 마지막 갱신, 대본 기준일의 마트 값을 반올림한 값)를 남깁니다.
{"type":"object","properties":{"claim_id":{"type":"string"},"video_id":{"type":"string"},"ticker":{"type":"string"},"stock_name":{"type":"string"},"metric_label":{"type":"string","description":"숏폼 생성기가 붙인 지표 이름 그대로입니다"},"label_key":{"type":"string","description":"metric_label 에서 공백과 괄호 문자 ( ) 를 지운 값입니다. 괄호 안 글자는 남깁니다"},"verdict":{"type":"string","enum":["마트와 맞음","의미 계층에 없는 지표","마트 갱신이 SLA 를 넘겨 밀림","지난 기준일 값을 씀","마트 값과 다름"],"description":"의미 계층에 없는 지표, 마트 갱신이 SLA 를 넘겨 밀림, 지난 기준일 값을 씀, 마트 값과 다름 순으로 먼저 걸린 하나입니다. 하나도 걸리지 않으면 마트와 맞음입니다"},"matched_metric":{"type":["string","null"],"description":"semantic_metrics 의 metric_name·aliases 를 같은 방식으로 지운 값이 label_key 와 같은 지표의 metric_name 입니다. 없으면 null 입니다"},"claim_value":{"type":"number"},"claim_unit":{"type":"string"},"metric_unit":{"type":["string","null"],"description":"matched_metric 의 semantic_metrics.unit 입니다"},"metric_decimals":{"type":["integer","null"],"description":"matched_metric 의 semantic_metrics.decimals 입니다"},"refresh_sla_hours":{"type":["integer","null"],"description":"matched_metric 의 semantic_metrics.refresh_sla_hours 입니다"},"claim_base_date":{"type":"string"},"generated_at":{"type":"string"},"last_refreshed_at":{"type":["string","null"],"description":"같은 ticker·matched_metric 의 invest_mart 줄 가운데 refreshed_at 이 generated_at 과 같거나 이른 가장 늦은 refreshed_at 입니다"},"elapsed_minutes":{"type":["integer","null"],"minimum":0,"description":"정적 계산값입니다. generated_at − last_refreshed_at 을 분으로 센 값이고, refresh_sla_hours × 60 보다 크면 SLA 를 넘긴 것입니다"},"latest_base_date":{"type":["string","null"],"description":"같은 ticker·matched_metric 의 invest_mart 줄 가운데 refreshed_at 이 generated_at 과 같거나 이른 줄의 가장 늦은 base_date 입니다"},"mart_value":{"type":["number","null"],"description":"같은 ticker·matched_metric 에서 base_date 가 claim_base_date 와 같은 invest_mart.value 입니다"},"mart_value_rounded":{"type":["number","null"],"description":"정적 계산값입니다. mart_value 를 metric_decimals 자리로 사사오입(HALF_UP)한 값이고, mart_value 가 null 이면 null 입니다"},"alias_candidate":{"type":["string","null"],"description":"verdict 가 의미 계층에 없는 지표일 때만 Claude Haiku 가 고른 metric_name 입니다. metric_name 목록에 글자 그대로 없으면 null 입니다"},"alias_reason":{"type":["string","null"],"description":"Claude Haiku 가 그 후보를 고른 이유 한 문장입니다"},"evidence":{"type":"array","items":{"type":"object","properties":{"table":{"type":"string","enum":["shortform_claims","semantic_metrics","invest_mart"]},"row":{"type":["string","null"],"description":"그 표의 키입니다. shortform_claims 는 claim_id, semantic_metrics 는 metric_name, invest_mart 는 ticker/metric_name/base_date 입니다"},"field":{"type":"string"},"value":{"type":["string","number","array","null"]},"agg":{"type":"string","enum":["count","sum","avg","min","max"]}},"required":["table","row","field"]}},"notes":{"type":"array","items":{"type":"string"},"description":"판정에 들지 않았지만 T&S 담당자나 분석가가 볼 사실입니다"},"summary":{"type":"string"}},"required":["claim_id","video_id","ticker","stock_name","metric_label","label_key","verdict","matched_metric","claim_value","claim_unit","metric_unit","metric_decimals","refresh_sla_hours","claim_base_date","generated_at","last_refreshed_at","elapsed_minutes","latest_base_date","mart_value","mart_value_rounded","alias_candidate","alias_reason","evidence","notes","summary"]}[
{
"claim_id": "SF-1014-0371-1",
"video_id": "SF-1014-0371",
"ticker": "999001",
"stock_name": "가람전자",
"metric_label": "외국인 연속 순매수",
"label_key": "외국인연속순매수",
"verdict": "지난 기준일 값을 씀",
"matched_metric": "외국인 연속 순매수 일수",
"claim_value": 5,
"claim_unit": "일",
"metric_unit": "일",
"metric_decimals": 0,
"refresh_sla_hours": 24,
"claim_base_date": "2026-10-12",
"generated_at": "2026-10-14T16:42:00+09:00",
"last_refreshed_at": "2026-10-14T16:10:00+09:00",
"elapsed_minutes": 32,
"latest_base_date": "2026-10-14",
"mart_value": 5,
"mart_value_rounded": 5,
"alias_candidate": null,
"alias_reason": null,
"evidence": [
{
"table": "shortform_claims",
"row": "SF-1014-0371-1",
"field": "metric_label",
"value": "외국인 연속 순매수"
},
{
"table": "semantic_metrics",
"row": "외국인 연속 순매수 일수",
"field": "aliases",
"value": [
"외국인 연속 순매수",
"외국인 순매수 연속일수"
]
},
{
"table": "shortform_claims",
"row": "SF-1014-0371-1",
"field": "generated_at",
"value": "2026-10-14T16:42:00+09:00"
},
{
"table": "invest_mart",
"row": "999001/외국인 연속 순매수 일수/2026-10-14",
"field": "refreshed_at",
"value": "2026-10-14T16:10:00+09:00"
},
{
"table": "semantic_metrics",
"row": "외국인 연속 순매수 일수",
"field": "refresh_sla_hours",
"value": 24
},
{
"table": "shortform_claims",
"row": "SF-1014-0371-1",
"field": "claim_base_date",
"value": "2026-10-12"
},
{
"table": "invest_mart",
"row": "999001/외국인 연속 순매수 일수/2026-10-14",
"field": "base_date",
"value": "2026-10-14"
},
{
"table": "invest_mart",
"row": "999001/외국인 연속 순매수 일수/2026-10-14",
"field": "value",
"value": 1
},
{
"table": "invest_mart",
"row": "999001/외국인 연속 순매수 일수/2026-10-13",
"field": "value",
"value": 0
},
{
"table": "invest_mart",
"row": "999001/외국인 연속 순매수 일수/2026-10-12",
"field": "value",
"value": 5
},
{
"table": "shortform_claims",
"row": "SF-1014-0371-1",
"field": "claim_value",
"value": 5
}
],
"notes": [
"대본 기준일 10월 12일의 마트 값 5일은 대본과 같습니다. 10월 13일 외국인이 순매도해 연속 일수가 0 으로 끊겼고, 16:42 생성 때는 10월 14일 값 1일이 마트에 들어와 있었습니다."
],
"summary": "대본은 10월 12일 기준 5거래일 연속 순매수를 말하는데, 16:42 생성 시점 마트에는 10월 14일 기준 값 1일이 이미 있었습니다."
},
{
"claim_id": "SF-1014-0402-1",
"video_id": "SF-1014-0402",
"ticker": "999002",
"stock_name": "한빛반도체",
"metric_label": "12개월 선행 PER",
"label_key": "12개월선행PER",
"verdict": "마트 값과 다름",
"matched_metric": "12개월 선행 PER",
"claim_value": 7.8,
"claim_unit": "배",
"metric_unit": "배",
"metric_decimals": 1,
"refresh_sla_hours": 24,
"claim_base_date": "2026-10-14",
"generated_at": "2026-10-14T16:55:00+09:00",
"last_refreshed_at": "2026-10-14T16:20:00+09:00",
"elapsed_minutes": 35,
"latest_base_date": "2026-10-14",
"mart_value": 9.13,
"mart_value_rounded": 9.1,
"alias_candidate": null,
"alias_reason": null,
"evidence": [
{
"table": "shortform_claims",
"row": "SF-1014-0402-1",
"field": "metric_label",
"value": "12개월 선행 PER"
},
{
"table": "semantic_metrics",
"row": "12개월 선행 PER",
"field": "metric_name",
"value": "12개월 선행 PER"
},
{
"table": "shortform_claims",
"row": "SF-1014-0402-1",
"field": "generated_at",
"value": "2026-10-14T16:55:00+09:00"
},
{
"table": "invest_mart",
"row": "999002/12개월 선행 PER/2026-10-14",
"field": "refreshed_at",
"value": "2026-10-14T16:20:00+09:00"
},
{
"table": "semantic_metrics",
"row": "12개월 선행 PER",
"field": "refresh_sla_hours",
"value": 24
},
{
"table": "shortform_claims",
"row": "SF-1014-0402-1",
"field": "claim_base_date",
"value": "2026-10-14"
},
{
"table": "invest_mart",
"row": "999002/12개월 선행 PER/2026-10-14",
"field": "base_date",
"value": "2026-10-14"
},
{
"table": "invest_mart",
"row": "999002/12개월 선행 PER/2026-10-14",
"field": "value",
"value": 9.13
},
{
"table": "semantic_metrics",
"row": "12개월 선행 PER",
"field": "decimals",
"value": 1
},
{
"table": "shortform_claims",
"row": "SF-1014-0402-1",
"field": "claim_value",
"value": 7.8
},
{
"table": "shortform_claims",
"row": "SF-1014-0402-1",
"field": "claim_unit",
"value": "배"
},
{
"table": "semantic_metrics",
"row": "12개월 선행 PER",
"field": "unit",
"value": "배"
}
],
"notes": [],
"summary": "대본은 12개월 선행 PER 7.8배를 말하는데, 같은 기준일 마트 값 9.13배를 소수 첫째 자리로 반올림하면 9.1배입니다."
},
{
"claim_id": "SF-1014-0402-2",
"video_id": "SF-1014-0402",
"ticker": "999002",
"stock_name": "한빛반도체",
"metric_label": "외국인 순매수액",
"label_key": "외국인순매수액",
"verdict": "마트와 맞음",
"matched_metric": "외국인 순매수 금액",
"claim_value": -1240,
"claim_unit": "억 원",
"metric_unit": "억 원",
"metric_decimals": 0,
"refresh_sla_hours": 24,
"claim_base_date": "2026-10-14",
"generated_at": "2026-10-14T16:55:00+09:00",
"last_refreshed_at": "2026-10-14T16:10:00+09:00",
"elapsed_minutes": 45,
"latest_base_date": "2026-10-14",
"mart_value": -1240.4,
"mart_value_rounded": -1240,
"alias_candidate": null,
"alias_reason": null,
"evidence": [
{
"table": "shortform_claims",
"row": "SF-1014-0402-2",
"field": "metric_label",
"value": "외국인 순매수액"
},
{
"table": "semantic_metrics",
"row": "외국인 순매수 금액",
"field": "aliases",
"value": [
"외국인 순매수",
"외국인 순매수액"
]
},
{
"table": "shortform_claims",
"row": "SF-1014-0402-2",
"field": "generated_at",
"value": "2026-10-14T16:55:00+09:00"
},
{
"table": "invest_mart",
"row": "999002/외국인 순매수 금액/2026-10-14",
"field": "refreshed_at",
"value": "2026-10-14T16:10:00+09:00"
},
{
"table": "semantic_metrics",
"row": "외국인 순매수 금액",
"field": "refresh_sla_hours",
"value": 24
},
{
"table": "shortform_claims",
"row": "SF-1014-0402-2",
"field": "claim_base_date",
"value": "2026-10-14"
},
{
"table": "invest_mart",
"row": "999002/외국인 순매수 금액/2026-10-14",
"field": "base_date",
"value": "2026-10-14"
},
{
"table": "invest_mart",
"row": "999002/외국인 순매수 금액/2026-10-14",
"field": "value",
"value": -1240.4
},
{
"table": "semantic_metrics",
"row": "외국인 순매수 금액",
"field": "decimals",
"value": 0
},
{
"table": "shortform_claims",
"row": "SF-1014-0402-2",
"field": "claim_value",
"value": -1240
},
{
"table": "semantic_metrics",
"row": "외국인 순매수 금액",
"field": "definition",
"value": "기준일 외국인 투자자의 매수 금액에서 매도 금액을 뺀 값입니다. 순매도면 음수입니다."
}
],
"notes": [
"대본 문장은 '순매도' 라고 썼고 숏폼 생성기는 값을 -1240 으로 남겼습니다. 의미 계층 정의에서 순매도는 음수라 부호도 마트와 같습니다."
],
"summary": "마트 값 -1,240.4억 원을 소수 0 자리로 반올림한 -1,240억 원이 대본 값과 같고, 기준일과 갱신 시각도 생성 시점 마트와 맞습니다."
},
{
"claim_id": "SF-1014-0418-2",
"video_id": "SF-1014-0418",
"ticker": "999003",
"stock_name": "솔길방산",
"metric_label": "시가 총액",
"label_key": "시가총액",
"verdict": "마트와 맞음",
"matched_metric": "시가총액",
"claim_value": 41.3,
"claim_unit": "조 원",
"metric_unit": "조 원",
"metric_decimals": 1,
"refresh_sla_hours": 24,
"claim_base_date": "2026-10-13",
"generated_at": "2026-10-14T17:03:00+09:00",
"last_refreshed_at": "2026-10-13T17:03:00+09:00",
"elapsed_minutes": 1440,
"latest_base_date": "2026-10-13",
"mart_value": 41.27,
"mart_value_rounded": 41.3,
"alias_candidate": null,
"alias_reason": null,
"evidence": [
{
"table": "shortform_claims",
"row": "SF-1014-0418-2",
"field": "metric_label",
"value": "시가 총액"
},
{
"table": "semantic_metrics",
"row": "시가총액",
"field": "metric_name",
"value": "시가총액"
},
{
"table": "shortform_claims",
"row": "SF-1014-0418-2",
"field": "generated_at",
"value": "2026-10-14T17:03:00+09:00"
},
{
"table": "invest_mart",
"row": "999003/시가총액/2026-10-13",
"field": "refreshed_at",
"value": "2026-10-13T17:03:00+09:00"
},
{
"table": "invest_mart",
"row": "999003/시가총액/2026-10-14",
"field": "refreshed_at",
"value": "2026-10-14T17:40:00+09:00"
},
{
"table": "semantic_metrics",
"row": "시가총액",
"field": "refresh_sla_hours",
"value": 24
},
{
"table": "shortform_claims",
"row": "SF-1014-0418-2",
"field": "claim_base_date",
"value": "2026-10-13"
},
{
"table": "invest_mart",
"row": "999003/시가총액/2026-10-13",
"field": "base_date",
"value": "2026-10-13"
},
{
"table": "invest_mart",
"row": "999003/시가총액/2026-10-13",
"field": "value",
"value": 41.27
},
{
"table": "semantic_metrics",
"row": "시가총액",
"field": "decimals",
"value": 1
},
{
"table": "shortform_claims",
"row": "SF-1014-0418-2",
"field": "claim_value",
"value": 41.3
}
],
"notes": [
"10월 14일 시가총액 42.05조 원은 17:03 생성 뒤인 17:40 에 마트에 들어와 판정에 쓰지 않았습니다. 게시하는 시각에는 더 새 값이 있다는 사실을 T&S 담당자가 이 메모로 봅니다.",
"마지막 갱신에서 생성까지 정확히 1,440분이 지나 SLA 24시간을 넘기지 않았습니다."
],
"summary": "'시가 총액' 은 공백을 지우면 시가총액이고, 생성 시점 마트의 최신 기준일 10월 13일 값 41.27조 원을 반올림한 41.3조 원이 대본과 같습니다."
},
{
"claim_id": "SF-1014-0455-1",
"video_id": "SF-1014-0455",
"ticker": "999004",
"stock_name": "새봄소재",
"metric_label": "공매도 잔고(비중)",
"label_key": "공매도잔고비중",
"verdict": "마트 갱신이 SLA 를 넘겨 밀림",
"matched_metric": "공매도 잔고 비중",
"claim_value": 4.1,
"claim_unit": "%",
"metric_unit": "%",
"metric_decimals": 1,
"refresh_sla_hours": 24,
"claim_base_date": "2026-10-12",
"generated_at": "2026-10-14T16:42:00+09:00",
"last_refreshed_at": "2026-10-12T18:05:00+09:00",
"elapsed_minutes": 2797,
"latest_base_date": "2026-10-12",
"mart_value": 4.08,
"mart_value_rounded": 4.1,
"alias_candidate": null,
"alias_reason": null,
"evidence": [
{
"table": "shortform_claims",
"row": "SF-1014-0455-1",
"field": "metric_label",
"value": "공매도 잔고(비중)"
},
{
"table": "semantic_metrics",
"row": "공매도 잔고 비중",
"field": "metric_name",
"value": "공매도 잔고 비중"
},
{
"table": "shortform_claims",
"row": "SF-1014-0455-1",
"field": "generated_at",
"value": "2026-10-14T16:42:00+09:00"
},
{
"table": "invest_mart",
"row": "999004/공매도 잔고 비중/2026-10-12",
"field": "refreshed_at",
"value": "2026-10-12T18:05:00+09:00"
},
{
"table": "semantic_metrics",
"row": "공매도 잔고 비중",
"field": "refresh_sla_hours",
"value": 24
},
{
"table": "shortform_claims",
"row": "SF-1014-0455-1",
"field": "claim_base_date",
"value": "2026-10-12"
},
{
"table": "invest_mart",
"row": "999004/공매도 잔고 비중/2026-10-12",
"field": "base_date",
"value": "2026-10-12"
},
{
"table": "invest_mart",
"row": "999004/공매도 잔고 비중/2026-10-12",
"field": "value",
"value": 4.08
},
{
"table": "semantic_metrics",
"row": "공매도 잔고 비중",
"field": "decimals",
"value": 1
},
{
"table": "shortform_claims",
"row": "SF-1014-0455-1",
"field": "claim_value",
"value": 4.1
}
],
"notes": [
"대본 값 4.1% 는 10월 12일 마트 값 4.08% 를 소수 첫째 자리로 반올림한 값과 같습니다. 대본이 마트를 잘못 읽은 것이 아니라, 10월 13일 갱신이 들어오지 않은 마트를 그대로 읽었습니다."
],
"summary": "공매도 잔고 비중의 마지막 갱신이 10월 12일 18:05 라 16:42 생성 시점에 2,797분이 지나 SLA 1,440분을 넘겼습니다."
},
{
"claim_id": "SF-1014-0463-1",
"video_id": "SF-1014-0463",
"ticker": "999005",
"stock_name": "다온플랫폼",
"metric_label": "외인 순매수",
"label_key": "외인순매수",
"verdict": "의미 계층에 없는 지표",
"matched_metric": null,
"claim_value": 312,
"claim_unit": "억 원",
"metric_unit": null,
"metric_decimals": null,
"refresh_sla_hours": null,
"claim_base_date": "2026-10-14",
"generated_at": "2026-10-14T17:10:00+09:00",
"last_refreshed_at": null,
"elapsed_minutes": null,
"latest_base_date": null,
"mart_value": null,
"mart_value_rounded": null,
"alias_candidate": "외국인 순매수 금액",
"alias_reason": "'외인' 은 외국인 투자자를 줄인 말이고, 대본의 '사들였습니다' 와 단위 억 원이 외국인 순매수 금액의 정의와 단위에 맞습니다.",
"evidence": [
{
"table": "shortform_claims",
"row": "SF-1014-0463-1",
"field": "metric_label",
"value": "외인 순매수"
},
{
"table": "semantic_metrics",
"row": null,
"field": "metric_name",
"agg": "count",
"value": 10
},
{
"table": "semantic_metrics",
"row": "외국인 순매수 금액",
"field": "aliases",
"value": [
"외국인 순매수",
"외국인 순매수액"
]
},
{
"table": "semantic_metrics",
"row": "외국인 순매수 금액",
"field": "definition",
"value": "기준일 외국인 투자자의 매수 금액에서 매도 금액을 뺀 값입니다. 순매도면 음수입니다."
},
{
"table": "shortform_claims",
"row": "SF-1014-0463-1",
"field": "claim_unit",
"value": "억 원"
}
],
"notes": [
"분석가가 '외인 순매수' 를 외국인 순매수 금액의 별칭으로 넣으면 다음 판정부터 마트 값과 견줍니다."
],
"summary": "'외인 순매수' 는 공백과 괄호를 지워도 의미 계층 지표 10개의 이름·별칭 어느 것과도 같지 않습니다."
},
{
"claim_id": "SF-1014-0471-1",
"video_id": "SF-1014-0471",
"ticker": "999006",
"stock_name": "누리바이오",
"metric_label": "선행PER",
"label_key": "선행PER",
"verdict": "마트 값과 다름",
"matched_metric": "12개월 선행 PER",
"claim_value": 45.2,
"claim_unit": "배",
"metric_unit": "배",
"metric_decimals": 1,
"refresh_sla_hours": 24,
"claim_base_date": "2026-10-14",
"generated_at": "2026-10-14T17:10:00+09:00",
"last_refreshed_at": "2026-10-14T16:20:00+09:00",
"elapsed_minutes": 50,
"latest_base_date": "2026-10-14",
"mart_value": null,
"mart_value_rounded": null,
"alias_candidate": null,
"alias_reason": null,
"evidence": [
{
"table": "shortform_claims",
"row": "SF-1014-0471-1",
"field": "metric_label",
"value": "선행PER"
},
{
"table": "semantic_metrics",
"row": "12개월 선행 PER",
"field": "aliases",
"value": [
"선행 PER",
"Forward PER",
"12M Fwd PER"
]
},
{
"table": "shortform_claims",
"row": "SF-1014-0471-1",
"field": "generated_at",
"value": "2026-10-14T17:10:00+09:00"
},
{
"table": "invest_mart",
"row": "999006/12개월 선행 PER/2026-10-14",
"field": "refreshed_at",
"value": "2026-10-14T16:20:00+09:00"
},
{
"table": "semantic_metrics",
"row": "12개월 선행 PER",
"field": "refresh_sla_hours",
"value": 24
},
{
"table": "shortform_claims",
"row": "SF-1014-0471-1",
"field": "claim_base_date",
"value": "2026-10-14"
},
{
"table": "invest_mart",
"row": "999006/12개월 선행 PER/2026-10-14",
"field": "base_date",
"value": "2026-10-14"
},
{
"table": "invest_mart",
"row": "999006/12개월 선행 PER/2026-10-14",
"field": "value",
"value": null
},
{
"table": "shortform_claims",
"row": "SF-1014-0471-1",
"field": "claim_value",
"value": 45.2
}
],
"notes": [
"의미 계층 정의상 추정 기관이 3곳 미만이거나 추정치 평균이 0 이하이면 12개월 선행 PER 을 산출하지 않습니다. 마트가 비워 둔 값을 대본이 45.2배로 말했으니, 이 숫자의 출처는 숏폼 생성기 쪽에서 확인합니다."
],
"summary": "누리바이오의 10월 14일 12개월 선행 PER 은 마트에 값이 없는데 대본은 45.2배라고 말합니다."
},
{
"claim_id": "SF-1014-0488-1",
"video_id": "SF-1014-0488",
"ticker": "999002",
"stock_name": "한빛반도체",
"metric_label": "외국인 지분율 변화",
"label_key": "외국인지분율변화",
"verdict": "마트 값과 다름",
"matched_metric": "외국인 지분율 5거래일 변화",
"claim_value": 0.82,
"claim_unit": "%",
"metric_unit": "%p",
"metric_decimals": 2,
"refresh_sla_hours": 24,
"claim_base_date": "2026-10-14",
"generated_at": "2026-10-14T17:18:00+09:00",
"last_refreshed_at": "2026-10-14T16:20:00+09:00",
"elapsed_minutes": 58,
"latest_base_date": "2026-10-14",
"mart_value": 0.82,
"mart_value_rounded": 0.82,
"alias_candidate": null,
"alias_reason": null,
"evidence": [
{
"table": "shortform_claims",
"row": "SF-1014-0488-1",
"field": "metric_label",
"value": "외국인 지분율 변화"
},
{
"table": "semantic_metrics",
"row": "외국인 지분율 5거래일 변화",
"field": "aliases",
"value": [
"외국인 지분율 변화",
"외국인 보유 비중 변화"
]
},
{
"table": "shortform_claims",
"row": "SF-1014-0488-1",
"field": "generated_at",
"value": "2026-10-14T17:18:00+09:00"
},
{
"table": "invest_mart",
"row": "999002/외국인 지분율 5거래일 변화/2026-10-14",
"field": "refreshed_at",
"value": "2026-10-14T16:20:00+09:00"
},
{
"table": "semantic_metrics",
"row": "외국인 지분율 5거래일 변화",
"field": "refresh_sla_hours",
"value": 24
},
{
"table": "shortform_claims",
"row": "SF-1014-0488-1",
"field": "claim_base_date",
"value": "2026-10-14"
},
{
"table": "invest_mart",
"row": "999002/외국인 지분율 5거래일 변화/2026-10-14",
"field": "base_date",
"value": "2026-10-14"
},
{
"table": "invest_mart",
"row": "999002/외국인 지분율 5거래일 변화/2026-10-14",
"field": "value",
"value": 0.82
},
{
"table": "semantic_metrics",
"row": "외국인 지분율 5거래일 변화",
"field": "decimals",
"value": 2
},
{
"table": "shortform_claims",
"row": "SF-1014-0488-1",
"field": "claim_value",
"value": 0.82
},
{
"table": "shortform_claims",
"row": "SF-1014-0488-1",
"field": "claim_unit",
"value": "%"
},
{
"table": "semantic_metrics",
"row": "외국인 지분율 5거래일 변화",
"field": "unit",
"value": "%p"
}
],
"notes": [
"지분율이 0.82%p 움직였는데 대본처럼 '0.82% 늘었습니다' 로 쓰면, 지분율이 원래 값의 1.0082배가 됐다는 말로 읽힙니다."
],
"summary": "값 0.82 는 마트와 같지만 대본 단위 % 가 의미 계층 단위 %p 와 다릅니다."
}
][자동 검증 · 코드가 판정합니다] 1. verdict 가 마트와 맞음·의미 계층에 없는 지표·마트 갱신이 SLA 를 넘겨 밀림·지난 기준일 값을 씀·마트 값과 다름 다섯 값 중 하나인지 확인합니다. 2. 필수 필드 claim_id·video_id·ticker·stock_name·metric_label·label_key·verdict·matched_metric·claim_value·claim_unit·metric_unit·metric_decimals·refresh_sla_hours·claim_base_date·generated_at·last_refreshed_at·elapsed_minutes·latest_base_date·mart_value·mart_value_rounded·alias_candidate·alias_reason·evidence·notes·summary 가 모두 존재하는지 확인합니다. 3. 의미 계층에 없는 지표: label_key 가 metric_label 에서 공백과 괄호 문자를 지운 값인지 다시 계산하고, semantic_metrics 의 metric_name·aliases 를 같은 방식으로 지운 값 가운데 label_key 와 같은 것이 없으면 이 판정이고 matched_metric 은 null 입니다. '시가 총액'·'공매도 잔고(비중)'·'선행PER' 은 지운 뒤 시가총액·공매도잔고비중·선행PER 과 같아 지표가 정해지고, '외인 순매수'·'수주잔고 회전율' 은 같은 값이 없어 걸립니다. 4. 마트 갱신이 SLA 를 넘겨 밀림: last_refreshed_at 이 같은 ticker·matched_metric 의 invest_mart 줄 가운데 generated_at 과 같거나 이른 가장 늦은 refreshed_at 인지 확인하고, elapsed_minutes 가 generated_at − last_refreshed_at 을 분으로 센 값인지 다시 계산합니다. elapsed_minutes 가 refresh_sla_hours × 60 보다 크면 이 판정입니다. SF-1014-0455-1 은 2,797분이 1,440분보다 커서 걸리고, SF-1014-0418-2 는 정확히 1,440분이라 걸리지 않습니다. 5. 지난 기준일 값을 씀: latest_base_date 가 refreshed_at 이 generated_at 과 같거나 이른 같은 ticker·matched_metric 줄의 가장 늦은 base_date 인지 다시 계산하고, claim_base_date 가 그보다 이르면 이 판정입니다. SF-1014-0371-1 은 2026-10-12 가 2026-10-14 보다 일러 걸리고, SF-1014-0418-2 는 17:40 에 들어온 2026-10-14 줄을 빼면 최신 기준일이 2026-10-13 이라 걸리지 않습니다. 6. 마트 값과 다름: mart_value_rounded 가 claim_base_date 와 같은 base_date 의 mart_value 를 metric_decimals 자리로 사사오입(HALF_UP)한 값인지 다시 계산하고, mart_value_rounded 가 claim_value 와 다르거나 mart_value 가 null 이거나 claim_unit 이 metric_unit 과 다르면 이 판정입니다. SF-1014-0402-1 은 9.13 을 반올림한 9.1 이 7.8 과 달라서, SF-1014-0471-1 은 mart_value 가 null 이라서, SF-1014-0488-1 은 값 0.82 는 같지만 % 와 %p 가 달라서 걸립니다. SF-1014-0402-2 의 -1240.4 는 -1240 이 되고 SF-1014-0493-1 의 1.315 는 1.32 가 되어 대본과 같으므로 걸리지 않습니다. 7. 판정 순서: 의미 계층에 없는 지표, 마트 갱신이 SLA 를 넘겨 밀림, 지난 기준일 값을 씀, 마트 값과 다름 순으로 먼저 걸린 하나가 verdict 입니다. SF-1014-0455-1 은 기준일과 반올림 값이 대본과 같아도 SLA 가 앞서므로 밀림으로 다시 계산됩니다. 8. alias_candidate 가 null 이 아니면 verdict 가 의미 계층에 없는 지표이고, 그 값이 semantic_metrics.metric_name 목록에 있는지 확인합니다. 9. evidence 의 table·field 가 shortform_claims·semantic_metrics·invest_mart 에 실재하는 컬럼인지 대조합니다. 10. agg 가 없는 evidence 의 value 가 그 row 의 그 컬럼 값 그대로인지 확인합니다. 11. summary 가 존댓말로 끝나는지 확인합니다. [수동 검증 · 사람이 봅니다] 1. 걸린 수치가 든 숏폼을 게시할지, 보류할지, 재생성을 요청할지는 T&S 담당자가 정합니다. 2. alias_candidate 를 별칭으로 넣을지, 새 지표로 정의할지는 금융 데이터 분석가가 지표 정의를 읽고 정합니다. 3. SLA 를 넘긴 마트가 원천 지연인지 변환 작업 실패인지는 데이터 담당자가 Jobs 실행 이력으로 봅니다. [평가 러너 · 2주차] 1. 작성자가 판정을 손으로 매긴 인용 수치 60개에서 verdict 가 정답과 같은 개수를 셉니다. 2. 정답과 다른 수치에는 이름 맞추기·시점 조인·SLA·기준일·반올림·단위 가운데 원인 단계를 붙입니다. 3. 의미 계층에 없는 지표 가운데 작성자가 정답 별칭을 단 수치에서 alias_candidate 가 정답과 같은 개수를 셉니다. [판정식에 더한 정의 · 오너 확인 항목] 1. 숏폼 한 편에 수치가 여럿이라, 수치 하나를 가리키는 번호가 없으면 같은 숏폼 안에서 맞는 수치와 걸린 수치를 나눌 수 없습니다. 그 번호로 카드 inputs 에 없던 shortform_claims.claim_id 를 더했습니다. 화면에 대본 문장을 보이려고 stock_name·script_line 을, 별칭 후보를 고를 때 모델이 읽을 산출 기준으로 semantic_metrics.definition 을 더했습니다. 2. '공백·괄호를 지운 뒤' 는 공백 문자와 괄호 문자 ( ) 만 지우고 괄호 안 글자는 남기는 것으로 정했습니다. metric_name·aliases 도 같은 방식으로 지운 뒤 견줍니다. 3. SLA 의 '이른 줄' 과 기준일의 '시점까지' 를 둘 다 refreshed_at 이 generated_at 과 같거나 이른 줄로 읽었습니다. SLA 는 '넘으면' 이라 경과 분이 refresh_sla_hours × 60 과 같으면 걸리지 않습니다. 4. 카드가 정한 순서는 의미 계층에 없는 지표가 먼저라는 것뿐이라, 나머지는 SLA, 기준일, 값 순으로 정했습니다. 마트가 밀린 상태에서는 기준일과 값의 비교가 오래된 마트를 기준으로 나오기 때문입니다. 5. mart_value 가 null 이면 대본이 숫자를 말한 것 자체를 마트 값과 다름으로 봅니다. 반올림은 사사오입(HALF_UP)입니다.