엘리스
경력근거: 엔지니어링 경험을 바탕으로 AX 교육(PoC, 부트캠프, 워크숍 등)의 커리큘럼과 콘텐츠를 기획·개발하고
※ 실제 산출물이 아닌 AI 예측 시안입니다.
엘리스는 엘리스LXP 로 6,200여 기업·기관과 260만 명 학습자를 받치면서, AI AX팀이 고객사와 함께 AX 부트캠프를 열고 커리큘럼 기획부터 코칭까지 직접 맡습니다. 제출물을 커리큘럼 목표와 맞춰 막힌 사유를 가르는 이 화면은 그 교육이 실제로 굴러가는 자리에 바로 붙고, 과제마다 필수 개념과 금지 이름이 정해져 있는 엘리스의 실습 과제 구조가 있어야 판정이 성립합니다.
공고가 Solution/FDE 분야를 고객사와 함께 AX 프로젝트와 교육을 수행하는 자리로 못박았습니다. 그 교육 현장에서 매일 쌓이는 제출물을 판정 대상으로 잡았습니다.
부트캠프 커리큘럼을 기획하고 코칭·멘토링까지 직접 한다고 적혀 있습니다. 코칭 순서를 정하는 일이 그 사람의 하루에서 가장 먼저 걸립니다.
평가 도구로 품질을 검증한 경험을 우대합니다. 판정과 정답을 대조하는 평가 러너를 2주차에 그대로 붙였습니다.
고객사 사내 AX 부트캠프에서 하루에 쌓이는 제출물을 과제 정의표와 기수 계획표에 맞춰 제출 하나하나가 어디서 막혔는지 정합니다. 통과 개수를 전체 개수로 나눠 기준과 견주고, 과제가 가르치려던 개념을 실제로 썼는지는 제출한 코드를 파이썬 문법 나무로 읽어 반복문과 예외 처리 같은 마디가 정말 있는지 직접 찾아 정하고, 같은 사람이 같은 과제에서 같은 오류를 몇 번째 내고 있는지 세고, 제출일이 그 모듈 체크포인트를 넘겼는지 따집니다. 점수만 보면 통과인데 배운 것이 안 남은 제출과, 점수는 낮아도 오늘 붙잡으면 따라오는 사람이 사유별로 갈라져 코칭 순서가 정해집니다.
고객사 사내 AX 부트캠프를 맡아 코칭까지 직접 하는 솔루션 엔지니어 — 하루에 수백 건 채점 결과가 쌓이지만 점수만 봐서는 오늘 누구를 붙잡아야 하는지가 정해지지 않는다
통과 개수와 제출 코드에서 뽑아낸 개념, 오류 종류, 제출 시각을 과제 정의표와 기수 계획표에 맞추면 점수 하나로는 안 갈리던 막힘이 여섯 가지 사유로 나뉘고, 코치가 오늘 누구부터 붙잡을지 목록으로 받습니다.
제출 기록과 개념 판별표, 과제 정의표, 기수 계획표를 올리면 제출마다 코드 원문에서 실제로 쓴 개념을 뽑아 여섯 사유 중 하나를 정하고 통과율과 반복 횟수, 늦은 날수를 붙여 사유별로 묶어 보여 주는 관리자 페이지입니다. 제출 기록은 공개 실습 과제 양식으로 지원자가 직접 만들어 넣습니다.
제출물 600건에 손으로 매긴 정답 판정을 붙여 자동 판정과 대조하고 사유별 일치율과 어긋난 제출의 목록을 내며, 반 전체 통과율을 기수 목표와 나란히 보여 주는 단계입니다.
같은 사유가 몰린 과제를 찾아 문제 설명이 헷갈리는지 테스트가 지나친지 가려 커리큘럼 담당에게 넘기고, 걸린 제출마다 짚어 줄 대목을 커리큘럼 문서에서 찾아 코칭 문안 초안으로 붙이는 단계입니다.
솔루션 엔지니어가 제출 기록과 개념 판별표, 과제 정의표, 기수 계획표를 올리면 제출 코드에서 뽑은 개념과 함께 오늘 붙잡을 사람이 사유별로 묶여 화면에 나오는 과정을 시연합니다.
제출물 600건에 손으로 매긴 정답 판정을 붙여 대조하고 사유별 일치율을 냅니다. 단, 정답과 제출물을 모두 작성자가 만든 합성 기준이라 성능 검증이 아니라 데모 조건 동작입니다.
망가진 입력 30종을 먼저 통과시켜 봅니다. 걸린 시간이 비었거나 계획표에 없는 모듈이 붙었거나 코드가 문법에 어긋나 못 읽혀도 화면이 서고, 대조하지 못한 조건은 사유 자리 대신 hedge 로 내려갑니다.
통과 기준을 0.8 에서 0.7 로 내렸을 때 통과율 미달로 걸리는 제출이 몇 건 줄어드는지 회귀로 확인합니다.
여기서부터는 재지 않았습니다. 위 수치는 제가 만든 제출물을 제가 채점한 값이고, 수료율이 실제로 올랐는지는 엘리스가 운영하는 고객사 부트캠프의 실 제출 기록과 실 코치 판단을 넣어야 나옵니다. 그 측정을 붙이자마자 돌릴 수 있게 평가 러너와 정답 서식을 미리 갖춰 둡니다.
사유별 일치율은 제가 만든 제출물을 제가 채점한 값이라 성능 근거가 못 됩니다. 면접에서는 화면이 도는 범위와, 고객사 실 제출 기록이 오면 바로 재볼 수 있다는 준비 상태까지만 말합니다.
필수 개념 목록도 정답 판정도 제가 적었으니 맞아떨어지는 것이 당연합니다. 걸린 시간이 빈 제출과 자동 채점기 값이 코드와 갈리는 제출, 계획표에 없는 모듈까지 붙여 두어 점수가 깨끗한 제출만 통과시키는 목록이 되지 않게 했습니다.
이 포트폴리오는 제출 기록을 과제 정의와 맞춰 막힘을 사유로 가르는 기술을 보여줍니다. 교육학이나 학습 효과 측정 전문성은 주장하지 않습니다. 판정은 나눗셈과 목록 대조가 하고 모델은 코치가 읽을 문장만 맡습니다.
개념을 알아보는 기준이 판별표에 적어 둔 문법 요소라, 같은 개념을 다른 문법으로 쓴 제출은 못 잡습니다. 정렬을 sorted 없이 손으로 구현한 코드는 정렬을 안 쓴 것으로 걸립니다. 그래서 필수 개념 미사용은 확정이 아니라 코치가 코드를 열어 볼 후보로 냅니다.
실제 도입 때는 과제와 기수가 계속 늘어나므로, 필수 개념과 체크포인트를 커리큘럼 담당과 이어서 채우는 일을 운영 과제로 둡니다.
① 인라인 샘플 · ② seed.json 다운로드 · ③ 증강 프롬프트. 세 층 모두 동일한 schema 에서 파생.
고객사 부트캠프에서 하루에 쌓이는 제출 기록입니다. 제출 번호와 학습자 번호, 과제 번호, 통과한 테스트 수와 전체 테스트 수, LMS 자동 채점기가 적어 보낸 사용 개념 칸, 제출한 코드 원문, 오류 종류, 걸린 시간, 제출일을 한 줄에 둡니다. 개념을 실제로 썼는지는 자동 채점기 칸이 아니라 코드 원문에서 도구가 직접 뽑아 정하고, 자동 채점기 칸은 두 값이 갈리는지 보는 대조용으로만 둡니다. 지원자는 공개 실습 과제 양식으로 이 표를 스스로 만듭니다. 걸린 시간이 안 남은 줄과 통과가 하나도 없는 줄, 같은 개념을 띄어쓰기만 달리 적은 줄, 한 사람이 같은 과제를 세 번 다시 낸 묶음, 그리고 자동 채점기는 썼다고 적었는데 코드에는 그 문법이 없는 줄을 일부러 섞어 사유가 갈리게 둡니다.
| submission_no | learner_id | task_id | passed_tests | total_tests | used_concepts | error_type | elapsed_min | submitted_at | code_text |
|---|---|---|---|---|---|---|---|---|---|
| S-001 | L-1012 | task-14 | 3 | 10 | 리스트 컴프리헨션; 정렬 | AssertionError | 42 | 2026-09-07 | scores = [int(x) for x in raw.split(",… |
| S-002 | L-1027 | task-12 | 9 | 10 | 파일 입출력 | — | 46 | 2026-09-03 | f = open("data.txt") lines = f.readlin… |
| S-003 | L-1043 | task-09 | 4 | 10 | 반복문; 예외 처리 | TypeError | 22 | 2026-09-05 | total = 0 for row in rows: try: … |
| S-004 | L-1043 | task-09 | 5 | 10 | 반복문; 예외 처리 | TypeError | 31 | 2026-09-06 | total = 0 for row in rows: try: … |
| S-005 | L-1043 | task-09 | 6 | 10 | 반복문; 예외처리 | TypeError | 78 | 2026-09-07 | total = 0 for row in rows: try: … |
아래 JSON Schema 를 그대로 만족하는 제출 행을 600개 더 만들어 주세요. 학습자를 60명쯤 두고 과제는 과제 정의표에 있는 것에서 고르며 한 사람이 같은 과제를 두세 번 다시 내는 경우를 넉넉히 넣습니다. total_tests 는 6에서 12 사이, passed_tests 는 0 에서 total_tests 사이로 흩고 몇 행은 0 으로 둡니다. code_text 에는 그 과제를 푼 열 줄 안팎의 파이썬 코드를 실제로 돌아가는 문법으로 적되, 과제 정의표의 필수 개념 가운데 하나가 빠진 코드와 금지 이름을 그대로 부른 코드를 넉넉히 섞습니다. used_concepts 는 자동 채점기가 적어 보낸 칸이므로 code_text 를 보고 채우되, 세미콜론으로 이어 적고 같은 개념을 '예외 처리'와 '예외처리'처럼 띄어쓰기를 달리 쓴 행과 코드에는 없는 개념이 적힌 행을 1할쯤 섞어 두 값이 갈리는 경우가 나오게 합니다. error_type 은 통과한 제출이면 null 로 두고 막힌 제출은 TypeError·AssertionError 처럼 적으며 같은 사람이 같은 과제에서 같은 오류를 세 번 넘게 내는 묶음을 여럿 만듭니다. elapsed_min 은 5에서 180 사이로 두고 2할은 null 로 비웁니다. submitted_at 은 2026-08-20 에서 2026-09-10 사이로 흩습니다. 판정 결과나 막힌 사유는 넣지 마세요. 그리고 열이 하나 빠지거나 인코딩이 어긋난 CSV 를 5건 따로 만들어 읽기 실패가 어떻게 보고되는지 확인하게 합니다.
{"type": "object", "properties": {"submission_no": {"type": "string"}, "learner_id": {"type": "string"}, "task_id": {"type": "string"}, "passed_tests": {"type": "integer", "minimum": 0}, "total_tests": {"type": "integer", "minimum": 1}, "used_concepts": {"type": "string", "description": "LMS 자동 채점기가 적어 보낸 사용 개념 칸입니다. 참고로만 두고 판정에는 쓰지 않습니다."}, "code_text": {"type": "string", "description": "학습자가 제출한 코드 원문입니다. 개념은 이 원문에서 뽑습니다."}, "error_type": {"type": ["string", "null"]}, "elapsed_min": {"type": ["integer", "null"]}, "submitted_at": {"type": "string"}}, "required": ["submission_no", "learner_id", "task_id", "passed_tests", "total_tests", "used_concepts", "code_text", "error_type", "elapsed_min", "submitted_at"]}{"type": "object", "properties": {"submission_no": {"type": "string"}, "learner_id": {"type": "string"}, "task_id": {"type": "string"}, "passed_tests": {"type": "integer", "minimum": 0}, "total_tests": {"type": "integer", "minimum": 1}, "used_concepts": {"type": "string", "description": "LMS 자동 채점기가 적어 보낸 사용 개념 칸입니다. 참고로만 두고 판정에는 쓰지 않습니다."}, "code_text": {"type": "string", "description": "학습자가 제출한 코드 원문입니다. 개념은 이 원문에서 뽑습니다."}, "error_type": {"type": ["string", "null"]}, "elapsed_min": {"type": ["integer", "null"]}, "submitted_at": {"type": "string"}}, "required": ["submission_no", "learner_id", "task_id", "passed_tests", "total_tests", "used_concepts", "code_text", "error_type", "elapsed_min", "submitted_at"]}개념 이름 하나를 코드에서 무엇으로 알아볼지 적어 둔 판별표입니다. 규칙 번호와 개념 이름, 알아보는 방식, 찾을 이름을 한 줄에 둡니다. 방식은 네 가지입니다. 구문요소는 코드를 파이썬 문법 나무로 읽었을 때 그 종류의 마디가 있는지, 호출이름은 그 이름을 그대로 부른 호출이 있는지, 메서드이름은 점 뒤에 그 이름을 붙여 부른 호출이 있는지, 모듈이름은 import 로 들여온 이름이 그 모듈이거나 그 아래 하위 이름인지를 봅니다. ClassDef.bases 는 물려받은 클래스가 적힌 클래스 마디를 뜻합니다. 지원자는 파이썬 표준 라이브러리의 문법 나무 문서에 적힌 마디 이름 목록과 과제 정의표에 쓴 개념 이름을 나란히 놓고 개념 하나에 마디나 이름을 한둘씩 짝지어 이 표를 만듭니다. 한 개념에 방식이 여럿이면 줄을 나눠 적습니다.
| rule_no | concept_name | match_kind | match_token |
|---|---|---|---|
| CR-01 | 변수 | 구문요소 | Assign |
| CR-02 | 조건문 | 구문요소 | If |
| CR-03 | 반복문 | 구문요소 | For |
| CR-04 | 반복문 | 구문요소 | While |
| CR-05 | 예외 처리 | 구문요소 | Try |
아래 JSON Schema 를 그대로 만족하는 판별 규칙 행을 40개 더 만들어 주세요. 과제 정의표에 나오는 개념 이름마다 한 줄 이상을 두고, 같은 개념을 여러 문법으로 쓸 수 있으면 줄을 나눠 적습니다. match_kind 는 구문요소·호출이름·메서드이름·모듈이름 넷에서 고르고 match_token 은 파이썬 문법 나무의 마디 이름이나 실제 함수·메서드·모듈 이름으로 적습니다. 판별표에 줄이 하나도 없는 개념도 두세 개 남겨 두어, 요구 개념이 판별표에 없을 때 무엇이 보고되는지 보게 합니다. 판정이나 사유는 여기에 적지 마세요.
{"type": "object", "properties": {"rule_no": {"type": "string"}, "concept_name": {"type": "string"}, "match_kind": {"type": "string", "enum": ["구문요소", "호출이름", "메서드이름", "모듈이름"]}, "match_token": {"type": "string"}}, "required": ["rule_no", "concept_name", "match_kind", "match_token"]}{"type": "object", "properties": {"rule_no": {"type": "string"}, "concept_name": {"type": "string"}, "match_kind": {"type": "string", "enum": ["구문요소", "호출이름", "메서드이름", "모듈이름"]}, "match_token": {"type": "string"}}, "required": ["rule_no", "concept_name", "match_kind", "match_token"]}과제마다 무엇을 가르치려는지 적어 둔 과제 정의표입니다. 과제 번호와 모듈, 반드시 써야 할 개념, 통과 기준, 예상 소요 시간, 목적을 건너뛰는 금지 이름을 한 줄에 둡니다. 개념과 금지 이름은 여러 개일 때 세로줄로 이어 적습니다. 지원자는 공개된 파이썬 입문 커리큘럼과 온라인 실습 사이트가 과제마다 걸어 둔 학습 목표·통과 기준을 옮겨 적고, 금지 이름은 그 사이트들이 제출 검사에서 막는 함수 목록에서 가져와 이 표를 만듭니다. 기수 계획표에 없는 모듈에 붙은 과제도 한 줄 두어 기한을 견줄 곳이 없는 상황이 나오게 합니다.
| task_id | module_id | required_concepts | pass_threshold | expected_minutes | banned_shortcut |
|---|---|---|---|---|---|
| task-04 | M-01 | 변수|조건문 | 0.7 | 25 | eval |
| task-07 | M-01 | 조건문|반복문 | 0.75 | 30 | eval |
| task-09 | M-02 | 반복문|예외 처리 | 0.8 | 40 | eval|exec |
| task-12 | M-02 | 예외 처리|파일 입출력 | 0.8 | 50 | eval|exec |
| task-14 | M-03 | 리스트 컴프리헨션|정렬 | 0.8 | 35 | eval |
아래 JSON Schema 를 그대로 만족하는 과제 정의 행을 40개 더 만들어 주세요. 모듈은 M-01 부터 M-12 까지 두고 과제 하나가 모듈 하나에 붙게 합니다. required_concepts 는 세로줄로 이어 두세 개씩 적고 pass_threshold 는 0.6 에서 0.9 사이, expected_minutes 는 20에서 90 사이로 둡니다. banned_shortcut 에는 eval·exec 처럼 과제 목적을 건너뛰는 이름을 세로줄로 적습니다. 기수 계획표에 없는 모듈에 붙은 과제도 두세 개 넣어 기한을 견줄 곳이 없는 경우가 나오게 합니다.
{"type": "object", "properties": {"task_id": {"type": "string"}, "module_id": {"type": "string"}, "required_concepts": {"type": "string"}, "pass_threshold": {"type": "number"}, "expected_minutes": {"type": "integer"}, "banned_shortcut": {"type": "string"}}, "required": ["task_id", "module_id", "required_concepts", "pass_threshold", "expected_minutes", "banned_shortcut"]}{"type": "object", "properties": {"task_id": {"type": "string"}, "module_id": {"type": "string"}, "required_concepts": {"type": "string"}, "pass_threshold": {"type": "number"}, "expected_minutes": {"type": "integer"}, "banned_shortcut": {"type": "string"}}, "required": ["task_id", "module_id", "required_concepts", "pass_threshold", "expected_minutes", "banned_shortcut"]}고객사 기수마다 모듈을 언제까지 끝내기로 했는지 적은 계획표입니다. 계획 번호와 고객사, 모듈, 담당 코치, 체크포인트 날짜, 반 목표 통과율을 한 줄에 둡니다. 지원자는 공개된 기업 교육 과정 안내문에 실린 주차별 일정표에서 모듈마다 언제까지 끝내는지를 옮겨 적고, 반 목표 통과율은 교육 위탁 계약 공고에 적힌 수료 기준을 그대로 가져와 이 표를 만듭니다. 제출일이 체크포인트를 넘겼는지와 반 전체가 목표에 못 미치는지를 이 표로 견줍니다. 과제가 붙지 않은 모듈도 담아 두어 계획이 판정보다 넓게 깔리게 합니다.
| plan_no | client_id | module_id | coach_id | checkpoint_date | target_pass_rate |
|---|---|---|---|---|---|
| CP-01 | ACME | M-01 | C-01 | 2026-08-28 | 0.85 |
| CP-02 | ACME | M-02 | C-01 | 2026-09-04 | 0.85 |
| CP-03 | ACME | M-03 | C-02 | 2026-09-05 | 0.8 |
| CP-04 | ACME | M-04 | C-02 | 2026-09-11 | 0.8 |
| CP-05 | ACME | M-05 | C-03 | 2026-09-18 | 0.75 |
아래 JSON Schema 를 그대로 만족하는 기수 계획 행을 30개 더 만들어 주세요. 고객사를 대여섯 곳 두고 모듈마다 담당 코치와 체크포인트 날짜, 반 목표 통과율을 적습니다. checkpoint_date 는 2026-08-20 에서 2026-10-10 사이로 두고 target_pass_rate 는 0.7 에서 0.9 사이로 둡니다. 같은 모듈을 두 고객사가 서로 다른 날짜로 잡은 경우도 몇 줄 넣어 계획이 겹칠 때 무엇이 보고되는지 보게 합니다.
{"type": "object", "properties": {"plan_no": {"type": "string"}, "client_id": {"type": "string"}, "module_id": {"type": "string"}, "coach_id": {"type": "string"}, "checkpoint_date": {"type": "string"}, "target_pass_rate": {"type": "number"}}, "required": ["plan_no", "client_id", "module_id", "coach_id", "checkpoint_date", "target_pass_rate"]}{"type": "object", "properties": {"plan_no": {"type": "string"}, "client_id": {"type": "string"}, "module_id": {"type": "string"}, "coach_id": {"type": "string"}, "checkpoint_date": {"type": "string"}, "target_pass_rate": {"type": "number"}}, "required": ["plan_no", "client_id", "module_id", "coach_id", "checkpoint_date", "target_pass_rate"]}| Python | 제출 코드를 문법 나무로 읽어 실제로 쓴 개념을 뽑고, 그것을 과제 정의표·기수 계획표와 맞춰 제출마다 막힌 사유를 정하는 추출기와 판정 엔진을 맡습니다. |
| Next.js | 사유별로 묶은 목록과 제출 하나를 펼쳐 보는 상세를 그리는 관리자 페이지를 맡습니다. |
| Evaluation harness | 2주차에 손으로 매긴 정답 판정과 자동 판정을 대조해 사유별 일치율을 내는 평가 러너로 씁니다. |
| RAG | 3주차에 걸린 제출마다 그 과제의 커리큘럼 문서에서 짚어 줄 대목을 찾아 코칭 문안 초안에 붙입니다. |
| vLLM | 3주차에 코칭 문안 초안을 만드는 오픈웨이트 모델을 띄워 하루치 수백 건을 한 번에 돌립니다. |
✗ fail → 정의가 없는 과제나 판별표에 줄이 없는 개념이 절반을 넘으면 커리큘럼 쪽에서 먼저 받아 채웁니다.
✓ pass → 2주차 정답 대조로 넘어갑니다.
✗ fail → 어긋난 제출을 모아 개념 판별표의 짝과 반복 세는 기준을 다시 봅니다.
✓ pass → 3주차 과제별 함정 찾기와 코칭 문안으로 넘어갑니다.
위 예측 UI 는 3주차까지 완주했을 때의 화면입니다. 1주차에 실제로 만드는 것은 아래 표시된 화면 하나입니다.
block_reason사유 라벨 · submission_no + 한 줄 요약(근거 수치 포함)화면·코드·면접에서 이 단어를 그대로 씁니다. 키는 출력 스키마의 enum 과 같습니다.
목표대로 통과통과필수 개념 미사용개념 빠짐테스트 통과율 미달통과율 미달같은 오류 반복같은 오류 반복지름길 사용지름길체크포인트 기한 넘김기한 넘김제출 하나마다 커리큘럼 목표에 견줘 어디서 막혔는지 정합니다. 막혔으면 필수 개념·통과율·같은 오류 반복·지름길·체크포인트 기한 중 어느 쪽인지 싣고, 통과율과 반복 횟수, 늦은 날수를 함께 냅니다. 제출 코드에서 뽑아낸 개념 목록도 함께 실어 화면의 묶음이 이 사유를 따릅니다.
{"type": "object", "properties": {"verdict_no": {"type": "string"}, "submission_no": {"type": "string"}, "learner_id": {"type": "string"}, "task_id": {"type": "string"}, "module_id": {"type": ["string", "null"]}, "block_reason": {"type": "string", "enum": ["목표대로 통과", "필수 개념 미사용", "테스트 통과율 미달", "같은 오류 반복", "지름길 사용", "체크포인트 기한 넘김"]}, "pass_rate": {"type": ["number", "null"], "description": "passed_tests 를 total_tests 로 나눠 소수 둘째 자리까지 남긴 통과율입니다."}, "repeat_count": {"type": ["integer", "null"], "description": "같은 learner_id 와 task_id 에서 같은 error_type 이 그 제출까지 쌓인 횟수입니다. 오류 없이 통과한 제출은 null 입니다."}, "late_days": {"type": ["integer", "null"], "description": "submitted_at 이 그 모듈의 checkpoint_date 를 넘긴 날수입니다. 기한 안에 낸 제출과 계획표에 그 모듈이 없는 제출은 null 입니다."}, "detected_concepts": {"type": ["string", "null"], "description": "제출 코드에서 뽑은 개념을 판별표 차례대로 겹치지 않게 세미콜론으로 이어 적은 값입니다. 코드를 문법 나무로 못 읽으면 비웁니다."}, "flagged_concept": {"type": ["string", "null"], "description": "필수 개념 미사용이면 빠진 개념, 지름길 사용이면 걸린 이름을 적습니다."}, "evidence": {"type": "array", "items": {"type": "object", "properties": {"field": {"type": "string"}, "agg": {"type": ["string", "null"]}, "value": {}}, "required": ["field", "value"]}}, "summary": {"type": "string"}, "hedge": {"type": ["string", "null"]}}, "required": ["verdict_no", "submission_no", "learner_id", "task_id", "block_reason", "evidence", "summary"]}[
{
"verdict_no": "OV-001",
"submission_no": "S-007",
"learner_id": "L-1068",
"task_id": "task-04",
"module_id": "M-01",
"block_reason": "목표대로 통과",
"pass_rate": 1,
"repeat_count": null,
"late_days": null,
"flagged_concept": null,
"evidence": [
{
"field": "passed_tests",
"agg": null,
"value": 10
},
{
"field": "pass_threshold",
"agg": null,
"value": 0.7
}
],
"summary": "열 개 테스트를 다 통과했고 변수와 조건문을 모두 써서 이 제출은 코칭 목록에 올리지 않습니다.",
"hedge": null,
"detected_concepts": "변수; 조건문"
},
{
"verdict_no": "OV-002",
"submission_no": "S-010",
"learner_id": "L-1027",
"task_id": "task-25",
"module_id": "M-05",
"block_reason": "목표대로 통과",
"pass_rate": 0.75,
"repeat_count": null,
"late_days": null,
"flagged_concept": null,
"evidence": [
{
"field": "passed_tests",
"agg": null,
"value": 6
},
{
"field": "pass_threshold",
"agg": null,
"value": 0.75
}
],
"summary": "여덟 개 중 여섯 개를 통과해 기준과 똑같은 자리라 통과로 넘기지만 다음 과제에서 다시 볼 사람입니다.",
"hedge": "테스트 하나만 더 틀렸으면 미달로 갈렸으니 반 평균과 함께 읽습니다.",
"detected_concepts": "변수; 판다스 데이터프레임; 결측 처리"
},
{
"verdict_no": "OV-003",
"submission_no": "S-002",
"learner_id": "L-1027",
"task_id": "task-12",
"module_id": "M-02",
"block_reason": "필수 개념 미사용",
"pass_rate": 0.9,
"repeat_count": null,
"late_days": null,
"flagged_concept": "예외 처리",
"evidence": [
{
"field": "required_concepts",
"agg": null,
"value": "예외 처리|파일 입출력"
},
{
"field": "code_text",
"agg": null,
"value": "f = open(\"data.txt\")\nlines = f.readlines()\nf.close()\nprint(len(lines))\n"
}
],
"summary": "테스트는 아홉 개나 통과했는데 제출 코드 어디에도 try 가 없어, 이 과제가 가르치려던 예외 처리를 한 번도 쓰지 않았습니다.",
"hedge": null,
"detected_concepts": "변수; 파일 입출력"
},
{
"verdict_no": "OV-004",
"submission_no": "S-001",
"learner_id": "L-1012",
"task_id": "task-14",
"module_id": "M-03",
"block_reason": "테스트 통과율 미달",
"pass_rate": 0.3,
"repeat_count": 1,
"late_days": 2,
"flagged_concept": null,
"evidence": [
{
"field": "passed_tests",
"agg": null,
"value": 3
},
{
"field": "pass_threshold",
"agg": null,
"value": 0.8
}
],
"summary": "열 개 중 세 개만 통과해 기준 0.8 에 한참 못 미치니 오늘 먼저 붙잡을 사람입니다.",
"hedge": "체크포인트도 이틀 넘겼지만 지금 급한 것은 통과율이라 그쪽 사유로 세웠습니다.",
"detected_concepts": "변수; 리스트 컴프리헨션; 정렬"
},
{
"verdict_no": "OV-005",
"submission_no": "S-005",
"learner_id": "L-1043",
"task_id": "task-09",
"module_id": "M-02",
"block_reason": "같은 오류 반복",
"pass_rate": 0.6,
"repeat_count": 3,
"late_days": 3,
"flagged_concept": null,
"evidence": [
{
"field": "error_type",
"agg": "count",
"value": 3
},
{
"field": "elapsed_min",
"agg": null,
"value": 78
},
{
"field": "expected_minutes",
"agg": null,
"value": 40
}
],
"summary": "같은 TypeError 로 세 번째 막혔고 마지막 제출에 78분을 썼으니 혼자 더 붙들게 두지 않습니다.",
"hedge": null,
"detected_concepts": "변수; 반복문; 예외 처리"
},
{
"verdict_no": "OV-006",
"submission_no": "S-006",
"learner_id": "L-1055",
"task_id": "task-15",
"module_id": "M-03",
"block_reason": "지름길 사용",
"pass_rate": 0.8,
"repeat_count": null,
"late_days": 2,
"flagged_concept": "eval",
"evidence": [
{
"field": "banned_shortcut",
"agg": null,
"value": "eval|exec"
},
{
"field": "code_text",
"agg": null,
"value": "def rank(items):\n return sorted(items, key=lambda x: -x)\n\ndata = eval(user_input)\nprint(rank(data))\n"
}
],
"summary": "정렬을 직접 구현하는 과제인데 eval 로 건너뛰어 테스트가 통과해도 배운 것이 남지 않습니다.",
"hedge": "체크포인트도 이틀 넘겼으니 코칭할 때 함께 짚습니다.",
"detected_concepts": "변수; 정렬; 함수 정의; eval"
},
{
"verdict_no": "OV-007",
"submission_no": "S-009",
"learner_id": "L-1012",
"task_id": "task-07",
"module_id": "M-01",
"block_reason": "체크포인트 기한 넘김",
"pass_rate": 0.8,
"repeat_count": null,
"late_days": 4,
"flagged_concept": null,
"evidence": [
{
"field": "submitted_at",
"agg": null,
"value": "2026-09-01"
},
{
"field": "checkpoint_date",
"agg": null,
"value": "2026-08-28"
}
],
"summary": "통과 기준은 넘겼지만 체크포인트보다 나흘 늦게 내 다음 모듈 일정이 그만큼 밀립니다.",
"hedge": "걸린 시간이 안 남아 늦은 이유가 난이도인지 결석인지는 이 표로 갈리지 않습니다.",
"detected_concepts": "변수; 조건문; 반복문"
},
{
"verdict_no": "OV-008",
"submission_no": "S-012",
"learner_id": "L-1071",
"task_id": "task-30",
"module_id": "M-11",
"block_reason": "목표대로 통과",
"pass_rate": 0.9,
"repeat_count": null,
"late_days": null,
"flagged_concept": null,
"evidence": [
{
"field": "passed_tests",
"agg": null,
"value": 9
},
{
"field": "pass_threshold",
"agg": null,
"value": 0.75
}
],
"summary": "열 개 중 아홉 개를 통과했고 시각화와 집계를 모두 써서 통과로 넘깁니다.",
"hedge": "이 과제가 붙은 M-11 은 기수 계획표에 줄이 없어 기한은 견주지 못했습니다.",
"detected_concepts": "변수; 시각화; 집계"
},
{
"verdict_no": "OV-009",
"submission_no": "S-013",
"learner_id": "L-1055",
"task_id": "task-12",
"module_id": "M-02",
"block_reason": "필수 개념 미사용",
"pass_rate": 0.9,
"repeat_count": null,
"late_days": null,
"detected_concepts": "변수; 반복문; 파일 입출력",
"flagged_concept": "예외 처리",
"evidence": [
{
"field": "required_concepts",
"agg": null,
"value": "예외 처리|파일 입출력"
},
{
"field": "used_concepts",
"agg": null,
"value": "예외 처리; 파일 입출력"
},
{
"field": "code_text",
"agg": null,
"value": "with open(\"input.txt\") as f:\n lines = f.readlines()\ncounts = {}\nfor line in lines:\n key = line.strip()\n counts[key] = counts.get(key, 0) + 1\nprint(counts)\n"
}
],
"summary": "파일을 열어 줄을 세는 데까지는 갔지만 예외 처리가 코드에 없어, 입력이 어긋나는 순간 그대로 멈추는 제출입니다.",
"hedge": "자동 채점기가 보낸 사용 개념 칸에는 예외 처리가 적혀 있는데 코드에는 try 가 없어, 코드에서 뽑은 목록을 따랐습니다."
}
][자동 검증 · 코드가 판정합니다] 1. block_reason 이 enum 여섯 값 중 하나인지 확인합니다. 2. verdict_no·submission_no·learner_id·task_id·block_reason·evidence·summary 가 모두 채워졌는지 확인합니다. 3. submission_no 가 제출 기록에 실재하는 번호인지 대조하고, module_id 가 그 과제 정의의 값과 같은지 확인합니다. 4. pass_rate 를 passed_tests 를 total_tests 로 나눠 소수 둘째 자리까지 다시 계산합니다. 5. code_text 를 파이썬 문법 나무로 읽어 이 제출이 실제로 쓴 개념을 뽑습니다. 개념 판별표의 줄마다 match_kind 가 구문요소이면 match_token 과 같은 종류의 마디가 코드에 있는지, 호출이름이면 그 이름을 그대로 부른 호출이 있는지, 메서드이름이면 점 뒤에 그 이름을 붙여 부른 호출이 있는지, 모듈이름이면 import 로 들여온 이름이 그 모듈이거나 그 아래 하위 이름인지 봅니다. ClassDef.bases 는 물려받은 클래스가 적힌 클래스 마디를 뜻합니다. 걸린 줄의 concept_name 을 판별표 차례대로 겹치지 않게 이어 detected_concepts 를 만듭니다. 코드를 문법 나무로 못 읽으면 detected_concepts 를 비우고 그 사실을 hedge 에 적습니다. 6. detected_concepts 에 banned_shortcut 을 세로줄로 나눈 이름이 하나라도 있으면 block_reason 이 지름길 사용이고 flagged_concept 이 그 이름인지 확인합니다. 7. required_concepts 를 세로줄로 나눠 띄어쓰기와 대소문자를 접은 뒤 detected_concepts 와 맞춰 하나라도 빠지면 block_reason 이 필수 개념 미사용이고 flagged_concept 이 그 개념인지 확인합니다. LMS 자동 채점기가 적어 보낸 used_concepts 는 판정에 쓰지 않고, required_concepts·banned_shortcut 에 적힌 이름에서 detected_concepts 와 갈리면 그 사실만 hedge 에 적습니다. 8. repeat_count 를 같은 learner_id 와 task_id 에서 같은 error_type 이 그 제출까지 쌓인 횟수로 다시 세고, 3 이상이면 block_reason 이 같은 오류 반복인지 확인합니다. error_type 이 비어 있으면 repeat_count 는 null 입니다. 9. pass_rate 가 pass_threshold 보다 작으면 block_reason 이 테스트 통과율 미달인지 확인합니다. 10. late_days 를 submitted_at 에서 그 모듈의 checkpoint_date 를 뺀 날수로 다시 계산하고, 0 보다 크면 block_reason 이 체크포인트 기한 넘김인지 확인합니다. 다만 계획표에 그 모듈이 없으면 late_days 는 null 이고 이 조건은 건너뜁니다. 11. 사유가 둘 이상 걸리면 지름길 사용·필수 개념 미사용·같은 오류 반복·테스트 통과율 미달·체크포인트 기한 넘김 순으로 앞선 것 하나만 세웁니다. 앞의 둘은 점수가 좋아도 배운 것이 안 남은 자리라 먼저 두고, 가운데 둘은 혼자서는 못 넘는 막힘이라 그다음에, 일정은 마지막에 둡니다. 같은 오류를 세 번 낸 제출은 통과율도 대개 낮으므로 이 차례가 없으면 두 사유가 갈립니다. block_reason 이 목표대로 통과이면 위 다섯 조건 어디에도 안 걸리는지 다시 확인합니다. 12. elapsed_min 이 비어 있거나 계획표에 그 모듈이 없으면 그 사실이 hedge 에 적혔는지 확인합니다. 13. evidence 의 field 이름이 제출 기록·개념 판별표·과제 정의·기수 계획에 실재하는 컬럼인지 대조합니다. 14. agg 가 없는 evidence 의 value 가 그 컬럼에 수록된 행 값과 같은지 확인합니다. 15. summary 가 존댓말로 끝나는지 확인합니다. [평가 러너 · 2주차] 공개 실습 과제 양식으로 만든 제출물 600건에 손으로 매긴 정답 판정을 붙여 대조하고, 사유별 일치율과 어긋난 제출의 목록을 냅니다. 개념을 뽑아낸 결과가 손으로 읽은 것과 다른 제출은 따로 모아 판별표에 줄을 더할지 정합니다. [수동 검증 · 사람이 봅니다] 1. 오늘 코칭 순서는 솔루션 엔지니어가 사유별 목록을 보고 정합니다. 2. 과제마다 필수 개념과 금지 이름이 맞는지, 개념 하나를 어느 문법으로 알아볼지는 커리큘럼 담당과 맞춰 갱신합니다.