Skip to content

🔀 :: perf.yml 동작 확인용 더미 PR - #144

Closed
aiden30015 wants to merge 23 commits into
developfrom
feature/perf-ci-dry-run
Closed

aiden30015 wants to merge 23 commits into
developfrom
feature/perf-ci-dry-run

Conversation

@aiden30015

@aiden30015 aiden30015 commented Sep 18, 2026 •

Copy link
Copy Markdown
Contributor

💡 개요

perfkit 성능 측정 GitHub Action(.github/workflows/perf.yml)이 pull_request 트리거로 정상 동작하는지 확인하기 위한 임시 PR입니다.

🔗 관련 이슈

Closes #

예외: 연결된 이슈 없음. #142(feature/perf-ci)와 동일하게 CI 검증 목적의 브랜치라 이슈 번호를 붙이지 않았습니다. 확인 후 머지하지 않고 닫습니다.

📃 작업내용

  • 더미 마크다운 파일 1개 추가 (실제 기능 변경 없음)

🔍 테스트 방법

  • perf 워크플로우(perf-reusable.yml)가 트리거되는지 확인
  • baseline 대비 프레임/메모리/시작시간 측정 결과가 정상 출력되는지 확인

🖼️ 스크린샷

🙋‍♂️ 질문사항

  • 개선할 점, 오타, 코드에 이상한 부분이 있다면 Comment 달아주세요.

✅ 체크리스트

  • 코드가 정상적으로 컴파일되고 실행되는지 확인했습니다.
  • 불필요한 코드가 없는지 확인했습니다.
  • 코드 스타일 가이드를 준수했습니다.
  • 기존 기능이 정상적으로 작동하는지 확인했습니다.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@aiden30015

Copy link
Copy Markdown
Contributor Author

perf.yml 동작 확인 완료 — 외부 perfkit reusable workflow(line 95 secrets in if:)의 기존 버그를 재현했습니다. 머지 없이 닫습니다.

flutter drive --profile 빌드가 매번 'Your project's Gradle version (8.12.0)
is lower than Flutter's minimum supported version of 8.14.0' 로 실패해서
perf 시나리오 5개가 전부 결과 없이 끝났다. perf CI 통과 확인용 임시 커밋 —
실제 수정은 별도 PR로 develop 에 올린다.
@github-actions

github-actions Bot commented Sep 18, 2026 •

Copy link
Copy Markdown

📊 Flutter Performance Report

✅ Passed — 회귀 없음

✅ app_startup

Metric Baseline Current Change Threshold
🆕 startup_ms — 935ms n/a —%
기타 지표
Metric Baseline Current Change Threshold
🆕 startup_rasterized_ms — 1110ms n/a —%

✅ home_scroll

Metric Baseline Current Change Threshold
🆕 fps — 60.0 n/a —%
🆕 jank_rate — 4.7% n/a —%
🆕 p95_frame_time_ms — 16.2ms n/a —%
🆕 memory_mb — 327MB n/a —%
기타 지표
Metric Baseline Current Change Threshold
🆕 dropped_frames — 6.0 n/a —%
🆕 p50_frame_time_ms — 11.1ms n/a —%
🆕 p90_frame_time_ms — 15.4ms n/a —%
🆕 p99_frame_time_ms — 19.2ms n/a —%
🆕 duration_ms — 16046ms n/a —%

✅ login

Metric Baseline Current Change Threshold
🆕 fps — 60.0 n/a —%
🆕 jank_rate — 2.3% n/a —%
🆕 p95_frame_time_ms — 6.0ms n/a —%
🆕 memory_mb — 292MB n/a —%
기타 지표
Metric Baseline Current Change Threshold
🆕 dropped_frames — 1.0 n/a —%
🆕 p50_frame_time_ms — 2.3ms n/a —%
🆕 p90_frame_time_ms — 5.3ms n/a —%
🆕 p99_frame_time_ms — 27.5ms n/a —%
🆕 duration_ms — 1537ms n/a —%

✅ member_list_scroll

Metric Baseline Current Change Threshold
🆕 fps — 60.0 n/a —%
🆕 jank_rate — 0.0% n/a —%
🆕 p95_frame_time_ms — 11.9ms n/a —%
🆕 memory_mb — 389MB n/a —%
기타 지표
Metric Baseline Current Change Threshold
🆕 dropped_frames — 0.0 n/a —%
🆕 p50_frame_time_ms — 8.8ms n/a —%
🆕 p90_frame_time_ms — 11.6ms n/a —%
🆕 p99_frame_time_ms — 13.3ms n/a —%
🆕 duration_ms — 31232ms n/a —%

✅ outing_state_scroll

