Skip to content

[P1][U03] 상세 알림 토글의 저장·반영 상태와 빠른 조작을 일관되게 처리 #612

Description

@jjoonleo

[P1][U03] 상세 알림 토글의 저장·반영 상태와 빠른 조작을 일관되게 처리

문제와 사용자 영향

‘알림에 일정 이름 표시’는 잠금화면 개인정보 노출 범위를 바꾸는 설정이다. 현재 화면은 요청한 값을 먼저 체크하고 DB 저장을 기다린다. 저장 예외를 처리하지 않으며, 저장 중 반대 조작을 받은 경우 어떤 선택이 최종 적용되는지 보장하지 않는다. 저장 후 알림 재등록이 실패하면 일시적인 공통 SnackBar만 보여 준다. 사용자는 화면의 OFF를 보고 기존 알림도 비공개로 바뀌었다고 생각할 수 있지만, DB 저장 여부와 기존 상세 알림 취소 여부는 별개의 사실이다.

2026-09-23 종합 감사 U03 / P1의 상세 명세다. 전담 서브에이전트 /root/grill_u03가 grill-with-docs로 실제 질문하고 root가 사용자를 대신해 답했다. 이 문서는 합의한 후속 구현 계획이며, U03 구현·테스트·실기기 완료를 주장하지 않는다. A05/A14/A15/D03의 이미 구현된 공통 알림 엔진을 활용하되, 각 이슈의 미완료 기기 조건까지 완료된 것으로 간주하지 않는다.

고정 소스 근거

조사 기준은 main/Figma PR #607 통합 커밋 **074d5fd642a2890dc48933dafcbd038534f759a4**다. A06의 working tree 변경과 U01의 문서 변경은 이 조사 근거에 섞지 않았다. 모든 제품 코드 근거는 git show로 고정 커밋에서 읽었다. 실제 구현 시작 시 최신 통합 소스를 다시 확인한다.

근거 현재 확인한 동작
상세 설정 초기 읽기 L264–290 _enabled=false, _loading=true에서 시작한다. _load가 예외를 처리하지 않아 실패 시 로딩과 미처리 Future가 남을 수 있다. 미확인 상태도 화면 값은 false다.
상세 설정 변경 L293–325 UI 선반영→catch 밖 DB write→reconcile 순서다. 저장 중 재입력·요청 순번·read-back이 없고 재등록 partial/settingsUnavailable만 공통 SnackBar로 표시한다. 제목은 한국어 상수다.
DetailedNotificationPreferenceService L11–20 DB의 상세 설정 조회·갱신만 수행한다. UI 의도, 실패 read-back, generation, 알림 결과를 소유하지 않는다.
UserDao L141–164 설정 read는 profile row 부재 시 기본값을 반환한다. 상세 write는 transaction으로 필드만 갱신하며 실제 변경에만 durable revision을 증가시킨다.
Reconcile 접수·drain L74–130 A15 요청 revision과 lease가 이미 있다. 각 요청은 해당 cutoff의 pass 결과를 받으며 단순 in-flight 합류 구조가 아니다. U03은 이 경계를 이용해야 한다.
Reconcile read-back L480–539 provider 관측과 실패를 반영해 confirmed/retained record를 구분한다. UI가 enum 하나만으로 ‘잠금화면 완전 비공개’를 선언할 근거는 아니다.
AlarmReconciliationResult L408–450 status, failures, provider, armed ID를 제공하지만 UI의 DB 저장 상태 및 특정 상세 의도와 연결된 적용 상태는 별도로 모델링해야 한다. 필요한 경우 최소 typed 이유를 확장한다.
AlarmOperationCoordinator OS 부작용을 공통 owner가 직렬화하고 D03 journal 최소 소유권을 보존한다. UI timeout으로 owner를 해제할 수 없다.
LocalDataOperationGate replacement/invalidation 시 generation이 바뀐다. UI dispose와 데이터 세대 변경은 다른 경계다.
App resume L151–174 resume의 공통 reconcile 요청은 존재한다. 상세 설정 tile 자체는 lifecycle 관찰/최신 상태 구독을 하지 않는다.
기존 MyPage 테스트 L104–142 opt-in 저장과 commit 후 reconcile exception을 검사한다. write/read-back 실패·연속 요청·화면 이탈·replacement 경계 검증은 부족하다.
Backup Restore L175–201 복원 데이터에 상세 선호가 포함되고 generation replacement 안에서 DB를 교체한다. 구화면의 늦은 상세 write가 복원 설정을 덮으면 안 된다.

도메인과 범위

  • Private Notification Content가 기본이며 Detailed Notification Content는 명시적 opt-in이다. 상세 ON이 허용하는 내용은 일정명과 기기 시간대와 다른 Schedule Time Zone뿐이다. Place, note, Preparation 및 Preparation Step 원문은 제외한다(ADR 0030).
  • 상세 선호는 암호화 Local Data Store에 있는 Durable OnTime Data다. 현재 OS 예약·취소 상태와 같지 않으며, OnTime Backup에는 선호만 포함한다.
  • Schedule Notification Setting은 미래 일정 준비 알림 사용 여부다. 상세 내용 설정과 OS 표시 권한은 서로 다른 축이다. 진행 중 Preparation Step 알림의 A06 설정 의미를 변경하지 않는다.
  • Local Data Reset, Backup Restore, Backup Cutoff 및 기존 A15 generation 계약을 사용한다. 새 제품 용어는 없다. requested/confirmed/applying/controller/revision 같은 구현 표현을 CONTEXT glossary에 추가하지 않는다. 새 ADR도 필요 없다.
  • Android/iOS local-only, schema 2, backup v2/v1 호환, nearest eligible 60개, Android 신규 native alarm 금지 및 현재 Figma/Flutter MyPage 구성을 유지한다. 서버·원격 분석·별도 durable 설정 큐·원문 알림 payload 저장소는 추가하지 않는다.

확정한 사용자 상태와 저장 계약

읽기, 최신 요청, 확정값

  1. 최초 active Local Profile 및 데이터 gate readiness가 확인되기 전에는 실제 저장값을 안다고 표시하지 않는다. 설정 읽기 중에는 ‘확인 중’, 오류에는 ‘설정을 불러오지 못함’과 명시적 재시도를 제공한다. false로 가정해 저장하거나 profile을 새로 만들지 않는다. 새 설치의 정상 private 기본값과 읽을 수 없는 상태를 구분한다.
  2. 확인된 DB 값, 사용자가 마지막으로 요청한 값, DB 저장 상태, OS 반영 상태를 구분한다. UI가 요청값을 스위치에 즉시 표시할 수 있지만 저장 전에는 ‘끔 요청 중/켬 요청 중’처럼 미확정임을 보조 문구와 접근성 상태로 명시한다.
  3. 최신 의도 하나를 직렬로 처리한다. ON 저장/알림 반영이 진행 중이어도 OFF 요청을 접수한다. 빠른 ON→OFF→ON은 최신 값에 수렴한다. 저장과 OS writer를 병렬 복제하지 않는다.
  4. 오래된 write가 이미 commit될 수는 있지만 최신 OFF가 대기 중이면 그 오래된 ON 결과를 이유로 새 detailed OS 등록을 시작하지 않는다. currentness 검사와 A15 후속 요청 접수를 연결한다. 이미 OS에 전달된 호출은 실제 반환·취소 확인을 D03/A15가 소유한다.
  5. write 실패 뒤 authoritative DB read-back으로 마지막 확정값을 알아낸다. 실패를 이유로 추정 rollback write를 하지 않는다. read-back도 실패하면 unknown이고 ON/OFF 저장 성공을 표시하지 않는다. 오류 자체가 무한 재시도를 만들지 않으며 명시적 재시도/새 조작으로 회복한다.
  6. DB에 commit된 ON/OFF는 OS 실패 때문에 되돌리지 않는다. 특히 OFF를 상세 ON으로 rollback하거나 상세 내용으로 재등록하는 가용성 fallback은 금지한다.
  7. 한 write의 늦은 결과, 초기 읽기의 늦은 결과, 과거 reconcile 결과는 최신 요청·현재 generation의 UI를 덮지 않는다. 최신 의도가 같은 DB 값이면 불필요 write 및 dataRevision 증가는 없다.

DB 저장과 알림 적용을 구분하는 상시 표시

상태 표시 의미와 행동
최초 읽기 지연/실패 미확인/읽기 오류를 표시하고 미확인 스위치 조작을 막는다. 읽기 재시도를 제공한다.
최신 값 DB 저장 중 요청값과 ‘저장 중’을 표시한다. 반대 의도는 접수 가능하며 완료라고 하지 않는다.
write 실패, read-back 성공 실제 확정값과 아직 저장되지 않은 요청/오류를 구분한다. 명시적 재시도 또는 새 선택을 받는다.
write 실패, read-back 실패 현재 값 확인 필요. 가짜 OFF/ON 성공 및 추정값 기반 알림 조정을 하지 않는다.
OFF 저장 성공, 상세 취소 미확인 ‘끔으로 저장됨 · 기존 알림에 일정 이름이 남아 있을 수 있음’처럼 privacy 적용 미완료를 지속 표시한다.
OFF 저장 성공, 기존 취소 확인, private 예약 실패 저장값은 OFF로 유지하고 ‘일부 알림 예약 실패’ 또는 전달 공백을 알린다. 이전 상세 등록을 복원하지 않는다.
ON 저장 성공, 예약 일부 실패 ON 저장 사실과 일부 적용 실패를 구분한다. 성공한 대상만 근거에 맞게 집계한다.
관측 불가/영속 자료만으로 세부 privacy 결과 구분 불가 보수적인 ‘알림 적용 확인 필요’를 표시한다. 과거 원문을 보관해 상태를 추론하지 않는다.
전체 Schedule Notification Setting OFF 상세 선호는 저장 가능하되 ‘일정 알림 꺼짐’과 구분한다. 남은 취소 미확인이 있으면 감추지 않는다.
권한 부족 설정 저장 실패로 취급하지 않는다. 권한 상태 및 사용자가 선택하는 기존 설정 이동 경로를 제공한다. 자동 권한 팝업을 반복하지 않는다.
현재 eligible 미래 일정 없음 ‘예약된 알림 없음’. 저장 성공은 표시할 수 있으나 존재하지 않는 예약을 적용 성공 건수로 만들지 않는다.
알림 작업 Future 미반환 제한된 대기 뒤 ‘확인 지연’을 안내한다. timeout은 성공/취소 완료/owner 해제 의미가 아니며 중복 retry를 접수하지 않는다.

SnackBar는 보조 안내일 뿐 유일한 상태 저장소가 아니다. 재진입/resume에서 DB와 현재 coordinator의 조정·관측 상태를 다시 확인하여 미완료를 복구 표시한다. 실제 platform 관측이 지원하지 않는 사실은 ‘확인됨’으로 바꾸지 않는다. Android plugin cache와 실제 OS read-back의 차이는 A14 기준을 유지한다. pending 존재/등록 요청 성공이 미래 잠금화면 전달 보장은 아니다.

‘알림 다시 적용’은 현재 확정 선호를 읽어 delivery 단계만 재시도한다. 동일 선호를 DB에 다시 쓰거나 dataRevision을 증가시키지 않는다. read 미확정이면 임의 bool을 reconcile에 전달하지 않는다. 호출이 미반환 상태면 같은 진행 상태를 보여 주고 별도 provider 작업을 만들지 않는다. 새 generation 이후 구요청 재시도는 금지한다.

화면·생명주기·데이터 경계

  1. 화면은 저장/알림 적용 중에도 이탈할 수 있다. 접수된 최신 의도는 화면보다 오래 사는 현재 설치 generation 범위의 작은 상세 설정 controller/service가 계속 소유한다. 화면 dispose가 대기 중 OFF를 버려 앞선 ON만 남기는 동작은 허용하지 않는다.
  2. 재진입은 동일 진행 상태에 구독한다. 이탈 뒤 setState·SnackBar를 호출하지 않고 모든 Future 실패를 controller의 원문 없는 안전한 오류 유형으로 보관해 다음 구독에서 보여 준다. 다른 설정·일정 전체를 처리하는 전역 범용 큐를 새로 만들지 않는다.
  3. process kill 전에 DB에 저장되지 않은 메모리 의도의 보존은 약속하지 않는다. 재시작은 DB committed 선호와 기존 D03 journal/관측에서 현재 상태를 재구성한다. 새 durable preference intent journal은 만들지 않는다.
  4. restore/reset 시작으로 설치 generation이 바뀌면 아직 시작하지 않은 의도를 폐기한다. 이미 시작한 write가 새 DB에 침투하지 못하게 실제 gate/transaction 경계를 연계한다. await 뒤 UI 결과만 무시하는 것으로 충분하다고 간주하지 않는다. 이미 commit된 구세대 설정을 복원된 DB에 다시 쓰지 않는다.
  5. backup은 commit과 snapshot의 순서에 따른 기존 Backup Cutoff 계약을 유지한다. 컷오프 이전 committed 선호는 포함되고 이후 변경은 이후 active data로 남는다. 파일 선택 화면이 열린 시간만으로 설정 의도를 이전 snapshot에 소급 포함하지 않는다.
  6. 초기 Q1 응답의 ‘현재 screen/controller lifetime’은 화면 이탈 시 OFF를 버리라는 의미가 아니다. Q3에서 명시적으로 현재 설치 generation에 묶인 화면보다 긴 controller 소유로 정정했다.

한국어/영어에 이 row의 제목, private/detailed 허용 범위, 로딩·저장·취소 미확인·예약 실패·확인 지연·재시도 의미를 제공한다. 200% 글자 크기, 작은 휴대전화 너비, 스크린리더에서 checked/requested/busy/error 의미를 잃지 않게 한다. 단순 색상이나 애니메이션만으로 상태를 구별하지 않고 긴 경고문과 retry가 잘리거나 다른 설정을 가리지 않게 한다. 일정명·준비명 sentinel을 오류 메시지/로그/스크린샷 증거에 불필요하게 재사용하지 않는다. 앱 전체 localization은 U05다.

구현 경로와 의존성

범위 책임
lib/presentation/my_page/my_page_screen.dart 및 필요한 작은 상세 설정 controller/state 요청·확정·진행·오류·이탈/재진입 상태, KO/EN/접근성 UI. 현재 MyPage의 다른 설정과 Figma 구조를 보존한다.
lib/core/services/detailed_notification_preference_service.dart 또는 domain use case로 정리한 작은 설정 경계 DB read/write, 현재 generation 유효성, 최신 의도 직렬 실행. UI가 직접 여러 부작용을 조합하지 않게 하되 범용 전역 작업 프레임워크를 만들지 않는다.
lib/domain/use-cases/reconcile_alarms_use_case.dart, alarm_entities.dart 필요한 경우 최소 typed 반영 이유/요청 결과 연결을 확장한다. content 재작성·provider 정리 엔진을 복제하지 않는다.
LocalDataOperationGate, DB transaction/restore/reset 호출 경계 늦은 구세대 write 방지. UI의 generation 체크만으로 await 이후 실제 DB write를 보호했다고 주장하지 않는다.
lib/l10n/app_ko.arb, app_en.arb 및 기존 tracked l10n 산출물 U03 문구를 일관되게 현지화한다. 기타 ignored generator 출력은 commit하지 않는다.
test/presentation/my_page/my_page_screen_test.dart, 새 필요 controller/service 테스트, 실제 DAO·owner 통합 테스트 화면만 정상으로 보이는 fake 테스트에 그치지 않고 DB/최종 provider/실패 ownership을 함께 확인한다.

수용 기준과 검증 시나리오

Completer/barrier를 사용해 실제 await 경계에 지연·실패·후속 의도를 삽입한다. 임의 sleep이나 구현 필드 값만 검사하지 않는다. 합성 일정과 임시 DB/파일, 명시적 fake OS 상태로 UI·durable preference·provider 내용·최소 취소 증거를 함께 대조한다.

번호 시나리오 기대 결과
1 최초 read 지연 미확인 표시, 쓰기 0, 조작 비활성, false 저장 없음.
2 최초 read 오류→명시 retry 성공 예외 미누출, 읽기 오류/재시도 후 실제 저장값 표시.
3 초기 read 결과가 새 요청 뒤 늦게 반환 오래된 snapshot이 최신 UI/요청값을 덮지 않음.
4 OFF→ON 정상 허용 내용 설명, DB commit, 해당 요청의 현재 reconcile 결과를 구분해서 표시.
5 ON→OFF 정상 OFF commit 후 기존 상세 철회/비공개 재예약, 최신 private 결과 표시.
6 ON write 지연 중 OFF 접수 OFF 의도 유지, 과거 ON 결과로 신규 상세 예약 시작 안 함, 최종 DB/OS private.
7 ON→OFF→ON burst 최신 의도에 수렴하며 write/provider 병렬 중복 없음.
8 OFF/ON 동일값 중복 입력 불필요 DB revision 증가/중복 알림 작업 없음.
9 write 실패, read-back 이전값 미저장 오류와 실제 확정값 표시, 추정 rollback write 없음.
10 write 응답 실패지만 read-back 요청값 commit 사실과 OS 미확정 단계 구분; 같은 write 중복/리비전 증가 방지.
11 write와 read-back 모두 실패 unknown 유지, 성공 문구/임의값 재등록 없음.
12 OFF commit 후 기존 상세 취소 실패 OFF 유지, 이름 잔존 가능성 안내, tombstone 유지, latest private armed 거짓 성공 없음.
13 취소 확인 후 private 예약 실패 OFF 유지, 전달 공백 안내, old detailed 복원 없음.
14 여러 대상 중 부분 실패 성공 대상과 미확인 대상 혼동 없음, 전체 성공 안내 없음.
15 retry 후 회복 현재 DB값으로 delivery만 실행, 선호 write/dataRevision 증가 없음.
16 OS 관측 unavailable/unknown 확인 필요 표시, empty/success로 처리하지 않음.
17 권한 부족/전체 알림 OFF/미래 일정 없음 각각 저장 실패와 구별, 이전 cleanup 미확인 감추지 않음.
18 provider Future 미반환→UI 제한 대기 지연 안내, owner 유지, 중복 retry 불가, 늦은 반환은 원래 owner가 회수.
19 OFF 대기 중 화면 이탈→재진입 접수 의도 유실 없음, 동일 진행 상태 구독, disposed setState/SnackBar/Future 예외 없음.
20 resume와 사용자 입력 경합 현재값과 최신 결과만 반영, 오래된 resume read가 최신 선택을 덮지 않음.
21 restore/reset이 write 전/중/직후 진입 구세대 queued 의도 폐기, 구 write가 신세대 DB를 덮지 않음, 늦은 OS 결과도 기존 owner가 정리.
22 과정 중 프로세스 종료→재시작 미저장 intent durable 주장 없음, DB committed 값과 D03 journal만 사용해 현재 조정.
23 backup snapshot 전/후 preference commit Cutoff에 따라 일관된 값 포함, 새 plaintext intent/상세 payload 백업 없음.
24 schedule 변경/locale·zone 변경과 동시에 조작 A05 canonical 내용과 A15 최신 cutoff로 수렴; 허용되지 않은 민감 필드 없음.
25 unrelated 알림 및 active Preparation Step 존재 상세 Schedule Notification 처리만 수행, blanket cancelAll 없음.
26 KO/EN·작은 화면·200%글자·스크린리더 loading/requested/saved/applying/failed 의미와 retry 조작 접근 가능, 문구 잘림/overflow 없음.
27 privacy 원문 sentinel 새 상태·로그·journal·오류에 일정/장소/준비 원문 불필요 복제 없음.
28 Android/iOS 실제 설정 변경 기기별 허용 관측과 실제 새 잠금화면 표시를 구분해 기록, 미실행 provider는 미검증으로 남김.

실행 순서는 필요한 codegen, 변경 범위 focused tests, analyze, full Flutter tests 및 기존 CI 정책 검사다. 테스트 결과에는 실제 SHA와 실행 로그/CI URL을 기록한다. GitHub issue 문서 생성만으로 위 시나리오를 통과했다고 체크하지 않는다. 실기기에서는 합성 데이터로 상세 ON 예약→OFF→실제 미래 전달, 취소 미확인 안내, 재진입/권한 복귀를 확인한다. 기존 사용자 앱/시뮬레이터 데이터는 지우지 않는다. Android cache 관측, iOS pending/AlarmKit 관측, 실제 화면 전달은 각각 다른 증거로 적는다.

완료 체크리스트

  • 최초 읽기·write·read-back 실패에서 미처리 Future와 거짓 확정값이 없다.
  • 접수된 최신 의도가 빠른 조작·화면 이탈 중 보존되고 구결과가 최신 상태를 덮지 않는다.
  • ON/OFF DB 선호와 OS 적용 단계·privacy 취소 실패·예약 공백을 구분한다.
  • retry/resume/재진입이 현재 확정값으로 안전하게 수렴하며 불필요 DB revision·중복 owner가 없다.
  • restore/reset generation과 실제 write 경계를 통합 검증해 구세대 쓰기가 새 데이터에 침투하지 않는다.
  • privacy 기본값/허용 필드/최소 journal/A06 설정 의미와 기존 Figma UI를 유지한다.
  • 한국어/영어/200%접근성 검증 및 focused/analyze/full/CI 결과를 실제 SHA에 연결한다.
  • 지원 mobile provider별 실기기 증거와 미확인 제한을 남긴다. 미검증 기기 조건이 있으면 OPEN을 유지한다.

실제 grill-with-docs 문답 전체

스킬: /Users/ejunpark/.agents/skills/grill-with-docs/SKILL.md. 전담 agent는 먼저 스킬·고정 소스·CONTEXT·ADR 0030 및 A05/A14/A15/D03 문서를 읽었다. 코드로 답할 수 있는 현재 동작은 조사했고, 아래 정책 질문은 한 번에 하나씩 전송한 뒤 응답을 기다렸다. root 응답은 사용자가 위임한 의사결정이며 별도 사용자 인터뷰를 했다고 표현하지 않는다.

적용 및 조사 안내

Agent → root:

U03에서 grill-with-docs 스킬을 적용합니다. 고정 HEAD 074d5fd6의 상세 알림 설정·재등록 상태와 기존 도메인 계약부터 확인한 후, 코드로 결정할 수 없는 질문만 한 개씩 보내겠습니다.

질문 1 — 최신 의도와 저장 실패

Agent → root:

U03 질문 1/진행 방식. 고정 HEAD 074d5fd6의 상세 토글은 UI를 먼저 바꾸고 DB 저장을 await하며, 저장 중 재입력 차단/최신 의도 보존이 없습니다. A05는 DB에 저장된 OFF를 OS 실패 때문에 ON으로 되돌리지 말라고 정했지만, ON 저장·예약 중 사용자가 즉시 OFF를 누르는 정책은 아직 없습니다. 권장: 최초 읽기 성공 전에는 값 미확인+비활성·재시도, 읽은 뒤 조작은 최신 의도 1개를 유지하는 직렬 처리로 받습니다. 저장 중에도 OFF 요청을 접수해 바로 '끔 요청 중'으로 표시하되 확정 OFF/적용 완료라고 하지 않고, 앞선 write가 끝나면 최신 값만 commit합니다. 여러 write/OS 작업은 병렬로 만들지 않고 ON→OFF→ON burst는 최종 의도로 수렴합니다. 저장 실패 시 DB를 다시 읽어 확정값과 사용자가 요청한 값/미저장 오류를 구분하고 무한 재시도는 하지 않습니다. 단순 저장 중 스위치 잠금은 즉시 privacy OFF를 누를 수 없으므로 권장하지 않습니다. 이 최신 의도 접수 정책으로 확정할까요?

Agent → root, 추가 조사:

U03 추가 조사 사실: 현재 상세 토글의 _load 저장소 오류는 catch되지 않고 로딩이 유지될 수 있고, _change의 DB write도 catch 밖입니다. 재등록 결과는 partial/settingsUnavailable만 SnackBar로 보여 주며 화면 재진입·resume 때 상세 설정/적용 상태를 갱신하지 않습니다. 기존 테스트는 happy path와 DB commit 후 reconcile exception만 있어 DB 지연/실패·빠른 입력·disposed widget·generation 변경을 검증하지 않습니다. A14/A15/D03 계약을 UI에 연결하는 범위로 문서를 작성 중이며, 해당 하위 엔진을 완료 전으로 오인해 재설계하지 않겠습니다.

Root → agent (원문):

Q1권고채택. 초기읽기unknown은임의false표시/저장하지않고disabled+retry. 확인값/요청값/DB저장상태/OS적용상태구별, 최신의도1개직렬수렴. OFF요청은저장중에도받아끔요청중,아직비공개적용완료라하지않음. 이전ONwrite가이미DB반영될수있지만최신OFF대기중이면구형ON결과로새detailedOS등록을시작하지않도록currentness/A15후속요청경계에연결. 이미OS수락한ON은D03실제취소확인필요. write실패후authoritativeDBreadback으로확정/미저장구별,readback도실패면unknown이며ON/OFF성공거짓표시금지. 최신의도보관은현재screen/controllerlifetime내 ephemeral,restore/resetgeneration바뀌면폐기. 무한재시도없음,명시retry/새조작만재시도. 취소되지않는구형Future결과가최신UI/DB의도를덮지않아야함.

Q1의 lifetime 표현은 아래 Q3 답변에서 화면보다 긴 설치 generation controller로 정정되었다. 위 원문은 실제 의사결정 과정을 보존하기 위해 그대로 남기고 최종 계약은 Q3를 적용한다.

질문 2 — 반영 결과와 재시도

Agent → root:

U03 질문 2/DB 저장 후 알림 반영 실패와 재진입. 권장: 토글 체크값은 DB에 저장된 선호 또는 명확히 표시된 최신 요청값이고, 아래 상시 보조 상태를 별도로 둡니다. OFF 저장+기존 상세 취소 실패는 '끔으로 저장됨 · 기존 알림에 일정 이름이 남아 있을 수 있음'과 '알림 다시 적용'; 취소 성공+private 등록 실패는 '끔으로 저장됨 · 일부 알림 예약 실패'로 구분합니다. ON 저장+예약 실패도 저장값 유지, 권한 부족/알림 전체 OFF/미래 일정 없음은 각각 상태이지 저장 실패가 아닙니다. resume/재진입 때 DB와 최신 조정 결과를 읽어 이전 SnackBar가 사라져도 미해결 상태를 다시 표시하고, retry는 저장 재실행/DB revision 증가 없이 현재 선호로 알림 조정만 수행합니다. 조정이 반환하지 않으면 제한된 시간 뒤 '확인 지연'을 표시하되 Future/owner를 강제로 해제하거나 중복 retry를 만들지 않습니다. 기존 result만으로 privacy 철회 실패와 예약 공백을 구별할 수 없으면 U03에 필요한 최소 typed 결과를 확장합니다. 단순 '모두 적용됨/이름이 완전히 삭제됨' 보장은 하지 않습니다. 이 상태·재시도 계약을 확정할까요?

Agent → root, 진행 근거:

U03 문서 근거는 074d5fd642a2890dc48933dafcbd038534f759a4에 고정했습니다. A06 변경 중 파일은 git show로만 확인했고, 제품·테스트·공유 문서는 수정하지 않았습니다. 질문 2 답변 뒤 화면 이탈 시 접수된 OFF 의도/restore·reset 경계를 마지막 질문으로 확인하겠습니다.

Root → agent (원문):

Q2채택. OFF저장후취소미확인은기존일정이름이남을수있음,취소확인후private등록실패는예약공백으로구분. unknown/관측불가를비공개완료라하지말고보수적확인필요. 현재공통result불충분시최소typedreason확장가능하되새private원문/영속detailedpayload추가금지,과거내용보존으로상태추론하지않음. ON/OFF저장값OS실패때rollback안함. 전체알림OFF/permission/noUpcoming은별도표시,active step알림은A06설정의미유지. 재진입/resumeDB+최신coordinator관측갱신,이전snackbar에의존않음. retry는기존현재값read후조정만,동일값DB쓰기/revision증가없음. 미반환Future동안확인지연안내+retry중복불가,시간초과소유권해제금지. save미확정readback실패는재조정에임의값을넘기지않음. 영속된자료만으로privacy철회상태를구체확정못하면일반확인필요로안전하게설명.

질문 3 — 화면 이탈과 데이터 세대

Agent → root:

U03 질문 3/화면 이탈과 데이터 세대. ON write 대기 중 OFF가 접수됐는데 사용자가 뒤로 나가면 화면 dispose가 OFF 의도를 버려 ON만 저장되는 위험이 있습니다. 권장: 화면은 즉시 이탈 가능하되, 접수된 최신 의도는 화면보다 긴 설치 세대 범위의 작은 controller/service가 DB write와 후속 조정까지 계속 소유합니다. controller는 전역 범용 작업 큐가 아니며 한 상세 설정 흐름만 담당하고, 재진입은 같은 진행 상태에 구독합니다. 이탈 후 setState/SnackBar는 없고 catch되지 않은 Future도 없어야 합니다. process kill 전 미저장 의도는 durable하다고 약속하지 않으며 재시작은 DB만 읽습니다. restore/reset 시작의 generation 변경은 아직 시작 안 한 의도를 폐기하고 이전 세대 write가 새 DB에 침투하지 않게 gate/transaction 경계를 조정합니다; 이미 commit된 값은 복원 DB를 덮는 재적용 대상이 아닙니다. 실제 snapshot 진행 중 backup은 commit 순서의 Cutoff대로 포함되며 새 intent journal을 만들지 않습니다. 이 방식으로 확정할까요? 저장 완료까지 화면을 잠그는 대안은 이탈 마찰과 무응답 차단 때문에 비권장입니다.

Agent → root, 추가 경계:

U03 추가 경계: 현재 getAlarmSettings는 profile row가 없으면 기본 false를 반환합니다(UserDao L141–149). 새 설치의 확정된 private 기본값과 restore/reset/초기화 중 아직 읽을 수 없는 프로필을 구분해야 하므로, U03 controller는 active Local Profile/gate readiness가 확인된 경우에만 이 기본값을 읽어 보여 주는 계약을 적겠습니다. 임의 empty profile 생성이나 DAO 기본값 전면 변경은 D01/C01 범위를 침범하지 않습니다. 새 도메인 용어/ADR은 필요 없고, confirmed/requested/applying 같은 UI 상태는 구현 개념으로만 둡니다.

Root → agent (원문):

Q3채택. Q1의'현재screen/controllerlifetime내'는화면dispose때접수된OFF까지버리는뜻이아님을정정: controller는현재설치generation내에서화면보다길게소유,재진입동일진행구독,processkill미저장보장없음. 설치generation변경시queuedintent폐기, in-flight write가새DB에침투못하도록기존gate/transaction연계(단순afterawait UI검사만으론부족), commit된구세대설정복원DB에재적용금지. backupcutoff동작도권고채택,새영속intentjournal추가안함. 화면이탈가능,실패는controller안전상태로보관하고다음구독에표시; 원문없는오류유형만. activeProfile/gate readiness확인없이DAOdefaultfalse를성공읽기로쓰지않는추가경계채택. 초기설치온보딩엔기존private기본정책유지,빈profile임의생성없음. 새용어/ADR없음. 실제3문답과이정정/추가근거모두포함U03.md작성동결해주세요.

문서 작성 시 실행 경계

이 세션에서 수행한 것은 스킬·고정 소스 읽기, 실제 3문답, 이 이슈 명세 작성뿐이다. 제품 코드, 테스트, QA 도구, shared CONTEXT/ADR, state/README를 변경하지 않았다. Flutter 실행, git mutation, GitHub 게시를 수행하지 않았다. 문서 게시와 실제 구현·검증은 root가 우선순위 흐름에서 별도로 수행한다.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions