이 글은 2026-06-04 하루 동안
artifact-transformer의 시험 산출물 generate/parse를 바뀐 스키마·양식에 다시 맞추고, 비어 있던 init 스캐폴딩을 채운 작업 기록이다.
배경
artifact-transformer는 Jira 이슈와 PlantUML 다이어그램을 입력으로 받아 요구사항·유스케이스·기능·시퀀스 명세서와 단위·통합·운영·인수 시험서 등을 docx/xlsx로 자동 생성하는 도구다 (#4 참조).
#8까지는 주로 분석·설계 쪽 산출물(유스케이스·시퀀스)의 필드 개명과 양식 변경을 코드에 정합시켰다. 오늘은 무게중심이 시험 산출물(test artifacts) 쪽으로 넘어왔다. 통합·운영·인수 시험서의 generate/parse가 새 스키마를 따라가지 못하고 있었고, 시나리오와 시험 케이스를 처음부터 만들어 줄 init_* 스크립트들은 아직 비어 있거나 옛 모델 기준이었다.
그래서 오늘의 일은 두 갈래였다. 하나는 이미 있는 generate/parse를 최신 스키마에 정합시키는 일, 다른 하나는 산출물을 도출하는 init 스캐폴딩을 채우는 일. 두 갈래를 관통하는 원칙은 지난 편들과 같았다.
분류·참조는 단일 출처(business.json / requirement.json)에서 가져온다. require가 아닌 값은 비워 두고, 채우는 일은 뒤에 LLM에게 맡긴다.
문제
손대기 전에 어긋나 있던 것들.
- 운영 시나리오가 자유 도출 — 업무와 연결이 없었다 —
operational-scenario.json이 업무 정의서(business.json)와 무관하게 만들어지고 있었다. 업무 1건이 운영 시나리오 1건으로 이어진다는 모델이 코드에 박혀 있지 않았다. - 시험 문서 generate/parse가 새 스키마와 어긋남 —
itd/itp/itpr/itr(통합),atd/atp/atpr/atr(인수),otp(운영),utp(단위) 곳곳에서 칸이 비거나 엉뚱하게 채워졌다. “영역”·“우선순위”·“참여 모듈” 같은 컬럼이 대표적이었다. - 인수 단계 init 스크립트가 없었다 — 요구사항에서 인수 시나리오를, 인수 시나리오에서 인수 시험 케이스를 도출하는
init_*가 아예 부재했다. 통합 시나리오 초안 생성기도 마찬가지였다. references가 산출물마다 제각각 — 스키마는 참조를{number, name, version}구조로 정의하는데, 기반 산출물에는 문자열 배열로 들어 있는 경우가 많았다.- 인수 시험 케이스의 id·연관·양식이 옛 기준 — testcase id 형식, “연관 시나리오 ↔ 연관 요구사항”, 정의서 컬럼 배치가 모두 바뀌었는데 코드는 따라가지 못했다.
- 죽은 스키마·죽은 코드가 남아 있었다 — 더는 쓰지 않는
scenario.schema.json, 공통 스키마에 잘못 자리 잡은 시험용 정의들, 사장된 함수들.
결정 1 — 운영 시나리오를 업무(business.json) 기반으로 전환
운영 시나리오는 운영자가 시스템을 다루는 절차이고, 그 절차의 출처는 업무다. 그래서 operational-scenario.json을 업무 1건 = 운영 시나리오 1건 모델로 다시 묶었다. 분류(categories)는 업무 카테고리를 그대로 쓰고, 시나리오 id는 업무 id에서 BIZ 접두만 떼어 {프로젝트코드}-OSC-{분류코드}-00n 형태로 맞췄다.
init_operational_scenario.py는 require가 아닌 속성을 빈 값으로 만들어 두도록 했다. 채우는 일은 뒤에 LLM이 맡는다 — 스캐폴딩은 구조만 책임지고, 내용은 비워 둔다는 [#7] 이후의 약속을 여기에도 적용했다.
README·파일명 표·디렉터리 트리도 업무 기반 모델로 일괄 갱신하고, operational-scenario.sample.json을 최신 스키마로 다시 생성했다.
시나리오는 자유 창작물이 아니라 업무의 파생물이다. 출처가 업무라면, 도출 코드도 업무를 입력으로 받아야 한다.
결정 2 — 시험 문서 generate/parse를 최신 스키마에 정합
오늘 가장 손이 많이 간 갈래다. 통합·인수·운영·단위 시험서의 generate/parse를 차례로 새 스키마·양식에 맞췄다.
- 영역은 단일 출처에서 —
itd/itp/itpr/itr의 “영역”을business.json의categories를 참조하도록 바꿨다. 각 산출물이 자기 분류를 따로 들고 있던 중복을 또 하나 걷어냈다. - 미맵핑 칸 메우기 — 통합 시험 계획서의 4.2 시험 대상 요약의 선행 조건, 5.2 시험 범위 및 검증 조건의 검증 관점·관련 인터페이스가 비어 있었다. 양식 변경을 코드가 따라가며 채웠다.
- 참여 모듈은 시나리오 step에서 — 통합 시험 결과서(
itr)의 참여 모듈 정보를 해당 시나리오 step의participants에서 맵핑하도록 하고, 양식에서 빠진 참여 모듈 컬럼은 generate/parse 양쪽에서 정리했다. - 단위 시험 우선순위 — 단위 시험 계획서(
utp)에서 시험 대상 우선순위가 맵핑되지 않던 것을 generate/parse 양쪽에서 맞췄다. - 운영 시험 정의서 —
generate_osd.py에 목록 탭 맵핑과 상세 시나리오 생성을 더하고,generate_otd.py가 운영 시험 정의서의 상세 절차까지 생성하도록 했다. 운영 시험 계획서 양식 변경은otp코드에 반영했다.
통과 기준은 늘 같았다 — 샘플 데이터로 generate→parse 왕복을 돌려 칸이 제자리에 들어가는지 본다.
결정 3 — 인수·통합 단계 init 스캐폴딩 신규 작성
도출 사슬의 빈 칸을 채웠다. 모두 상위 산출물을 입력으로, 빈 값은 LLM 몫으로 남기는 같은 패턴이다.
init_integration_scenario.py—function.json을 입력으로 통합 시나리오 초안을 기능 카테고리별로 생성.init_acceptance_scenario.py—requirement.json을 기반으로 인수 시나리오를 생성. 최신 스키마를 반영하고 빈 속성은 비워 둔다.init_acceptance_testcase.py— 인수 시나리오를 기반으로 인수 시험 케이스를 생성.init_operational_testcase.py—operational-testcase.schema.json을 반영. 스키마에 없는testResults는 제거하고,areas는business.json을 참조해 도출.
스캐폴딩이 채워지자 도출 사슬이 요구사항 → 시나리오 → 시험 케이스 → 시험 문서로 한 줄로 이어졌다.
결정 4 — references를 {number, name, version}으로 통일
references(근거·표준·법령)는 스키마가 number/name/version 객체 배열로 정의하는데, 기반 산출물에서는 흔히 문자열 배열로 들어온다. 예컨대 국내 근거는 “항공안전법 (법률 제19513호)” 같은 한 줄 문자열, 국외 근거는 “Aeronautical Information Services (ICAO Annex 15)” 같은 형태다.
그래서 모든 init 코드가 references를 객체 구조로 생성하도록 맞추되, 기반 데이터가 구조와 어긋나면 통째로 버리지 않고 name에만 맵핑해 둔다. 번호·버전은 비워 두고 뒤에 채운다.
| 입력 형태 | number | name | version |
|---|---|---|---|
{number, name, version} | 그대로 | 그대로 | 그대로 |
| 문자열 한 줄 | (빈 값) | 문자열 전체 | (빈 값) |
구조를 강제하되 비정형 입력을 버리지 않는다. 맞는 칸이 없으면
name으로 받아 두고, 정합은 나중 단계로 미룬다.
결정 5 — 인수 시험 케이스 정합: id·연관·양식
인수 시험 케이스 쪽은 id 규칙부터 양식까지 한꺼번에 움직였다.
- testcase id —
{프로젝트코드}-TC-AT-{요구사항 영역}-00n. 시험 영역은 연관된 요구사항의 분류를 참조한다. - 연관 대상 교체 — “연관 시나리오”를 “연관 요구사항”으로 바꿨다. 인수 시험은 시나리오가 아니라 요구사항에 대응한다는 관점의 정정이다.
- 정의서 양식 B ↔ C 컬럼 위치 교체 —
acceptance-testcase.schema.json최신화에 맞춰 generate/parse의 컬럼 매핑을 새 배치로 돌렸다. testAreas맵핑 —id/name/description을 제대로 채우도록 고쳤다(아래 함정 참조). 인수 시험 절차서의 세부 절차 안{TEST_AREA.NAME} ({TEST_AREA.CODE})자리는testArea에서 맵핑하도록 했다.- 운영 시험 결과서(
atr) — 관련 시나리오 항목을 양식에서 들어낸 데 맞춰 generate/parse 코드에서도 제거했다.
결정 6 — 죽은 스키마·코드 정리와 산출물 관계도
마지막은 청소다.
- 더는 쓰지 않는
scenario.schema.json을 삭제하고 그것을 읽던 코드를 걷어냈다. _common.schema.json에 있던TestEnv·TestArea정의를 성격에 맞는_test.schema.json으로 옮겼다. 공통 스키마에는 진짜 공통인 것만 남긴다.generate_otp의_fill_mode_flow_table처럼 양식 변경으로 사장된 함수를 제거했다.
그리고 11종 산출물이 분석 → 설계 → 구현 → 테스트 → 인수 단계로 어떻게 이어지는지를 PlantUML 관계도로 그렸다. 단계별로 묶어 가독성을 손봤다(처음엔 다이어그램 타입을 sequence로 잘못 추정해 syntax error가 났다 — 아래 함정).
함정
generate_itpr가 시험 절차 step 1을 항상 빈 칸으로 추가했다 — 절차 행을 만들 때 off-by-one으로 맨 앞에 빈 step이 하나 더 붙었다. step 수만큼만 칸을 만들도록 고쳤다. 양식이 비어 보이지 않으니 눈으로는 잘 안 잡히는 종류의 버그다.testAreas가id에만 값이 들어가고name·description이 비었다 —"id": "데이터", "name": "", "description": ""처럼 맵핑되고 있었다. 분류 코드를 id로만 받고 이름·설명 출처를 연결하지 않은 탓이었다. 맵핑 소스를 다시 이어 줬다.init_sequence.py의_PROJECT_ROOT버그 — 프로젝트 루트 추정이 어긋나 경로가 엉뚱한 곳을 가리켰다. 시험 산출물과 직접 상관없는 잠복 버그였지만, 같은 init 계열을 손대는 김에 함께 고쳤다.- PlantUML 다이어그램 타입 오추정 — 관계도를 그리며 자동 추정이 sequence 다이어그램으로 잡혀 syntax error가 났다. 관계도는 시퀀스가 아니라 컴포넌트/패키지 관계다. 타입을 바로잡아 해결.
- 운영 시나리오 정의서의 “대표 흐름” 컬럼은 넣었다 뺐다 — 양식에 대표 흐름 컬럼을 더해 generate/parse osd에 반영했다가, 곧 그 컬럼을 다시 제거했다. 양식이 확정 전이면 코드 정합도 같이 출렁인다 — 양식이 굳은 다음 코드를 맞추는 편이 싸다.
마무리
오늘은 시험 산출물 라인을 새 스키마에 정합시키고, 비어 있던 도출 스캐폴딩을 채운 날이다. 관통하는 결은 셋이었다.
- 분류·참조는 단일 출처에서 — 운영 시나리오는
business.json, 인수 시나리오는requirement.json. 각 산출물이 분류를 따로 들고 있던 중복을 또 걷어냈다([#7]의 연장). - 스캐폴딩은 구조만, 내용은 LLM 몫 — 모든
init_*가 require 아닌 값을 비워 두고 끝낸다. 도출 사슬의 골격을 먼저 세우고, 살은 뒤에 붙인다. - 양식·스키마가 움직이면 generate/parse가 따라간다 — id 형식, B↔C 컬럼 교체, 미맵핑 칸, references 구조. 원천이 바뀌면 코드 쪽이 따라가서 메운다는 원칙은 시험 산출물에서도 그대로였다.
다음에 할 것:
- LLM 채움 Skill 다듬기 — 비워 둔 데이터 채우기 — init 스캐폴딩이 구조만 세우고 비워 둔 require 아닌 값들을, 그 빈 칸을 메우는 LLM 단계의 Skill(프롬프트·도출 규칙)로 정교화한다. 골격은 섰으니 이제 살을 일관된 품질로 붙이는 쪽이 다음 병목이다.
- 정합성 검사를 시험 산출물까지 확장 — [#7]에서 만든 cross-reference 검증은 분석·설계 산출물 위주였다. 오늘 정합시킨 통합·인수·운영·단위 시험 산출물의 참조(시나리오↔시험 케이스↔요구사항·업무)와 커버리지까지 검사 범위를 넓히고, 샘플 수정 시 자동으로 걸리도록 CI 게이트로 승격한다.
- legacy 폴백 일괄 정리 시점 정하기 —
requirements/relatedFn,usecase/relatedUc, references 문자열 폴백 등 개명·구조 전환마다 단 읽기 폴백이 쌓였다. 마이그레이션이 끝난 항목부터 폴백을 걷어내야 두 표기가 영구 공존하지 않는다. - init → 채움 → generate → parse 파이프라인 통합 — 지금은 단계가 따로 도는데, 상위 산출물에서 스캐폴딩을 세우고 LLM이 채운 뒤 문서를 생성·역파싱해 round-trip을 한 번에 검증하는 단일 흐름으로 묶는다.