화이트보드 완료 BRID 기반 — 보드에서 시작한 세션만 완료로 (2026-08-29)
- 기간: 2026-08-29 (1세션, 오너 지시 "이슈 880이랑 875 같이 묶어서 진행" + 결정 D1=a안·D2=a안 "중간에 멈춤 없이 끝까지 완주")
- 랜딩: PR #908 (Phase 1 클라 계보 발급,
600805f5) · PR #911 (Phase 2 서버 컷오버,b6e85705) — Production db push + Vercel success 실측(app-EypLmYFN.js계보 마커·매니페스트 20260829130000) - 설계서: 없음 — 계획서 = 이슈 #880 스레드(예상 효과·개선사항 표 포함, 오너 승인 08-29)
- 정본:
docs/data/brid.mdbarbelic source_ref 계보 규약 절 ·src/react/services/workoutDraftCache.ts(groupBoardWorkoutSourceRef) ·supabase/migrations/20260829130000_group_board_completion_lineage_v1.sql(get_group_board_day_sessions_v1) ·docs/contracts/group-props.md§4 - 도구: Management API 포이즌 필 드라이런(마이그레이션 전문+지표 raise 롤백) · read-only 프로브(전→후 실측)
- 게이트:
supabase/tests/database/group_board_completion_lineage.test.sql(신설 plan 7) ·groups_v2_interactions.test.sql(계보 픽스처, 38 단언 유지) ·tests/react/workoutDraftCache.test.mjs·activeWorkoutCommands.test.mjs·groupScreens.test.mjs계보 앵커 - 버그리포트: BUG-033 (완료 의미론 후속 랜딩 반영)
- 계약: group-props.md §4(완료·기록 공급 기준 = 보드 출처 세션만) · brid.md 계보 규약(접두 불변 원칙)
Phase 현황
| Phase | 내용 | 상태 |
|---|---|---|
| Phase 0 | 분석·설계 확정(a안 vs b안 비교) — 오너 D1=a안·D2=a안 | ✅ 이슈 #880 스레드 |
| Phase 1 | 클라: 보드 프리필 계보 sourceRef 발급 | ✅ PR #908 |
| Phase 2 | 서버: 완료 행 RPC 계보 접두 컷오버 | ✅ PR #911 |
| Phase 3 | Production 실측·기록 | ✅ 이 문서 |
| Phase 4 | 오너 실기기 확인 → #880·#875 동시 종결 + PR #878 처분 | 🔄 확인 대기 |
1. 배경
#875가 완료 행 3결함(사람 단위·전환 스테일·속도)을 수리한 뒤, 완료의 의미 자체가 문제로 남았다: get_group_board_day_sessions_v1은 "그날(date) 그룹 멤버의 완료 세션 전부"를 세므로 보드가 없는 날에도 완료 행이 뜨고(마블오후반 08-18~25, 8일 연속 실측) 다른 그룹에서 한 운동까지 완료로 잡혔다(필앤주 08-26 실측). 오너 결정(08-27): "화이트보드에 적혀있는 세션은 어떤 그룹에서 만들었는지 정보를 가지고, 그 그룹에서 수행해야만 완료" — 이를 세션 BRID 통합(#879, 08-29 종결) 위에서 구현하기로 재편(#879→#880).
2. 문제 제기
세션에 보드 출처(provenance)가 어디에도 없다. 어디에 실을 것인가 — 두 안이 있었다: (a안) 출처를 source_ref 발급 규약으로 BRID 정체성에 내장 vs (b안) sessions.group_board_id FK 컬럼(#878 draft). 코드 실측이 판을 갈랐다: barbelic 세션의 source_ref는 클라가 드래프트 생성 시 발급하고(local:local-workout:<uuid>), 스냅샷→봉투(재부팅 생존)→payload→엔진→BRID 트리거까지 기존 배선이 이미 전 층을 왕복한다 — a안은 발급 지점 한 곳과 읽기 RPC 하나로 성립한다.
3. 해결 방안
원칙 (오너 결정, 2026-08-29)
- D1 = a안: 출처는 태어난 사실 — BRID 계보에 내장. 서버 DDL 0·엔진 무수정, "보드 사정이 저장을 막지 않는다"가 구조적으로 보장(저장 경로가 보드를 모른다), 보드 삭제→재생성에도 좌표 매칭이라 완료 유지. 비용 = 출처가 문자열 규약(관계형 FK 아님).
- D2 = a안: 종목 기록 뷰도 완료 행과 같이 보드 출처 세션으로 좁힘 — RPC 단일 소스 유지, 한 화면 안 숫자 불일치(완료 2명 vs 기록 3명) 차단.
접근
- 발급(Phase 1): 프리필 start에
origin {groupId, date}동반 →group-board:<group_id>:<board_date>:<operationId>선발급. 좌표 어긋나면local:*조용한 낙하. - 판정(Phase 2): RPC가 보드 존재 게이트(없으면 빈 items) +
starts_with(source_ref, 계보 접두)+source='barbelic'필터. 세션 date 필터 제거(자정 넘긴 완료도 그 보드 소속). 멤버십·차단·테이크다운·상한·셰이프·contract_version(1) 유지 — 클라 계약 무변경.
기각된 대안
| 대안 | 기각 사유 |
|---|---|
| b안 — group_board_id FK(#878 재기반) | 변경 폭(컬럼+엔진 전문+payload 2키+클라 4층) 대비 이득 없음, 엔진에 소거 로직 필요, 보드 재생성 시 완료 소실, 출처가 BRID 밖 |
| 읽기 전 세션 유지(D2-b) | RPC 2모드 분리 = 표면 증가 + 완료 행과 기록 뷰 숫자 불일치 재발 경로 |
4. 적용한 내용
- Phase 1 (#908):
groupBoardWorkoutSourceRef신설 + 프리필 배선(origin) + 계약문 2곳(group-props.md §4·brid.md 계보 규약 절). 표시 의미 무변경. - Phase 2 (#911):
20260829130000— RPC 전문 재발행 + postcheck(계보 필터 존재·date 등호 부재·보드 게이트 존재, 손댄 함수만 단언). pgTAP 신설 plan 7(보드 없는 날 빈 목록·셰이프 유지·계보만·date 무관·타 그룹 배제 + 유출 후보 3종 비공허) + 기존 38 단언 픽스처 계보 패치(id는 자연키 파생 리터럴 재계산 — 트리거 22023 자가 검증). - 작업 중 드러난 것: ① 세션 id가 자연키 파생(#879)이라 픽스처 source_ref를 바꾸면 id 리터럴도 재계산해야 한다 — brid_uuid_v1이 md5 기반이라 Node로 오프라인 재계산(기존 리터럴 1건으로 공식 검증 후 일괄 치환). ② groupScreens 소스 앵커가 프리필 호출부의 한 줄 형태를 고정하고 있었다(멀티라인 개행에 깨짐 — 앵커도 계약의 일부).
5. 적용 결과
| 항목 | 전 | 후 | 근거 |
|---|---|---|---|
| 보드 없는 날 완료 행 | 뜸(마블오후반 08-18~25, 8일) | 0건(보드 존재 게이트) | 컷오버 후 Production 프로브 |
| 타 그룹 운동 오집계 | 필앤주 08-26 완료 1행 | 0행 | 〃 (per-board 프로브) |
| 마블오후반 08-26 완료 행 | 3행(#875 원 사례) | 0행(소급 없음) | 〃 |
| 마블 역도반 08-28 완료 행 | 1행 | 0행 | 〃 |
| 구 의미론 완료 행 합계(전 보드 3개) | 5행 | 0행 | 드라이런 DRYRUN-OK boards=3 lineage_sessions=0 before_rows=5 after_rows=0 + 적용 후 재프로브 일치 |
| 완료의 의미 | 그날 아무 완료 세션 | 이 보드에서 시작해 완료한 세션만(자정 넘긴 완료 포함) | pgTAP plan 7 |
| 저장 경로 | — | 무간섭(DDL 0·엔진 무수정) | 마이그레이션 diff |
- 미검증: 실기기에서 보드 프리필 시작→완료→완료 행 1줄(계보 세션은 클라 배포 후 새 세션부터 생긴다) — Phase 4 오너 확인 항목.
6. 이번 개선으로 향상된 것
- 완료 판정이 오너 정의("그 그룹에서 수행해야만")와 일치 — 보드 없는 날·타 그룹 오집계 소멸.
- 세션 BRID만 보고 출처를 안다 — "모든 데이터는 BRID" 원칙에 출처가 합류. barbelic source_ref 계보 규약(brid.md)은 다음 출처(계획 시작 등)로 확장 가능한 틀.
- "출처 판정은 읽기 쪽·저장 무간섭" 패턴 — 부가 기능의 사정이 핵심 경로(운동 저장)를 건드릴 수 없는 구조.
남은 것
- 오너 실기기 확인(Phase 4): ① 보드에서 시작·완료한 새 세션이 그 보드 완료 행에 1줄 ② 보드 없는 날 완료 행 0 ③ #875 잔여(날짜 이동 체감). 확인 후 #880·#875 동시 종결.
- PR #878(b안 draft) close — a안 채택으로 폐기.
- 소급 없음: 과거 보드(08-26 포함)는 완료 0명으로 표시된다(오너 인지).