Sandcorp샌드코프 · 웹·AI 제품 개발

새 프로젝트 받는 중 · 갱신 2026.11sandcorp.co.krGitHub

← 기록

Codemit서비스 설계AI 채점약관제품 기획

통과/미통과만으로는 줄을 세울 수 없다 — Codemit 「완성도」를 설계한 과정

필수 항목 달성률만 세면 잘 만든 제출물끼리 전부 동점이 됩니다. 새 기준을 만들지 않고 있던 체크리스트를 항목마다 0~5로 다시 매기는 「완성도」를 만들면서, 계산·재채점·공개 범위·약관 시행·이름 충돌을 어떻게 정했는지 적었습니다.

통과/미통과만으로는 줄을 세울 수 없다

Codemit 「완성도」를 설계한 과정

배경 — 「통과」는 모두 같은 「통과」였습니다

Codemit은 코딩 과제를 AI가 채점하는 서비스입니다. 두 곳에서 쓰입니다. 클래스에서는 강사가 문제를 내고 참여자가 풀어 제출하며, 공모전에서는 개최자가 요구사항을 걸고 참가자가 작품을 냅니다. 두 곳 모두 문제마다 체크리스트가 있고, AI는 제출물이 각 항목을 「충족했는지」를 판정합니다. 클래스의 「통과」와 공모전의 점수(필수 항목 달성률)는 모두 이 충족 판정에서 나옵니다.

충족 판정은 「됐다/안 됐다」를 가르는 데는 잘 맞습니다. 그런데 강사와 개최자가 실제로 궁금한 것은 그다음이었습니다. 통과한 사람들 가운데 누가 더 잘 만들었는가. 이 글은 그 질문에 답하려고 「완성도」라는 기능을 설계한 기록입니다. 기능 자체보다, 점수 하나를 새로 만들 때 함께 정해야 했던 것들(계산 규칙, 다시 채점할 범위, 누가 보는지, 약관, 이름)을 중심으로 적었습니다.

무엇이 문제였나

증상 — 상위권이 전부 동점

필수 항목을 모두 충족한 제출물은 달성률이 똑같이 100%입니다. 클래스에서 「통과」한 참여자도 모두 같은 「통과」입니다. 과제를 잘 낸 사람이 많을수록 맨 위에 같은 점수가 길게 쌓이고, 그 안에서는 순서를 매길 수 없었습니다.

원인 — 판정이 「얼마나 잘」을 묻지 않습니다

충족 판정은 항목마다 예/아니오만 남깁니다. 로그인을 「오류 처리까지 갖춰」 만든 제출과 「겨우 돌아가게」 만든 제출이 같은 「충족」입니다. 선택 항목은 아예 달성률에 들어가지 않습니다. 정보가 처음부터 버려지고 있었으니, 그 결과를 아무리 다시 세어도 차이가 생기지 않습니다.

하지 말아야 할 것도 분명했습니다

이미 쓰이는 점수(달성률·통과·분포)는 공모전 심사와 상금 배분에 묶여 있습니다. 새 점수를 만들면서 이 점수의 뜻이나 계산이 한 줄이라도 바뀌면, 이미 끝난 공모전의 결과가 흔들립니다. 그래서 처음부터 새 점수는 별도 기록이고, 기존 점수는 건드리지 않는다를 고정 조건으로 두었습니다.

고른 방법 — 있던 체크리스트를 0~5로 다시 매긴다

새 기준을 만들지 않았습니다

가장 먼저 떠오른 방법은 「품질 평가 기준표」를 따로 만드는 것이었습니다. 버렸습니다. 강사와 개최자가 문제마다 기준을 두 벌씩 관리해야 하고, 두 기준이 어긋나면 「통과는 했는데 품질 기준으로는 엉망」 같은 설명하기 어려운 결과가 나옵니다.

대신 이미 있는 체크리스트 항목을 그대로 씁니다. 다만 묻는 것을 바꿉니다. 「충족했나」가 아니라 「얼마나 잘 했나」를 항목마다 0~5 정수로, 근거와 함께 AI가 매깁니다. 필수·선택 항목 모두 매기고, 가중치는 필수 2, 선택 1입니다.

  • 가중 점수 = Σ(가중치 × 항목 점수)
  • 완성도(0~100) = 가중 점수 ÷ (5 × Σ가중치) × 100, 화면에는 소수 첫째 자리까지

문법 검사처럼 체크리스트 행이 아닌 판정은 넣지 않았습니다. 파서가 내리는 예/아니오라 「얼마나 잘」이 없기 때문입니다.