Metric Baseline Current Change Threshold
🆕 fps — 60.0 n/a —%
🆕 jank_rate — 0.0% n/a —%
🆕 p95_frame_time_ms — 12.0ms n/a —%
🆕 memory_mb — 361MB n/a —%
기타 지표
Metric Baseline Current Change Threshold
🆕 dropped_frames — 0.0 n/a —%
🆕 p50_frame_time_ms — 8.3ms n/a —%
🆕 p90_frame_time_ms — 11.3ms n/a —%
🆕 p99_frame_time_ms — 12.9ms n/a —%
🆕 duration_ms — 28902ms n/a —%

⚠️ baseline baseline/performance_baseline.json 이 없습니다. 이번 결과는 비교 없이 기록만 합니다. perfkit rebaseline 로 기준을 만드세요.

commit 368e8df · CI run

판정: |변화율| > 임계값 AND |Δ| > 2σ·측정노이즈 AND |Δ| > 최소유의차. 🟡 = 임계값은 넘었지만 노이즈 범위 안(실패 아님).

Gradle 8.14.3 로 올린 뒤에도 'Android Gradle Plugin version 8.9.1 is lower
than Flutter's minimum supported version 8.11.1' 로 계속 실패. perf CI
통과 확인용 임시 커밋 — 실제 수정은 별도 PR로 develop 에 올린다.
AGP 8.11.1 로도 'Kotlin version (2.1.0) is lower than Flutter's minimum
supported version 2.2.20' 로 계속 실패. perf CI 통과 확인용 임시 커밋 —
실제 수정은 별도 PR로 develop 에 올린다.
app.main() 후 pumpAndSettle() 만으로는 스플래시/세션 체크 구간을 못 기다려서
login_id 를 못 찾고 'Bad state: No element' 로 죽었다 (login, home_scroll,
outing_state_scroll, member_list_scroll 전부 연쇄 실패). perf CI 통과
확인용 임시 커밋 — 실제 수정은 별도 PR로 develop 에 올린다.
앱은 스플래시 후 곧장 로그인 화면이 아니라 온보딩으로 간다(토큰 없으면
항상 온보딩). perf_test.dart 는 이 단계를 빼먹고 바로 login_id 를 찾아서
20초 타임아웃으로 매번 실패했다. 온보딩 로그인 버튼에 Key 를 추가하고
_login 이 먼저 그 버튼을 누르게 했다. perf CI 통과 확인용 임시 커밋 —
실제 수정은 별도 PR로 develop 에 올린다.
'login' 시나리오는 _login() 헬퍼를 안 쓰고 로그인 절차를 직접 구현하고
있어서, _login() 에 추가한 온보딩 버튼 tap 이 적용되지 않고 여전히
바로 login_id 를 찾다 실패했다. 온보딩→로그인 이동을 _goToLoginScreen 으로
분리해서 'login' 시나리오의 setUp 과 _login() 이 공유하게 정리했다.
perf CI 통과 확인용 임시 커밋 — 실제 수정은 별도 PR로 develop 에 올린다.
profile 빌드는 앱의 Logger.d/e 가 kDebugMode 게이팅으로 꺼져있어서 로그인
실패 원인을 CI 로그에서 전혀 볼 수 없었다. 타임아웃 시점에 화면의 Text
위젯 내용을 debugPrint 로 찍어서 실제 에러 메시지(SnackBar 등)를 확인한다.
진단용 임시 커밋.
env 파일(assets/env/dev.env)에는 TEST_EMAIL/TEST_PASSWORD 키가 확인됐는데
화면에는 두 필드 모두 '입력해주세요' 빈값 에러가 뜬다 — dotenv.env 에서
실제로 무엇이 로드됐는지 확인한다.
dotenv 값은 정상 확인됨 (testEmail.length=6, testPassword.length=10).
제출 후에도 화면 텍스트가 그대로인 것처럼 보인 건 에러가 SnackBar로
잠깐 떴다가 20초 타임아웃 전에 사라져서였을 가능성이 크다. 제출 직후
0.5초 간격으로 5번 찍어서 실제 에러 문구를 잡아본다.
진짜 원인: LoginScreen 의 confirm 버튼은 이메일/비밀번호 컨트롤러 리스너의
setState 로만 활성화된다. enterText 두 번 뒤 pump 없이 곧바로 tap 하면
버튼이 아직 비활성 상태라 탭이 조용히 무시되고, 이후 20초 내내 화면이
그대로였다(에러도 SnackBar 도 전혀 없었던 이유). enterText 뒤 pump 한 번을
추가하고, 원인 파악용으로 넣었던 dotenv/스냅샷 디버그 프린트는 제거했다.
_pumpUntil 타임아웃 시 화면 텍스트를 찍는 진단은 앞으로도 유용해서 남긴다.
pump() 추가에도 결과가 이전과 완전히 동일해서, pump 가 실제로 버튼을
활성화했는지부터 직접 확인한다.
flutter drive(실기기) 환경에서는 tester.enterText() 만 호출하면 컨트롤러가
비어있는 채로 남는다 — showKeyboard() 가 여는 텍스트 입력 채널이 필드가
이미 포커스돼 있을 때만 제대로 붙는데, key 로 찾은 위젯을 tap 한 적이
없어서 포커스가 안 잡혀 있었다. 그래서 login_id/login_pw 가 계속 비어
있었고, 로그인 버튼도 항상 비활성 상태라 탭이 조용히 무시됐다
(_isButtonEnabled 는 두 필드가 비어있지 않을 때만 setState 로 켜짐).

