Skip to content

타 종목 1RM 기준 세트 % — 암묵 자기 종목 해석에서 기준 종목 영속·전 종목 선택까지 (2026-08-25)

  • 기간: 2026-08-25 (세션 1, 오너 보고 원문: "70%는 각 종목의 무게가 아니라, 본인 clean and jerk 무게의 70%를 지칭하는 것임 … 우리 시스템에서는 타종목 1rm으로 세트의 %무게를 작성하는게 불가능함. 보완 필요" — 이슈 #676)
  • 랜딩: PR #734(Phase 1~4, 325d5200) — 마이그레이션 20260821750000 Production 적용·check:remote-schema 0 실패·Vercel 배포 확인(신규 마커 load_percent_base_exercise_id 메인 청크 실측)
  • 설계서: 없음(단일 세션 트랙) — Phase 계획서·예상 효과·개선사항 표는 이슈 #676 계획서 코멘트
  • 정본: planned_sets.load_percent_base_exercise_id(null=자기 종목), validated_entry_percent_base_v1, 스크럽 트리거 scrub_planned_set_atomic_values_v1(%가 사라지면 기준 동반 소거), 클라 필드 loadPctBase(세트)·pctBase(편집기 exercise)
  • 도구: 단독 마운트 스모크(레포 밖 scratchpad vite — UiDesktopPlanEditor·UiWorkoutFlow(plan) 픽스처 마운트, gitignored)
  • 게이트: pgTAP planned_sets_load_percent_base.test.sql(12단언) · 왕복 하네스 planRoundTripHarness % 기준 2건 · plannedPercentBasePreservation.test.mjs(5건) · desktopExerciseIdentity 계약 재고정
  • 버그리포트: 없음(기능 확장)
  • 계약: 없음(신규 계약 문서 없이 스키마·코드 정본으로 유지)

Phase 현황

Phase내용상태
Phase 0조사·설계·계획서 게시✅ 이슈 코멘트
Phase 1DB 계약 — 컬럼·검증기·스크럽·RPC 재발행·pgTAP (750000)✅ PR #734 (325d5200)
Phase 2클라 데이터 계약 — loadPctBase 전 구간 관통✅ PR #734
Phase 3데스크톱 편집기 — % 게이트 일반화·기준 전 종목 선택✅ PR #734
Phase 4모바일 편집기 — 동등 기능 + 복합 % 신설✅ PR #734
Phase 5검증·랜딩 — CI·Production·Vercel 실측✅ 08-25
Phase 6작업 기록✅ 이 문서

1. 배경

역도식 프로그래밍은 보조 동작의 무게를 대표 종목 1RM의 %로 쓴다 — "Jerk Dip + Rack Jerk, 70% (2+3)x2"의 70%는 각 동작이 아니라 본인 Clean & Jerk 1RM 기준이다. 그런데 계획 세트의 %는 세 겹으로 자기 종목에 묶여 있었다: ① planned_sets.load_percent는 "무엇의 %인지"를 담는 자리가 없어 암묵적으로 자기 종목 1RM으로만 해석됐고, ② 편집기 % 버튼은 자기 종목(복합=구성 동작) 1RM 존재로 게이트돼 1RM 기록이 없는 종목(Jerk Dip)은 % 입력 자체가 안 보였고, ③ 데스크톱 복합에만 있던 "기준 1RM" 선택(pctBase)은 편집 세션 로컬이라 저장하면 소실됐다. 모바일 복합세트는 무게 단위 토글 자체가 없어 kg 고정이었다.

2. 문제 제기

%의 기준이 스키마에 없다 — 암묵 자기 종목 해석

load_percent는 스칼라 하나. % → kg 해석은 클라이언트 입력 시점에 자기 종목 1RM으로만 일어나고 서버는 1RM을 모른다. 타 종목 기준은 표현 자체가 불가능.

기존 기준 선택(pctBase)은 휘발·복합·데스크톱 한정

DesktopPlanEditorCardParts.tsx의 pctBase는 ① 복합 구성 동작 중에서만 고를 수 있어 제3 종목(C&J) 지정 불가 ② 저장 계약(WriteDto·RPC)에 없어 재편집 시 첫 1RM 보유 동작으로 폴백 ③ 모바일에 없음.

% 게이트가 필요한 유저를 배제

% 버튼 조건이 "자기(구성 동작) 1RM 있음"이라, 1RM을 잴 일이 없는 보조 동작에서는 %를 켤 방법이 없었다 — 이슈의 Jerk Dip이 정확히 이 경우.

3. 해결 방안

원칙 (오너 지시, 2026-08-25)

"땜질식 계획은 하지 말고, 가급적 본질적으로 문제를 해결하고 더 좋은 아키텍처를 구현하는 방향으로" — %의 기준을 스키마의 일급 데이터(provenance)로 승격하고, 기준 선택을 전 종목 일반 프리미티브로 확장. 오너 승인 없이 완주(같은 지시).

접근

대안판정
composite_meta에 기준 끼워넣기기각 — 복합 한정 땜질, 단일 종목(스내치 풀 @ 스내치 %) 불가, meta는 그룹핑 계층
load를 표현식 모델({kind:'percent', of, value})로 재설계기각 — stats_load_kg·통계·세션 시작 전 파이프라인 재설계 대비 지금 필요한 능력 이득 없음
세트 행에 기준 컬럼 신설(load_percent_base_exercise_id), kg 파생·정본 계약 유지채택 — 기존 두-스칼라(입력 %+파생 kg) 모델에 provenance 한 칸 추가, null=자기 종목이라 기존 행 전부 불변·백필 0

의미론 확정: 기준 1RM이 나중에 바뀌어도 저장된 kg는 자동 변경하지 않는다(작성된 계획의 무게는 명시적 재편집으로만 — 기존 % 동작과 동일 계약). 자기 종목 기준은 서버가 null로 정규화해 기본 상태의 표현을 하나로 유지. 명시 기준의 1RM이 사라지면 %를 잠가 kg 입력으로 폴백 — 다른 1RM으로 조용히 대체 계산하지 않는다.

4. 적용한 내용

Phase 1 — DB 계약 (#734, 20260821750000)

컬럼(uuid 형식·note 행 금지 check, FK 없음 — exercise_id와 같은 취급) + validated_entry_percent_base_v1(형식 22023·존재 23503·자기 종목 null 정규화) + scrub_planned_set_atomic_values_v1 재발행·트리거 재생성(load 원자 해제 또는 % null이면 기준 동반 소거 — apply_plan_atomic_values_v1의 UPDATE도 이 트리거를 지나는 단일 관문이라 apply는 재발행 불요) + validate_plan_payload_v3(+structure_core)·save_plan_v3_engine·get_planned_session_detail_v1_engine 전문 재발행(기준 있는데 % 없으면 22023 거부) + postcheck + pgTAP 12단언.

Phase 2 — 클라 데이터 계약 (#734)

쓰기: 편집 draft exercise.pctBase → 플로우 직렬화기(기준 있을 때만 키 방출 — 바이트 동치 계약 유지) → 평탄화(% 세트에만 loadPctBase, 복합은 그룹 전 행) → WriteDto → savePlan allowlist·uuid 검증·매핑. 읽기: 상세 어댑터 검증 → plannedSetView → 복원에서 그룹/단일 pctBase 재조립(기준 동작 행의 서버 null 정규화 내성 — 그룹 첫 비-null 기준 채택). 타입 미러 3곳 + 직접 select 컬럼.

Phase 3 — 데스크톱 편집기 (#734)

% 게이트 "자기 1RM 있음" → "해석 가능한 기준 1RM 있음(1RM 보유 종목 존재)". DkpBasePick을 복합 동작 택1 → 1RM 보유 전 종목 synonym 검색 선택(검색 계약 준수, 1RM kg 병기, 구성 동작/자기 종목 핀)으로 재구성, 단일 종목에도 기준 행 표시, % placeholder에 기준 종목명 병기.

Phase 4 — 모바일 편집기 (#734)

동등 규칙 + 복합 % 신설(unitMode의 !composite 게이트 해제, 복합 편집에 무게 단위 행 노출 — 디테일·종목 옵션 행은 복합 숨김 유지). WfBasePick(settype 드롭다운 패턴+검색), makeFlowExercise에 pctBase 보존, WorkoutFlow → WfRecord exerciseCatalog 관통. 완료 세션 저장은 명시 키 투영이라 pctBase 무영향(% = 계획 전용, kg 정본 불변).

주요 결정과 그 근거

  • 1RM 맵 재사용: oneRms가 이미 유저 전 종목 UUID 키로 클라에 있어 타 종목 기준에 새 페치 0.
  • 스크럽 단일 관문: 기준-% 종속을 CHECK 대신 BEFORE 트리거 정규화로 — apply 경로가 %를 null로 바꿔도 제약 위반 대신 기준이 조용히 함께 소거된다.
  • 자기 종목 null 정규화: 기본 상태 표현이 하나라 legacy 행·새 행이 같은 의미 공간에 있다.

작업 중 드러난 것

  • 번호 선점 2회: 730000(target_muscles)·740000(UGC)이 랜딩 도중 선점 — 장부 실측 후 750000 재번호, pgTAP 시드도 upstream target_muscles NOT NULL에 맞춰 보정. 740000의 "RPC 일괄 재발행"과 이 트랙 재발행 함수 5종의 겹침 없음을 grep으로 실측(겹쳤다면 게이트 되돌림 사고).
  • 충돌 PR은 Actions 미발화(기지 함정 재확인): push 후 run이 안 보이면 mergeable부터 확인.
  • pgTAP 함정 2건: ① 종목 시드 measurement_type 허용값은 weight_reps|reps|time|distance|bodyweight_reps — duration 기록 종목은 'time'format() 본문의 리터럴 %(제목 "기준 % 계획")가 지정자로 해석돼 셋업 크래시 — %%로 이스케이프하거나 문구에서 제거.
  • plannedSessionHardCutoverSqlContract의 추출기는 validate 정의부터 다음 $$;까지를 자르므로 마이그레이션 내 섹션 순서를 710000과 동일하게(validate → structure_core) 유지해야 한다.
  • 레이어 게이트 2건: viewMappers에서 set.load_percent* 스네이크 접근 금지(leanModelHardCut) · 복원 입력은 camel 단일 키(check:dual-key 기준선).
  • 별건 발견(보고만, 미수정): 계획 저장 DTO(workoutPlanCommands.ts plannedSessionWriteDto)와 플로우 직렬화기 둘 다 synonymId를 떨어뜨림 — #673 계획 표기 보존의 클라 층 회귀 의심. 오너 판단 대기.

5. 적용 결과

항목전 → 후
타 종목 1RM 기준 % 작성불가 → 데스크톱·모바일, 단일·복합 모두 가능 (스모크 실측: C&J 120kg 기준 70%→84kg·80%→96kg)
기준 선택 범위복합 구성 동작 한정·데스크톱 한정 → 1RM 보유 전 종목 검색·양 플랫폼
기준 선택 영속편집 세션 로컬(재열면 소실) → planned_sets 영속·재편집 복원 (하네스·pgTAP 왕복 증명)
1RM 없는 종목의 %% 버튼 숨김 → 기준 선택으로 사용 가능
모바일 복합 무게 단위kg 고정(토글 없음) → kg/lb/%
기존 행·기존 % 동작의미 불변(null=자기 종목, 백필 0) — 전체 스위트 1944 pass·pgTAP 897단언 통과
Production750000 적용·remote-schema 0 실패·컬럼/함수/엔진 3종 프로브 확인·Vercel 신규 마커 실측
오너 실기기 확인종결 — 오너 종결 지시(08-25)로 이슈 #676 닫음

6. 이번 개선으로 향상된 것

역도식 프로그래밍이 계획으로 표현된다

Jerk Dip + Rack Jerk 70%(C&J 기준) 같은 대표 종목 % 처방을 그대로 쓰고, 재편집 때 기준이 유지된다.

%의 기준이 데이터가 됐다

"70%가 무엇의 70%인지"가 스키마에 남는다(provenance) — 이후 % 재해석·표시·분석 기능의 토대. 구조적으로 남는 것: 기준 컬럼·검증기·스크럽 단일 관문·왕복 하네스 케이스·pgTAP.

기준 선택이 일반 프리미티브가 됐다

복합 한정 UI 특례가 전 종목 검색 선택(synonym 계약 재사용)으로 승격 — 단일·복합·양 플랫폼이 같은 규칙 하나를 쓴다.

남은 것

  • 오너 실기기 확인(이슈 #676 종결 판단)종결 — 오너 종결 지시(08-25, "오케이 고생했어 이슈 닫고 끝")로 이슈 #676 닫음.
  • 별건: 계획 저장 클라 층의 synonymId 드랍 의심(#673 회귀 가능성) → 오너 지시로 같은 날 수리 완료(PR #745, bug-024) — Production 프로브로 확정 후(계획 106행·세션 4,138행 전부 null) DTO·플로우 직렬화기 2곳 복원.
  • 범위 밖: 계획 조회(비편집) 표면의 % 기준 종목명 병기 — 현재 % 표시는 편집기 한정이라 미적용.