절대 점수, 정수로 줄 세우기, 같은 점수는 같은 등수

  • 제출마다 절대 점수입니다. 제출물끼리 견주어 매기는 상대 평가는 버렸습니다. 상대 평가는 제출이 하나 늘 때마다 다른 사람 점수까지 흔들고, 그러면 아래에서 말할 「바뀐 사람만 다시 채점」을 할 수 없습니다.
  • 등수는 정수인 가중 점수로 매깁니다. 화면의 소수 첫째 자리 값으로 줄을 세우면 반올림 때문에 다른 점수가 같아 보일 수 있습니다. 동점을 줄이려고 만든 기능에서 표시값이 동점을 만들면 안 됩니다.
  • 그래도 같으면 같은 등수입니다(1, 2, 2, 4). 억지로 순서를 만들지 않습니다.
  • AI 응답이 0~5 정수가 아니거나 항목이 빠지면 그 채점은 실패로 칩니다. 빈칸을 평균이나 0으로 채워 넣지 않습니다.

계산은 클래스와 공모전이 같은 공용 함수 하나를 씁니다. 두 곳의 완성도가 다른 규칙으로 계산되는 일을 구조로 막았습니다. 제출물(소스·설명)은 신뢰하지 않는 데이터로 감싸 프롬프트에 넣습니다. 제출물 안에 「이 항목은 5점」 같은 문장을 써 넣어 점수를 끌어올리는 시도를 막기 위해서입니다.

클래스에서 완성도가 매겨지는 길

  1. 대상 고르기

    문제마다 참여자별 가장 최근 「통과」 시도 하나입니다. 한 번도 통과하지 못한 사람은 순위에 없습니다.

  2. 비용 확인

    강사가 「완성도 채점」을 누르면 「새로 채점할 n명 · 예상 비용」을 먼저 보여 줍니다.

  3. 채점

    확인하면 큐에 넣고, 기존 판정 채점과 같은 동시성 상한을 나눠 씁니다.

  4. 순위표

    등수·완성도·항목별 0~5가 나오고, 펼치면 근거가 보입니다.

  5. 다시 누르면

    대상 시도나 체크리스트가 바뀐 사람만 다시 채점하고, 나머지는 이전 점수를 씁니다.

정한 것과 버린 대안

정할 것고른 것버린 대안과 이유
기준있던 체크리스트를 0~5로새 품질 기준표 — 기준이 두 벌이 되고 서로 어긋납니다
점수 성격제출마다 절대 점수제출끼리 견주는 상대 평가 — 하나가 늘면 모두 흔들려 부분 재채점을 할 수 없습니다
등수 기준정수인 가중 점수화면 표시값(소수 첫째 자리) — 반올림이 동점을 만듭니다
클래스 재채점바뀐 사람만매번 전원 — 강사가 내는 비용이 매번 다시 듭니다
공개참여자는 자기 것만순위표 전체 공개 — 다른 사람 이름·점수가 드러나고 위화감이 생깁니다
공모전 쓰임개최자 참고용추천작 자동 선정 — 선정과 상금은 개최자가 정합니다
  • 어떤 경우에도 기존 달성률·통과·분포의 뜻과 계산은 바꾸지 않았습니다.

누가 보는가 — 점수보다 먼저 정한 것

점수가 생기면 누군가는 남의 점수를 보고 싶어집니다. 그래서 계산만큼 공개 범위에 시간을 썼습니다.

클래스

기본은 강사만 봅니다. 채점도 강사가 버튼으로 돌리고, 비용은 그 클래스에 연결된 강사의 채점 키에서 나갑니다. 그래서 누르기 전에 「새로 채점할 n명 · 예상 비용」을 먼저 보여 줍니다. 새로 채점할 사람이 없으면 버튼이 할 일이 없다고 알려 줍니다.

강사가 문제마다 「참여자에게 공개」를 켜면 참여자도 볼 수 있습니다. 다만 자기 것만 봅니다. 「완성도 순위 k등 / N명」, 자기 완성도, 항목별 점수와 근거까지입니다. 다른 참여자의 이름과 점수는 보이지 않습니다. 공개가 꺼져 있으면 참여자에게 가는 응답에 완성도 칸이 아예 없습니다. 「값은 보내고 화면에서 숨기기」는 하지 않았습니다.

공모전

공모전은 마감 뒤 판정 점수가 생긴 제출에 자동으로 한 번 매깁니다. 판정 흐름은 한 줄도 고치지 않고, 「점수는 있는데 완성도가 없는 제출」을 집는 스캔을 따로 1분마다 돌립니다. 입력이 없거나 판정이 실패한 제출은 건너뜁니다. 실패하면 이력을 남기고 다섯 번 또는 영구 실패에서 멈추며, 대체값을 지어내지 않습니다. 완성도 채점에는 판정 때 본 근거를 그대로 실어, 저장소를 한 번 더 내려받지 않습니다.

개최자는 심사 화면에서 모든 제출작의 완성도와 등수를 보고 「완성도순」으로 정렬할 수 있습니다. 제출자는 자기 완성도와 항목별 근거를 봅니다. 등수는 보여 주지 않습니다. 등수는 남과 견준 값이기 때문입니다.

쓰지 않는 곳

완성도는 AI의 참고 의견입니다. 추천작을 뽑지 않고, 수상작 선정이나 상금 배분의 근거로 쓰지 않으며, 이의 제기 대상도 아닙니다. 이의는 지금처럼 충족 여부 판정에만 겁니다.

부딪힌 문제와 해결

약관에는 공지 기간이 있었습니다

증상 — 기능은 다 만들었는데 약관이 걸렸습니다. 약관에는 「AI 채점은 충족 여부 판정이며 품질·가치를 보증하지 않는다」는 조항과, 누가 무엇을 보는지 적은 조항이 있습니다. 완성도는 둘 다에 닿습니다.

원인 — 약관을 바꿀 때는 시행 7일 전부터 화면에 공지해야 한다는 규정이 있습니다. 약관에는 「지금 운영하지 않는 기능은 적지 않는다」는 원칙도 있어서, 기능보다 약관을 먼저 바꿀 수도 없었습니다.

해결 — 기능은 그대로 내보내고, 약관은 시행일을 상수로 두고 「병합일 + 7일」에 시행하기로 했습니다. 회원에게 불리한 개정이 아니라고 보아 30일이 아니라 7일 공지를 따랐습니다. 새 약관에는 완성도도 AI의 참고 의견이며 보증하지 않고, 선정·상금의 근거나 이의 대상이 아니라는 문장과, 누가 무엇을 보는지를 더했습니다.

시행일에 맞춰 다시 배포하고 싶지 않았습니다

증상 — 시행일 전에는 「개정 예정」을 띄우고 시행일부터는 내려야 하는데, 그날 누군가 배포 버튼을 눌러야 한다면 잊기 쉽습니다.

해결 — 서버가 페이지를 그리는 순간의 한국 시간 날짜를 시행일 상수와 견줍니다. 시행일 전날 자정 직전까지는 머리에 「개정 예정 · 시행일 …」이, 당일 0시부터는 「시행일 …」만 나옵니다. 페이지가 빌드 때 정적으로 굳어 버리면 날짜가 바뀌지 않으니, 요청마다 그려지는지도 확인했습니다. 날짜를 넣어 보는 시험 다섯 개(시행일 전, 자정 직전, 당일 0시, 이후 등)로 고정했습니다.

「완성도」라는 이름이 이미 있었습니다

증상 — 공모전 제출 폼에는 이미 「완성도 N%」가 있었습니다. 근거 연결, 데모 영상, 테스트 계정이 얼마나 채워졌는가를 세는 지표입니다. 새 완성도는 얼마나 잘 했는가입니다. 같은 말이 다른 두 뜻으로 화면에 나오게 됐습니다.

원인 — 새 개념의 이름을 고를 때 「루브릭」은 채점 지침과, 「점수·평가」는 기존 판정 점수와 헷갈려 피했습니다. 그렇게 남은 「완성도」가 옛 지표의 화면 문구와 겹친 것입니다.

해결 — 새 기능이 「완성도」를 갖고, 옛 지표는 **「채움률」**로 바꾸기로 했습니다. 「근거 충족률」도 후보였지만 버렸습니다. 이 지표에는 근거 말고도 데모·영상·테스트 계정이 들어가고, 「충족」은 체크리스트 판정(충족/미충족)과 또 겹칩니다. 바꾸는 것은 화면 문구·주석·문서뿐입니다. API 필드 이름은 코드에서 이미 옛 지표와 새 완성도가 다른 이름으로 갈려 있어 헷갈리지 않고, 바꾸면 API를 쓰는 쪽이 깨지기 때문입니다.

우연히 같았던 날짜 둘

증상 — 완성도 채점도 같은 제출물을 같은 AI 회사로 보내니, 개인정보 처리방침의 국외 이전 목적에 「완성도 채점」을 더해야 했습니다. 그런데 방침 시행일 상수를 옮기려고 보니, 다른 기능이 열리는 날짜도 같은 값을 기준으로 삼고 있었고 둘이 같아야 한다고 시험이 묶고 있었습니다.

원인 — 두 날짜는 뜻이 다릅니다(방침 개정일, 기능을 여는 날). 처음 정할 때 우연히 같은 날이었을 뿐인데 시험이 그 우연을 규칙으로 굳혀 두었습니다. 그대로 옮기면 열리기로 한 기능이 다시 잠깁니다.

해결 — 기능이 여는 날짜는 그대로 두고, 시험이 지키는 값을 「그 기능과 관련된 개정의 시행일」로 좁혀 두 날짜를 떼기로 했습니다. 상수를 바꾸기 전에 그 상수를 읽는 곳을 전부 찾아보는 것이 이번에 얻은 습관입니다.

결과

  • 클래스: 강사 제출 현황 화면에 「완성도 채점」 버튼과 「완성도 순위」 표가 생겼습니다. 버튼 → 비용 확인 → 채점 → 순위표 흐름을 브라우저 시험으로 고정했고, 다시 누르면 바뀐 사람만 채점되는지, 공개를 켜기 전엔 참여자 응답에 완성도가 없는지도 시험으로 지킵니다.
  • 공모전: 마감 뒤 완성도가 자동으로 생기고, 심사 화면에 「완성도순」 정렬이 생겼습니다. 백엔드 시험 11건 가운데 하나는 기존 판정 점수·분포·수상 결과가 그대로인지를 지킵니다.
  • 공용 계산: 가중치, 0~5 척도, 동점 같은 등수, 잘못된 AI 응답 거절(여덟 가지 모양)을 공용 시험으로 고정했습니다.
  • 약관: 2026년 11월 5일 개정을 병합해 「개정 예정」을 띄웠고, 11월 12일에 다시 배포하지 않고 시행됩니다.
  • 채움률: 옛 지표는 「채움률」로 이름을 바꿔 운영에 반영했습니다. 공모전 제출 폼에는 「채움률 N% — 근거 연결 a/b, 권장 자료 c/3」으로, 지표 화면에는 「제출 채움률 분포」로 나옵니다. 이제 화면에서 「완성도」는 얼마나 잘 했는가, 「채움률」은 얼마나 채웠는가 한 가지 뜻으로만 쓰입니다.
  • 개인정보 처리방침: 2항(처리 목적)과 6항(국외 이전)에 완성도 채점 목적을 더해 운영에 반영했습니다. 약관과 같은 방식으로 7일 동안 「개정 예정」을 공지한 뒤 2026년 11월 12일에 시행됩니다.

배운 것

  • 줄을 세우고 싶다면 계산 공식보다 잃어버린 정보를 먼저 봅니다. 충족 판정은 「얼마나 잘」을 처음부터 버리고 있었고, 다시 세는 방법으로는 되살릴 수 없었습니다.
  • 점수 하나를 더하는 일은 계산보다 둘레가 큽니다. 누가 보는지, 어디에 쓰지 않는지, 약관에 어떻게 적는지, 이름이 무엇과 겹치는지가 같은 무게로 따라옵니다.
  • 절대 점수로 정하면 부분 재채점과 비용 예측이 쉬워집니다. 상대 평가가 더 정확해 보여도, 운영 비용까지 보면 절대 점수가 낫습니다.
  • 날짜로 바뀌는 문구는 배포가 아니라 렌더 시점의 비교로 바꿉니다. 그리고 우연히 같은 상수 둘을 시험으로 묶지 않습니다.

남은 한계

  • 0~5 점수는 결국 AI의 판단입니다. 같은 제출을 두 번 매기면 점수가 조금 다를 수 있고, 그 흔들림을 아직 재 보지 않았습니다. 그래서 선정·상금의 근거로 쓰지 않고 참고 의견으로 둡니다.
  • 가중치(필수 2, 선택 1)는 모든 문제에 같습니다. 문제마다 항목의 무게가 다를 수 있지만, 강사·개최자가 가중치를 고르게 하지는 않았습니다.
  • 클래스의 예상 비용은 그 시도의 판정 프롬프트 길이로 어림합니다. 확인 단계에서 저장소를 내려받지 않으려는 선택이라, 실제 비용과 조금 다를 수 있습니다.
  • 완성도는 이의 대상이 아닙니다. 점수가 이상하다고 느낀 참여자가 근거를 보고도 납득하지 못할 때 기댈 길은 아직 없습니다.

문의 →