_enterText() 헬퍼로 tap → pump → enterText → pump 순서를 강제해서 고쳤다.
조사용으로 넣었던 디버그 프린트는 모두 제거했다.
tester.enterText() 는 tap 으로 먼저 포커스해도 flutter drive(실기기)
환경에서 컨트롤러가 계속 비어있는 채로 남았다(3번 확인). mock
TestTextInput 채널이 실제 기기의 EditableText 와 제대로 안 붙는 것으로
보인다. IME 시뮬레이션을 포기하고 TextFormField 의 controller.text 를
직접 대입하는 방식으로 바꿨다 — 이러면 컨트롤러 리스너(setState)는
정상적으로 타는다.
login 시나리오가 성공하고 나니, 같은 프로세스 안에서 이어지는
home_scroll/outing_state_scroll/member_list_scroll 이 전부
onboarding_login_button 타임아웃으로 실패했다 — 직전 시나리오에서 저장된
토큰이 남아있어 스플래시가 온보딩을 건너뛰고 곧장 홈으로 가는데, _login 은
여전히 온보딩이 뜨길 기다리고 있었다. home_list 가 이미 떠 있으면 그대로
반환하도록 고쳤다.
app_router.router 는 전역 싱글턴이라 app.main() 을 다시 호출해도 이전
시나리오에서 _goTo 로 옮겨둔 위치(예: 외출 현황)가 그대로 남는다.
member_list_scroll 이 이 상태에서 시작해 home_list/onboarding_login_button
어느 것도 못 찾고 타임아웃났다. _login 시작 시 홈으로 먼저 go() 해서
시작점을 고정했다.

참고: outing_state_scroll 은 별개 이유로 계속 실패할 수 있다 — CI 테스트
계정에 현재 외출 중인 학생이 0명이면 outing_state_list 키 자체가 안 뜬다
(코드 문제 아님, 조건부 렌더링). 테스트 계정에 외출 데이터가 있어야 한다.
CI 테스트 계정은 실제 외출/멤버 데이터가 비어있어서 outing_state_scroll,
member_list_scroll 이 스크롤할 대상이 없었다(코드 버그가 아니라 데이터
문제). main.dart 의 초기화를 main()/bootstrap() 으로 분리해 perf 테스트가
outingRepositoryProvider/memberRepositoryProvider 를 mock 으로 갈아끼울 수
있게 했다 — 로그인 자체는 여전히 실제 백엔드로 한다. perf CI 통과 확인용
임시 커밋 — 실제 수정은 별도 PR로 develop 에 올린다.
dynamic 으로 받은 기본값 const [] 는 List<dynamic> 으로 추론돼서
ProviderScope(overrides: ...) 에 넘기는 순간 'List<dynamic> is not a
subtype of List<Override>' 로 모든 시나리오(app_startup 포함)가 즉시
죽었다 — 로컬 flutter analyze 로는 안 걸리고 런타임에만 터지는 종류였다.
Override 는 riverpod 의 public 배럴(riverpod.dart)엔 없지만
riverpod/misc.dart 에는 export 돼 있어서, 거기서 제대로 import 해서
List<Override> 로 정확히 타입을 명시했다. riverpod 를 pubspec.yaml 에
명시적 의존성으로도 추가했다(지금까지 transitive 로만 딸려왔음).
member_list_scroll 은 데이터가 정상 로드됐는데도(화면 텍스트로 확인)
fling 시점에 member_list 키를 못 찾아 실패했다 — 화면 전환 직후
pumpAndSettle 이 끝나도 타겟이 트리에 아직 없는 찰나의 레이스로 보인다.
_pumpUntil 로 명시적으로 기다리게 했다.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@aiden30015

Copy link
Copy Markdown
Contributor Author

검증용 더미 PR이라 머지하지 않고 닫습니다. 실제 수정은 #145 에서 진행합니다.

@aiden30015 aiden30015 closed this Sep 19, 2026

This branch was successfully deployed

1 active deployment
Goms-v3 — 368e8df5 Deployed Sep 19, 2026 by aiden30015 via flutter_ci #239
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant