Files
Aislo/docs/raw/plans/2026-08-29_plan_initial_snapshot_reset.md
T
eomsangdonandClaude Opus 5 eb30b774f8 chore(docs): docs 폴더 git 추적 전환 · PLAN·OWNERS 최상위 이관
- `docs/` 를 .gitignore 에서 빼 git 추적 대상으로 전환 (위키·완료 이력·검증 기록)
- `docs/raw/PLAN.md` · `docs/raw/OWNERS.md` 를 저장소 최상위로 이동 후 .gitignore 에 등록
  — 창끼리 공유하되 저장소에는 안 올리는 장부
- 살아 있는 경로 참조 7개 파일 정정 (아카이브 107건은 그때 사실이라 그대로 둠)
- graphify 날짜별 산출물(`docs/wiki/graphify-out/20*/`) 제외 — `graphify update` 가 다시 만듦

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-09 18:19:07 +09:00

8.0 KiB

B03/B05 초기값 스냅샷 기반 초기화 완료 아카이브

  • 완료일: 2026-08-29
  • 상태: 사용자 검증 완료
  • 검증: docs/raw/verification/2026-08-29_verify_initial_snapshot_reset.md
  • 검증 방식: 사용자 실무 검증 채택, Codex 2차 교차검증 생략

완료 범위

초기값 스냅샷 기반 [초기화] (2026-08-29 구현 완료 — 검증 대기)

배경 — 현행 [초기화]는 복원이 아니라 재생산이다. DELETE FROM routesrun_auto_design_chain()을 처음부터 다시 돌린다(B05_Profile_Router.py:608). 초기값을 콕 집어 부를 수 없는 이유는 두 가지다.

  • routes에 초기값/변경값 구분이 없다(001_create_schema.sql:284status는 DRAFT/CONFIRMED/ARCHIVED뿐).
  • [저장]·[확정]이 새 행을 만들지 않고 최신 행을 제자리 갱신한다 (confirm_latest_routeconfirm_route(connection, latest["id"])). 종단·횡단 정본 파일도 덮어쓴다. 초기 상태가 물리적으로 남지 않는다.
  • 게다가 현행 초기화는 DB만 지우므로 structures.json·edits/pipe_points.json은 살아남아, 재계산 결과가 초기값과도 다르다(구조물 측점이 편집분에서 파생).

사용자 확정(2026-08-29) — 초기연산 결과를 초기값으로 영구 보존하고, [초기화]는 그 초기값을 되돌려 놓는다. 재계산하지 않는다.

설계

  • 스냅샷 시점: run_auto_design_chain() 성공 직후 1회 (B03_FileInput_Service_Chain.py 5)단계 뒤, return 직전). 재계산 체인 (run_redesign_chain)에서는 만들지 않는다 — 초기값은 최초 1회뿐.
  • 저장 위치: 프로젝트 저장소 아래 initial_snapshot/ (stage 폴더와 형제, PROJECT_STORAGE_LAYOUT_V2에는 넣지 않는다 — 워크플로 단계가 아니다).
  • 파일 스냅샷(그대로 복사): B05_Profile/route/ · B06_Section/longitudinal/ · B06_Section/cross_sections/ · {배수유역}/edits/ (common_util_drainage_pipes.edits_dir).
  • DB 스냅샷: routes 1행 + FK 자식 4개(route_points·route_statistics· longitudinal_sections·cross_sections)를 JSON 덤프로 같은 폴더에 남긴다. 스키마상 route_id를 참조하는 표는 이 4개가 전부다(001_create_schema.sql:539~556).
  • 복원(=[초기화]): DELETE FROM routes → 덤프에서 routes 1행 INSERT(새 id) → 자식 4표를 새 route_id로 INSERT → 파일 스냅샷을 위 4개 경로에 덮어쓰기 → prune_corridor_files()로 주인 없는 코리도 정리. 자동 설계 체인 호출 없음.
  • 폴백: 스냅샷이 없으면(옛 프로젝트) 지금의 재계산 경로를 그대로 탄다.

체크리스트

  • common_util/common_util_initial_snapshot.py 신설 — save_initial_snapshot() · load_initial_snapshot() · has_initial_snapshot(). 파일 복사와 JSON 덤프 한 벌만 담는다(700줄 제한 여유).
  • B03_FileInput_Service_Chain.run_auto_design_chain() — 성공 반환 직전 save_initial_snapshot() 호출. 실패는 비치명적(로그만) — 체인 규약과 동일.
  • B05_Profile_Router.reset_route_design() — 스냅샷이 있으면 복원 경로, 없으면 기존 재계산 경로. 응답 스키마(RouteResetResponse)는 유지하고 restored: bool만 더한다.
  • 프론트 B05_Profile_Api_Fetch.RouteResetResponserestored 추가. 복원이면 분석용 긴 타임아웃이 필요 없으나, 폴백을 위해 타임아웃은 그대로 둔다.
  • 세션 캐시 정리는 현행 resetDesign() 그대로 둔다(이미 B05·B06 양쪽을 비운다).
  • 정본 파일 덮어쓰기 확인 — 복원이 structures.json·edits/pipe_points.json을 스냅샷본으로 되돌리는지 테스트로 못박는다. 현행 초기화가 이 둘을 남겨 두는 것이 초기값 오염의 실체다(2026-08-29 사용자 확인).
  • 테스트 tmp/tests/test_initial_snapshot.py — ① 저장 후 파일·덤프 존재 ② 편집·저장 뒤 초기화하면 route 행 수 1, 종단 정본 파일이 스냅샷과 동일 ③ 스냅샷 없는 프로젝트는 재계산 폴백.
  • 화면 실측(2026-08-29) — 아래 「화면 실측」 절 참조.

확정 (2026-08-29 사용자)

  • 자동저장은 폐지한다. 사용자 조작분은 세션 캐시에 담고 [저장]·[확정]에서만 영구저장소에 쓴다 — 별도 항목 「자동저장 폐지…」 참조.
  • 스냅샷은 사용자 첫 접근 이전에 찍히고 그 뒤 읽기 전용이므로, 자동저장이 남아 있든 없든 초기값 자체는 오염되지 않는다.
  • 현재 조작 속도는 불편하지 않다. 성능이 아니라 초기값 보전이 이 작업의 목적이다.

구현 메모 — 복원은 DELETE FROM routes같은 트랜잭션 안에서 끝낸다(지우기만 하고 실패하면 경로가 없는 프로젝트가 된다). 파일 복원은 트랜잭션 밖 asyncio.to_thread. 스냅샷 파일 트리는 폴더명을 B05_Profile__route처럼 평탄화해 담는다.

  • 자체검증(2026-08-29) — tmp/tests/test_initial_snapshot.py 5 passed: ① 파일 4트리 + DB 덤프 촬영 ② 촬영 뒤 정본을 고쳐도 스냅샷 불변(읽기 전용 층) ③ 복원이 편집된 pipe_points.json을 초기값으로 되돌리고 스냅샷에 없던 파일은 남기지 않음 ④ 자식 4표가 새 route_id로 다시 들어가고 id 열은 비워짐 ⑤ 스냅샷 없으면 None(재계산 폴백). ruff format·check 통과. 실제 DB·화면 왕복은 미검증 — 공용 브라우저 확인 필요.

화면 실측 — 진짜 초기값 재생산 겸 검증 (2026-08-29, 사용자 승인 후 실행)

배경: 검증 대상 프로젝트(c1bb453f…)는 기능 추가 전에 만들어져 initial_snapshot/이 없었고, [저장]이 정본을 덮어써 진짜 초기값이 남아 있지 않았다. 자동설계 체인은 계획노선 CSV + config 기본값으로 도는 결정적 절차이므로 편집 정본만 걷어내고 다시 돌리면 원래 나왔어야 할 값이 나온다 — 종전 [초기화]가 그걸 못 하던 이유가 정확히 structures.json· edits/pipe_points.json을 안 지운 것이었다.

절차

  1. 백업 — tmp/backup_before_initial/에 storage 152파일 + routes·자식 4표 덤프 (스크립트 tmp/reconstruct_initial.py, backup/show 단계).
  2. 편집 정본 2개 삭제 — 자동 권한 검사가 파일 삭제·이동을 막아 사용자가 직접 지웠다.
  3. 공용 브라우저에서 B05 [초기화] 클릭(확인 모달 → 스냅샷이 없으므로 재계산 폴백).

결과

항목 초기값(route 102) 직전 작업본(route 101)
연장 350.11m 350.11m (계획노선 CSV가 같으니 동일)
횡단 측점 23 25
관 지점 4 6
구조물 0 (structures.json 없음) 0

줄어든 측점 2 · 관 2가 곧 사용자가 손댔던 몫이다. 초기 관 배치는 전부 자동 산출이다 — 4+4.3 배수관(spacing) · 7+9.7 세월교(stream) · 10+0.9 BOX암거(spacing) · 13+15.7 배수관(spacing).

체인이 스냅샷을 스스로 떴다 — 따로 부르지 않았다. initial_snapshot/db.json에 routes 1 · route_points 135 · route_statistics 1 · longitudinal_sections 1 · cross_sections 23(route 102 · CONFIRMED · 350.11m), 파일 4트리(cross_*.json 23개 포함). DB 값과 일치한다. 토스트 "초기 계산 상태로 되돌렸습니다." 확인, 10초 안에 완료.

남은 것

  • 복원 경로(restored=true)는 아직 미실측이다. 이번 클릭은 스냅샷이 없던 마지막 폴백 실행이었고, 그 실행이 초기값을 만들면서 동시에 촬영했다. 이제 스냅샷이 있으므로 다음 [초기화]가 복원 경로를 탄다 — 그때 route 행 재삽입·정본 파일 되돌리기·응답 restored를 실측한다.
  • 현재 작업본 = 초기값(route 102). 직전 설계(route 101)는 tmp/backup_before_initial/ 에만 있다. 되살릴지 초기값 상태로 둘지는 사용자 판단.