- `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>
53 KiB
일하는 법 · 검증 함정 — 겪은 것에서 (2026-09-07 ~ 09)
상시계획서
PLAN.md「참고」에서 옮긴 원문임. 줄이지 않았음. 옮긴 까닭 — 계획서의 「참고」는 코드 작업 중 필요한 기준표·확정사항만 두기로 되어 있는데 여기 든 것은 기준표가 아니라 일하는 법임(2026-09-09 사용자 지시 「반영」). 다음 세션이 계획서보다 먼저 읽을 것. 계획서 「참고」에는 이 파일 링크만 남겼음.든 것 — 일하는 법 열둘 · 좁은 폭 화면 깨짐 · vite 캐시 · 공용 이름 바꾸기 · [저장]과 횡단 재계산 · 공용 브라우저 조작 주의 셋 · 검증 함정 모음.
⚠⚠ 일하는 법 넷 — 2026-09-07 두 창이 겪은 것에서 (다음 세션이 먼저 읽을 것)
이 절의 값어치는 같은 사고를 다시 겪지 않는 것이다. 넷 다 하루에 여러 번 나왔다.
㉠ 「숫자가 늘어난 것」은 좋아진 신호가 아니다
배분율 표 25건이 살아났으나 그게 10 % 짜리였고, 2단 표 165줄이 늘었으나 상당수가 오독이었다. 늘어난 뒤에는 반드시 최대·중앙값과 손대조를 볼 것. (그래서 산출 요약에 최소·중앙·최대를 붙였다 — 8-22 ③.)
㉡ 넓은 규칙이 정상 값을 지운다 — 하루에 여덟 번 (두 창에서 넷씩)
① 배합 검사가 막자갈을 오탐 ② 자원 필터가 정상 자원 70/745 를 지움 ③ 비율 지시를
먼저 봐 강관동바리 소요량표가 참조로 넘어감 ④ 머리글 필터가 등급 글자(상·중·하)를 지움
⑤ 「당」을 느슨히 잡아 (무한궤도,0.7㎥) 를 밑수로 읽음 ⑥ 식 칸 집계가 비고 설명문까지
걸어 93 → 31 로 좁힘 ⑦ 「값 못 읽은 줄」 판정이 값이 없는 게 당연한 머리 줄까지 세어
28 → 12 ⑧ 표 안 긁기가 비고의 「10㎡」를 그 표의 밑수로 물어 옴.
⑨ REFERENCE_MARKS 의 「단 위」 하나가 공종 41건을 참조로 버림 — 그 안에
돌쌓기(장비) 13-4-5·13-4-2(우리 매핑이 매일 쓰는 코드)가 있었다. 규모가 가장 컸다.
⑩ 자간 공백 이름 세기가 「단 위」·「모 래」까지 걸어 101 → 20 으로 좁힘.
⚠ ⑦ 은 이 병을 다섯 번 잡아 놓고 새로 하나 만든 것이다. 원인은 짝 시험을 그 자리에 같이 안 둔 것. 세기 전에 「이건 세면 안 된다」 쪽 표본을 먼저 정해 둘 것.
⚠ ⑨ 의 진단이 이 절의 처방이다 — 그 표지의 원래 겨냥(품셈 1-2-2 「단위 표준」)은 chapter 규칙이 이미 거르고 있었다. 즉 넓기만 하고 얻는 것이 없었다. ⇒ 넓은 규칙을 만나면 그것이 실제로 무엇을 더 잡는지 세어 볼 것 — 다른 규칙과 겹치면 얻는 것 없이 잃기만 한다. 규칙을 지울 근거는 「안 잡히는 것」이 아니라 **「이미 다른 규칙이 잡고 있는 것」**이다.
⚠ 정규화는 값을 살리지만 잘못된 줄도 함께 살린다 (2026-09-07 서브 창 실례).
기종 이름 공백을 지워 빠졌던 장비 몫을 살렸더니, 같은 표의 버킷계수 K 를 소요량으로 읽어
시간당 사용료가 이중이 될 뻔했다. 살리는 규칙에도 짝 시험을 둘 것.
⇒ 규칙을 새로 둘 때마다 「걸려야 한다」와 「걸리면 안 된다」 짝 시험을 함께 둘 것.
⇒ 값을 지우는 규칙은 좁게, 표시만 하는 깃발은 넓게. 깃발은 넓어도 값이 안 사라진다
(partial_ratio 를 몫 유무로 넓게 잡은 판단이 그것).
㉢ 검사가 도는 줄 알았는데 안 돌고 있었다 — 하루에 네 번
① 가드를 만들어 두고 안 부름 ② 지문 장치가 원판 지문을 봐서 안 움직임
③ npx tsc 가 엉뚱한 패키지를 실행(이 저장소는
node ./config/node_modules/typescript/bin/tsc --noEmit 로 부를 것)
④ 사방공에 없는 type_id 를 적어 영영 안 걸릴 뻔함.
⇒ 새 검사·장치는 일부러 깨뜨려 보고 실제로 잡히는지 확인할 것. ⇒ 이름으로 무언가를 알아보는 코드는 정본(레지스트리·마스터)과 대조하는 시험을 둘 것.
㉤ ⚠ 먼저 원문부터 뒤진다 — 「관측값인 줄 알았는데 법이었다」가 여덟 번
여덟 다 「실무 관측값을 쓰자」·「사용자에게 물어야 한다」로 시작했다가 품셈 원문에 이미 정해져 있는 것을 찾았다. 뒤 여섯은 2026-09-08 재조사에서 네 창이 동시에 건졌다.
| 물음 | 처음 생각 | 원문 |
|---|---|---|
| 거푸집을 몇 번 쓰나 | 관측값 병용 | 품셈 1-7-1 — 「3회 … 옹벽, 파라펫트, 날개벽」 |
| 철근 갈래가 무엇인가 | 사용자에게 물음 | 품셈 12-3 [주]① — 「보통: 수문, 반중력식 옹벽 및 교대」 |
| 덤프 t↔㎥ 환산 γt | 지식DB 에 없음 | 품셈 10-12-1 [주]② — 토사 1.9 · 암 2.4 t/㎥ |
| 공구손료 밑수·제잡비와의 관계 | 두 문서가 어긋남 | 건설품셈 1-2-6 — 「명시된 것은 그것을 계상, 명시 안 된 것만 별도」·「인력품의 3%까지」 |
| 야면석 개수·중량 원단위 | 실무값밖에 없음 | 품셈 13-4 「돌쌓기의 개수 및 중량의 표준」 — 0.575 / 0.88 / 1.10 |
| 물빼기 구멍 간격·지름 | 사용자에게 물음 | 품셈 13-4-4 [주]④⑤⑦ — 2 |
| 돌쌓기 전면 기울기 | 사용자에게 물음 | 품셈 13-4-4 「표준경사」 표 — 직고×메찰×성절토 20칸 |
| 돌쌓기 뒷길이 규격 | 우리 표 네 칸이 전부 | 품셈 13-4-4 「뒷길이 표준」 표 — 일곱 규격, 높이별 |
⇒ 「이건 관측값밖에 없다」·「이건 사용자가 정할 값이다」로 넘어가기 전에 품셈 원문 본문(표가 아니라 표 앞뒤 [주]·안내 줄)을 먼저 볼 것. 밑수도 같은 자리였다 — 표 안이 아니라 표 바로 위 본문에 있었다.
⇒ 「지식DB 전수 확인: 없음」은 원문까지 안 보면 절반만 본 것이다 (2026-09-08 넷으로 굳음). 지식DB 는 요약·후보 가이드라 원문의 [주]·부속 표가 옮겨지지 않은 자리가 많다. 조사 보고에 「원문 어디까지 봤나」를 함께 적을 것 — 파일명·줄번호가 없으면 「안 본 것」으로 친다.
⇒ 원문에 표가 있으면 물음이 「값」에서 「축」으로 바뀐다. 전면 기울기가 그랬다 — 높이·메찰·성절토를 우리가 이미 아니까 값은 자동으로 정해지고, 남은 물음은 「품셈 축(높이·성절토)과 교본 축(시설 종류) 중 어느 쪽이냐」 하나였다.
⇒ 판정할 수 있는 것을 사람에게 물으면 그것이 곧 미결이 된다. 물음 목록이 길어질수록 사용자가 답할 수 있는 물음이 묻힌다. 실제로 「철근 갈래 전체」를 물으려던 것이 원문 확인 뒤 「캔틸레버식 옹벽 하나」로 좁아졌다.
㉪ ⚠ 계약이 바뀌면 시험부터 의심할 것 — 이틀에 열두 번
2026-09-08 네 번 (덧곱 · 구조물 한 줄 · 사방공 이름 · 뒷길이 접기) 2026-09-09 여덟 번 — 사용자 확정을 붙일 때마다 옛 시험이 옛 계약을 지키고 있었음:
버림 콘크리트 「없음」을 못 박은 둘 (구조물 한 줄 · 큰돌쌓기 성분 집합)
층따기 「막힌다」를 못 박은 둘
기울기 「늘 1:0.3」을 못 박은 셋 (실무 시트 대조 시험 포함)
stone_supply 기본값을 「근거 없음」으로 잡은 둘 ← 근거를 적어 예외로 뺌
⇒ 사용자 확정이 오면 「어느 시험이 옛 계약을 지키고 있나」를 먼저 찾을 것. ⚠ 검사를 눅이지 말 것 — 근거를 문장으로 적어 예외로 빼는 것과, 검사 자체를 약하게 만드는 것은 다름.
옛 시험이 틀린 계약을 못 박고 지키고 있던 자리. 실물:
def test_표에_없는_뒷길이는_덮는_칸으로_접을것():
assert _back_length({"back_len_cm": "25"}) == 35
assert _back_length({"back_len_cm": "75"}) == 60
「접는 것」이 옳다고 시험이 지키고 있었음. 그런데 접을 까닭이 아예 없었음 — 품셈이 일곱 규격(25·30·35·45·55·60·75)을 다 주는데 우리 표가 네 칸만 들고 있었을 뿐임 (실무 라이브러리가 네 칸만 옮겨 적은 것을 그대로 받았음).
⇒ 시험이 있다는 것이 「맞다」는 뜻이 아님. 값이 나오면 아무 시험도 안 잡음(㉣ 과 한 벌).
곁들여 같은 자리에서 나온 것 둘
- ⚠ 원문이 「-」인 칸에 0 줄을 만들지 말 것 — 25㎝ 고임돌이 0.0 으로 서고 있었음. 0 은 「없음」과 구별이 안 되고 받는 쪽이 「값이 0 인 자재」로 읽음. 줄을 빼고 사유를 낼 것.
- ⚠ 고른 갈래의 빈 칸은 빈 칸으로 덮을 것 —
None이라고 안 덮었더니 「야면석 75㎝」에 종전 값(깬돌 0.25)이 조용히 섰음.
㉦ ⚠ 저장 제원의 키 이름과 엔진이 읽는 키 이름을 대조할 것
레지스트리는 back_len_cm 인데 엔진이 stone_back_length_cm 을 읽고 있어 저장값이
영영 안 닿고 늘 기본 45㎝ 로 돌았다. 사용자가 뒷길이 75 를 골라도 45 계수가 붙었다.
⇒ 오늘 잡은 「조용히 틀린 값」 가운데 사용자가 고른 값이 직접 버려진 첫 사례다. 앞의 것들은 우리가 원문을 잘못 읽은 것이었는데 이건 사용자 입력이 무시된 것이라 성격이 더 나쁘다.
⇒ 「이름으로 알아보는 코드는 정본과 대조하라」(㉢)의 데이터 키 판이다. 대조를 시험으로
둔다(test_b08_option_keys.py). 「칸이 아예 없는 것」과 「이름이 어긋난 것」은 다른 것이라
가려 적는다 — 앞은 「칸이 생기면 받는다」이고 뒤는 버그다.
㉥ 폴더 튐은 「내 것이 없어진 것처럼 보이는」 착시까지 만든다
2026-09-07 두 창이 한 저장소에서 일하며 폴더 튐이 네 번 났다. 그중 하나는 상대 창이 **남의 폴더 파일을 읽으며 「내 코드가 사라졌다」**고 판단한 것이었고, 자기 폴더에서는 멀쩡했다.
⇒ 「내 변경이 사라졌다」고 느끼는 순간 먼저 현재 폴더부터 확인할 것. 그 상태에서
「복구」에 손대면 없어지지 않은 것을 되살리려다 멀쩡한 것을 덮는 진짜 사고가 된다.
⇒ push 전에 git status 로 남의 파일이 섞였는지 볼 것(OWNERS 규칙 2). 남의 파일이
보이면 경로를 지정해 커밋하고 자동 스크립트를 쓰지 말 것 — 폴백이 주워 담는다.
㉣ 「값이 있기는 하니 안 보이는」 것이 가장 위험하다
씨앗뿜어붙이기 합계 68.8원 · 측구터파기가 인력 10 % 몫만 · 운반 표가 [확정] 뒤 0줄 · 부분 성공한 표가 엉뚱한 직종에 붙음. 부분 성공이 완전 실패보다 위험하다 — 실패는 눈에 띄고 부분 성공은 안 띈다.
⇒ 「0 이 아님」이 아니라 「크기가 말이 되나」로 잴 것.
⚠ 그 반대 짝도 있다 — 「값이 맞는데 이상해 보이는」 경우. 반영률이 전부 100 % 라 성토면다짐과 층따기가 같은 수로 나온 것을 「곱하기가 빠졌다」로 오진한 일이 있었다 (두 계열이 같은 사면 면적에서 나오므로 원래 같다). ⇒ 「두 값이 같다」를 만나면 코드보다 설정·입력을 먼저 읽을 것.
㉧ 양쪽 근거가 다 있으면 한쪽으로 몰아 보고하지 말 것 (2026-09-08)
교차검토에서 「제잡비 3% 의 밑수에 굴착기 조종원 노임이 들어가는가」가 나왔음. 산림품셈 13-6-2 [주]③ 은 「노무비의 합계액」이라고만 하고 그게 무엇인지 정의를 안 함. 근거가 양쪽에 다 있었음 —
| 쪽 | 근거 |
|---|---|
| 사람 품만 | 건설품셈 제8장이 같은 「제잡비율」을 「직접노무비」로 못 박음. 기계를 밑수에 넣을 때는 「노무비, 기계손료 및 운전경비의 합」이라 따로 적음 |
| 노무비 계정 전체 | 우리 원가 체계에서 「노무비」와 「직접노무비」는 다른 말이고, 중기 운전사 노임도 같은 노임표에서 옴 |
한쪽만 실어 보냈으면 받는 창이 그대로 받았을 것임. 양쪽을 나란히 놓자 조율 창이 자기 앞 판정을 뒤집었음(「사람 품만」으로 확정, 미결 ㉮ 로도 올림).
⇒ 판단은 받는 쪽이 함. 반대 근거가 없으면 판단 자체가 안 됨. ⇒ 문구가 갈리는 자리는 「같은 규정이 다른 데서는 어떻게 쓰였나」를 볼 것 — 이 건은 **「넣을 땐 넣는다고 쓴다」**가 갈랐음. ⇒ 그리고 그 조항이 무엇을 사는 값인지 읽을 것 — 제잡비는 「콘크리트 버켓 손료·다짐기계 손료」, 즉 본 자원에 안 선 잔 기계임. 그 표에 굴착기는 이미 본 자원으로 서 있으므로 잔 기계를 그 굴착기 조종원 노임에 비례시키는 것은 뜻이 어긋남.
⚠ 이 자리는 어떤 시험도 안 잡았음 — 값이 나오고 자원 넷이 원문과 정확히 맞았음. 손대조로 차액을 역산해서야 밑수가 드러났음(㉣ 「크기가 말이 되나」의 한 단 아래).
⇒ 그리고 「없다」를 확정하기 전에 「어디에 없나」를 볼 것 (2026-09-08 ㉗). 품셈에 없다는 것이 답이 없다는 뜻은 아님. 같은 날 둘이 그랬음 — 지장목제거는 품셈에 공종이 없을 뿐 수량은 법령이 요구하고 실무가 같은 산식으로 세고 있었음, 입목 본수는 조사값이 아니라 우리 저장소가 재료(원본 LAS·다중 리턴)를 이미 갖고 있었음. ⇒ 찾을 자리는 셋임 — 품셈 · 다른 문서(법령·교본·실무) · 우리가 이미 가진 것.
**⇒ 값이 움직였는데 코드 diff 에 없으면 남의 창을 먼저 볼 것 (2026-09-08).
DB 는 원격 공용 서버 한 대(dsm.chemifactory.com)라 네 환경이 같은 자료를 쓴다.
어느 창이든 [확정]·[저장]을 부르면 나머지 셋의 값이 그 자리에서 바뀐다 — 코드를 하나도
안 건드려도 바뀐다. 실제로 성토가 +1.14 % 움직였고 원인은 랩탑의 실화면 검증이었다.
⚠ cross_sections 표에 시각 칸이 없어 언제·누가 바꿨는지 DB 로는 못 짚는다.
짚는 순서는 ① 커밋 diff 로 코드 배제 ② 서버 로그로 내 창 배제 ③ DB 재계산으로 「후」 값 확인
④ 파일 mtime 으로 시각 잡기. 되받기 전후로 tmp/snapshot_b08.py 를 떠 두면 대조가 된다.
㉩ ⚠ md 에 없으면 원본(pdf·xlsx)을 열어 볼 것 (2026-09-08)
변환본이 원본을 못 따라가는 자리가 있음. 「돌쌓기 표준도 그림이 저장소에 없다」고 판단해 원본 확보를 요청하려 했는데, PDF 원본(173쪽)이 이미 저장소에 있었음. md 로 옮길 때 그림 폴더를 안 받아 둔 것이었고, PDF 에서 그대로 뽑아 넣으니 끝났음.
- 오늘 같은 계열이 셋임 — 표가 코드를 못 따라감(8-25 화면 칸이 낡음) · 내 출력이 실물을 못 따라감(옵션 넷만 골라 찍고 「빠졌다」로 오해) · 변환본이 원본을 못 따라감(이번).
- ⇒ 「없다」를 말하기 전에 원본 형식(pdf·xlsx·las)을 한 번 볼 것. 특히 그림·서식·병합셀은 텍스트 변환에서 빠지기 쉬움.
㉨ ⚠ 「사유」 칸에는 왜 막혔나만 — 설명은 비고로 (2026-09-08, 하루에 세 번)
받는 쪽은 사유 칸을 「상태」로 읽는다. 설명을 거기 적으면 그 줄이 통째로 막힌 것이 된다.
- 겹침 설명을
blocked_reason에 넣었더니 B09 가 「막힌 줄」로 읽어 금액을 안 붙였음. blocked_kind: None— 「다른 표에서 이미 섬」은 막힌 것이 아니라 여기서 세면 안 되는 줄임. 막힘으로 보내면 받는 쪽이 「만들어야 할 것」에 얹어 결국 이중계상으로 감.- 사유를 뭉뚱그리면 할 일이 갈리지 않음 — 「일위대가 없음」 하나로는 「아직 안 만든 것」과 「성분이 빠져 못 세운 것」이 구분되지 않음. 앞엣것은 우리가 만들면 되고 뒤엣것은 참조 대상을 이어야 풀림. 사유를 갈라 적으니 다음 일감이 바로 보였음.
⇒ 사유 칸은 「왜 막혔나」만. 설명·계산 경위는 비고로. 그리고 사유를 갈라 적을 것.
㉫ ⚠⚠ 법이 두 동작을 묶은 자리 — 앞 동작만 세고 있지 않은지 (2026-09-09, 하루에 두 번)
막힘 목록에도 없고 어떤 검사에도 안 걸리는 자리임. 줄이 서 있고 값도 맞으니 「없는 줄」을 아무도 못 봄. 오늘 둘 다 별표2 원문을 읽다가 나왔음.
표토 별표2 「표토는 전량 **제거한 후** … 최고 홍수위보다 높은 장소로 **운반하고 쌓아두어야**」
우리 — 표토제거(9-15) 한 줄만. **운반·적치가 없었음**
뿌리 품셈 9-20 가. 「벌개·제근 → 뿌리다듬기 → **적재** → **운반**」 (시공 과정 표준)
별표2 「입목…과 **그 뿌리**, 표토는 전량 제거한 후 … 운반하고 쌓아두어야」
우리 — 「제근·뿌리다듬기」 한 줄뿐. **적재·운반이 없었음**
⇒ 어떻게 찾나 — 원문에서 동사가 둘 이상 이어진 문장을 볼 것.
제거한 **후** … 운반하고 쌓아두어야 · ~하고 ~하여야 · → 로 이어진 과정 표준.
앞 동작에 우리 줄이 있으면, 뒤 동작에도 줄이 있어야 함.
⇒ 찾은 뒤 지킬 것 셋
- 물량을 다시 세지 말 것 — 뒤 동작의 밑수는 앞 동작의 물량 그대로임(표토 운반 = 표토 제거량). 다시 세면 이중계상.
- 앞이 안 서면 뒤도 안 섬 — 밑수가 그 줄이므로 함께 막히게 할 것.
- 법 문구를 사유에 실을 것 — 화면에서 왜 이 줄을 세는지가 보여야 함.
⚠ 품셈에 그 공종이 없을 수 있음(뿌리 운반이 그랬음 — 10장 어디에 붙는지 원문이 안 말함). 그때도 줄은 세우고 코드만 비울 것. 지어내지 말고 사유로. → 아래 ㉬.
㉬ ⚠ 「수량은 서는데 품셈에 공종이 없는 줄」은 한 물음임 — 모아서 한 번에 물을 것 (2026-09-09)
따로 만나면 매번 새 물음처럼 보이나 답은 하나임.
뿌리 운반 9-20 가. 가 과정으로 두었는데 붙을 공종이 10장에 없음
도수로·절토사면 배수로 「수로」 전수 검색에 셋뿐 — 그 셋에 없음
지장목제거 수량은 서는데 단가 공종이 없음
부대시설 넷 국가지점번호판·안내판·차단기·수방자재 — 개소를 넣어도 단가 없음
⇒ 선례가 답을 정해 둠 — 확정 8-4 「편책은 바자얽기(5-15)를 빌려 쓰지 않음. 일위대가를 따로 만들어 연결」. 즉 품셈에 없으면 우리가 만들어 잇는다가 사용자 방침임. ⚠ 빌려 쓸 후보가 있어도 답이 「만들라」일 수 있음 — 편책이 그랬음. 후보 유무로 미리 가르지 말 것.
⇒ 물을 때는 한 표로 — 공종명 | 수량은 서나 | 빌려 쓸 후보 | 없으면 새로 만들 성분.
넷을 따로 물으면 사용자가 네 번 답해야 하고, 그 사이 창마다 다르게 처리함.
㉭ ⚠⚠ 대조표를 인용하기 전에 「그것이 언제 것인지」부터 볼 것 (2026-09-09, 한 건이 세 번 뒤집힘)
오늘 가장 비싼 헛걸음임. 구조물 터파기 한 줄을 두고 조율 창·데스크탑 메인·랩탑 보조가 세 바퀴를 돌았고, 뿌리는 「오전에 뜬 대조표를 오후에 그대로 인용한 것」 하나였음.
대조표(오전) 「우리 2.30」 = 2.0 × (0.95 + 0.2) ← 옛 두께식 · 기초 몫 없던 때
그 사이 바뀐 것 확정 ② 두께 → 뒷길이 기반 (`8141eb34`)
확정 3차 → 기초유/기초버림 축, 기초 몫 0.45·0.07 이 붙음 (`b4ae32d1`·`759343e3`)
실제(오후) H=2.0 · 두께 0.83 · 기초유 → **2.510** = 실무 정본 2.51 과 자릿수까지 같음
⇒ 그 낡은 2.30 하나가 만든 잘못된 결론 셋
1. 「우리가 6.6배 과다 — 955만원을 줄일까요」 ← 사용자에게 갈 뻔한 틀린 물음
2. 「기초 몫 0.45 를 빠뜨렸다」 ← 이미 들어 있었음
3. 「화면 0.5 와 수량 H 가 다른 말을 한다」 ← 셋이 같은 말을 하고 있었음
⇒ 지킬 것
- 대조표·실측표를 인용할 때 날짜와 커밋을 함께 적을 것. 「오늘」은 날짜가 아님 — 하루에 두 번 바뀜.
- 금액이 걸린 인용은 그 자리에서 다시 재 볼 것. 재는 데 몇 분, 헛걸음은 세 창 몇 시간.
- 표를 만들 때 머리에 「잰 시각 + 그때 커밋」을 박아 둘 것. 표가 스스로 낡았다고 말하게.
- ⚠ 이 병은 「값이 틀린 것」이 아니라 「값이 옛것인 것」이라 어떤 검사에도 안 걸림. 시험도 통과하고 숫자도 맞음 — 그때는 맞았기 때문.
⇒ 곁들여 나온 것 — 그럴듯하게 맞아떨어지는 설명이 같은 건에서 두 번 틀렸음
(0.7 × 0.5 = 0.35 · 「H × 평균두께」 모양 일치). 딱 맞아떨어질수록 곱셈을 해 볼 것. → ㉧
⇒ 같은 집안 하나 더 — 「잘라서 인용한 자리」를 「없는 자리」로 읽지 말 것 (2026-09-09). 규준틀 사유를 44자로 잘라 보고하다 **「아무 표시가 없다」**로 냈음. 실제로는 그 뒤에 「재료량은 품셈 11-2 [주]④ 「설계수량에 따른다」라 미확보」가 적혀 있었음. ⇒ 길이를 줄여 인용할 때는 「…(잘림)」을 붙일 것. 안 붙이면 자기가 자른 자리를 사실로 읽음. ⇒ 그리고 「아무도 말 안 함」과 「이쪽만 말 안 함」은 다름 — 보내는 쪽이 이미 말하고 있을 수 있음.
㉮ ⚠⚠ 시험이 「지금 동작」을 베껴 적으면 버그를 잠근다 (2026-09-09, 실물 한 건)
제근 단가가 두 배로 서 있던 것을 시험이 「맞다」고 지키고 있었음.
있던 시험 「제근은 보통인부 줄이 **둘**이다」
실제 그 둘이 곧 이중계상 — 품셈은 「0.2㎥를 쓰면 이 값 **또는** 0.7㎥를 쓰면 저 값」
⇒ 시험이 버그를 계약으로 못 박아, 고치려 하면 **시험이 먼저 막아섬**
⇒ 어떻게 생기나 — 시험을 쓸 때 원문을 안 보고 지금 출력을 베껴 적으면 이렇게 됨. 「돌려 보니 둘이 나오네」 → 「둘이어야 한다」. 그 순간 틀린 값이 정본이 됨.
⇒ 지킬 것
- 시험의 기대값은 「돌려 본 결과」가 아니라 「원문」에서 올 것. 기대값 옆에 근거를 한 줄 적을 것 (품셈 절 번호·실무 시트 셀 좌표). 근거를 못 적겠으면 그 시험은 아직 쓰면 안 되는 것임.
- 개수를 세는 시험(「줄이 둘이다」·「성분이 N개다」)이 가장 위험함 — 값이 아니라 모양을 잠그는데 모양이 틀렸을 때 그것을 알려 줄 것이 없음.
- 뒤집을 때는 「왜 뒤집혔는지」를 그 시험 설명에 남길 것. 안 남기면 다음 사람이 되돌림.
⚠ ㉪(계약이 바뀌면 시험부터 의심할 것)과 다른 병임. ㉪는 시험이 낡은 것이고, 이것은 시험이 처음부터 틀린 것임. 낡은 시험은 계약이 바뀔 때 깨져서 드러나는데, 처음부터 틀린 시험은 영영 안 깨짐 — 지키는 대상이 실제로 그렇게 돌고 있으므로.
㉯ ⚠ 검산은 「어디까지 쟀는지」를 함께 적을 것 (2026-09-09)
뒤채움 두께가 품셈 범위 안에 드는지 재면서 **H 4.0m 까지만 재고 「세 자리 다 범위 안」**으로 냈음. 그물을 시험으로 옮겨 H 6.0 까지 늘리자 4.0~4.5 사이에서 범위 밖으로 나감이 바로 걸렸음.
우리 두께 직고에 0.30/m 로 **계속** 붙음 (확정 ② 실무 정본 식)
품셈 표 하부 두께가 **1.40m 에서 멈춤** ([주]⑨ 직고 7m 칸 상한)
⇒ 높이 축의 기울기가 다름. 어느 쪽도 상대를 틀렸다고 못 함 — **갈리는 자리를 값으로 남길 것**
⇒ 「범위 안이다」는 잰 범위 안에서만 참임. 시험 이름·주석에 잰 구간을 박을 것. ⇒ 그리고 범위 검산은 등호로 바꾸지 말 것 — 밖으로 나가면 「틀림」이 아니라 **「봐야 함」**임. 우리 식이 맞을 수도 있음.
㉰ ⚠⚠ 표를 읽을 때 칸을 이어 붙이면 「원문에 없는 값」이 만들어진다 (2026-09-09)
앞 칸의 숫자 + 뒤 칸의 단위가 붙어, 원문 어디에도 없는 밑수가 섰음.
품셈 13-2-4 … 0.28 | **0.36** / **㎥당** | 0.60 … ⇒ 「0.36㎥당」 (0.36 은 뒷길이 60 의 ㎡당 값)
품셈 5-19-2 15 | **30**(표토두께 ㎝) / **㎥ 당** | … ⇒ 「30㎥당」 (30 은 두께)
⚠ 잘못된 값이 아니라 「없는 값」임. 그리고 두 숫자 다 그 표 안에 실재해서 그럴듯함 — 어떤 검사에도 안 걸림.
⇒ 지킬 것
- 표를 훑을 때 「칸 하나 안에서만」 볼 것. 셀을 죽 이어 붙여 정규식을 걸면 이 병이 남. 「100㎥당」처럼 한 칸에 다 든 것만 인정.
- 밑수가 늘어난 것은 좋아진 신호가 아님 — 이 건에서 밑수 확보가 182 → 180 으로 줄어든 것이 개선이었음(없는 값 둘이 빠지고 넷이 「미확보」로 정직해짐). → ㉠
- 잡은 실례를 그대로 재는 시험을 남길 것. 그래야 다음에 정규식을 넓힐 때 걸림.
⚠ 같은 날 잡은 「인」 오독과 다른 병임 — 「인」은 잘못된 단위(원문에 있는 글자를 잘못 읽음), 이것은 없는 숫자(원문에 없는 조합을 만들어 냄). 고치는 자리도 다름.
㉱ ⚠⚠ 코드 추적으로만 낸 「원인」은 자료를 재 보기 전까지 가설임 (2026-09-09, 하루를 돌아감)
계획서 3-14 에 **「원인 찾음(코드 추적)」**이라 적어 두었는데 자료를 안 재 봤고, 재 보니 틀렸음.
적어 둔 원인 「관을 나중에 놓으면 그 측점이 안 생긴다」 — 측점 생성 호출부를 따라가 낸 결론
실제 측점 440.0 · 620.0 · 720.0 · 900.0 이 **이미 있었고 구조물 이름표까지 달고 있었음**
진짜 원인 관 자리와 측점 자리가 **최대 0.5m 어긋나는 것이 설계**(정수 미터 격자로 스냅)인데
**붙이는 쪽이 0.02m 로만 봐서** 안 붙었음
⇒ 그 틀린 원인이 하루 동안 판단 셋을 끌고 다녔음
1. 「B06 자리」로 넘겨 B08·B09 가 손을 못 댐
2. 조율 창이 **「0.05 와 0.5 를 맞추지 말라」**고 지시 — **좁은 쪽이 스냅을 모르는 것**이 진짜 문제였음
3. [측점 만들기] 단추를 **주 해법**으로 잡음 (실제로는 0개짜리 예외 처리였음)
⇒ 지킬 것
- 「원인」이라 적을 때 어떻게 알았는지를 함께 적을 것 —
코드 추적/실측/원문. 추적만으로 낸 것은 「가설」이라 쓸 것. - 가설을 남에게 넘기기 전에 한 번 잴 것. 이 건은 「그 측점이 정말 없는가」를 한 번 조회하면 끝날 일이었음.
- 남이 넘겨준 진단을 그대로 이어받아 지시하지 말 것 — 조율 창이 그 위에 지시 둘을 얹었고 둘 다 틀렸음.
⚠ ㉭(대조표가 낡음)과 다른 병임. 그건 한때 맞았던 값이 낡은 것이고, 이것은 처음부터 안 재 본 것임. 낡은 값은 날짜로 걸러지지만 안 잰 것은 걸러지지 않음.
㉲ ⚠⚠ 「막혔다」고 말하기 전에 차단 표시를 볼 것 — 화면 문구는 근거가 아님 (2026-09-09, 하루에 두 번)
주의 문구를 차단으로 읽어 두 번 헛돌았음.
아침 겹침 설명을 `blocked_reason` 에 넣었더니 **B09 가 「막힌 줄」로 읽어 금액을 안 붙였음**
⇒ 비고 칸으로 옮기고 막힘은 **진짜 막힐 때만** 넣게 고침
밤 「관종을 안 정해 기본값(파형강관)으로 섰습니다」를 **조율 창과 B09 창이 「막는 사유」로 읽음**
실제 `blocked_kind` 는 **공종코드를 못 찾을 때만** 섬(`if code is None`).
기본값 파형강관은 코드가 있어 **줄도 서고 금액도 섬** — 그것은 `kind_note`(주의)였음
⇒ 「칸을 만들라」는 지시가 두 창에 나갔고 **칸은 이미 있었음**
⇒ 지킬 것
- 차단 여부의 근거는
blocked_kind하나임. 사유 글자·주의 문구·「미정」이라는 말은 근거가 아님. - 막힘을 보고할 때
blocked_kind값을 함께 적을 것. 「막혔음」만 적으면 받는 쪽이 문구를 읽음. - 화면에서도 「주의」와 「차단」을 갈라 보일 것 — 같은 자리에 뜨면 사람도 코드도 헷갈림.
- ⚠ 남이 옮겨 준 사유 문구를 그대로 판단 근거로 쓰지 말 것. 두 번 다 문구를 옮긴 창과 받은 창이 함께 틀렸음. → ㉱
⚠ ㉨(「사유」 칸에는 왜 막혔나만)의 반대쪽 얼굴임. 그건 쓰는 쪽 규칙이고 이것은 읽는 쪽 규칙임. 사유 칸에 설명을 섞으면 읽는 쪽이 막힘으로 읽고, 읽는 쪽이 표시를 안 보면 안 막힌 것을 막혔다고 함.
㉳ ⭐⭐ 예외는 「git 밖 시험 목록」이 아니라 「정본 스키마」에 적을 것 (2026-09-09)
칸은 건너가는데 까닭은 안 건너감 — 그래서 같은 판인데 창마다 시험 결과가 다름.
정본 등록부 B05_Profile_Structure_Types.json git **안** ⇒ 다른 창에 감
정책 시험 tmp/tests/…_registry_policy.py git **밖**(CLAUDE.md 4장) ⇒ **안 감**
⇒ 칸을 열고 시험의 예외 목록에 까닭을 적으면 **칸만 건너가고 까닭은 안 건너감**
⇒ 연 창은 통과, 받은 창은 실패. **둘 다 맞는 상태인데 서로 틀렸다고 함**
⇒ 고침 — 「예외」를 목록에서 스키마로 옮길 것. 실제로 세운 두 갈래:
empty_means 「비워 두는 것이 뜻인 칸」 — 비면 계산 쪽이 기준값으로 돌고 그 사실이 화면에 뜸.
값을 넣으면 그 값이 이김. **까닭 한 줄을 값 옆에** 적음
default_basis 기본값이 **도메인 확정값이 아닐 때** 그 뜻(「다단 없음」·「안 더함」).
법정·확정 수치면 **비워 둠** — 비어 있는 것이 「확정값」이라는 뜻
⇒ 시험은 목록을 읽지 않고 그 칸을 읽음. 까닭이 한 낱말이면 잡는 시험도 함께 둘 것 (빈 문구로 통과하는 것을 막음).
⇒ 규칙 한 줄 — 등록부에 칸을 열 때 예외 목록을 고치지 말고 까닭을 값 옆에 적을 것.
⚠ 다만 구조를 고쳐도 「옮기는 일」은 남음 (2026-09-09 그날 저녁 실측).
스키마를 고치면 그 스키마를 읽는 시험 파일도 바뀌는데, 그 파일이 tmp/tests(git 밖)라
여전히 안 건너감. 실제로 한 창이 스키마를 고친 뒤 다른 창이 옛 시험으로 2건 실패했음.
⇒ 스키마를 고쳤으면 **그 시험 파일 내용을 메시지로 보내** 각 창이 자기 폴더에 놓을 것
⚠ 남의 폴더에 직접 쓰지 말 것 — 보내고, 받는 쪽이 놓음
⇒ 「내 창은 통과인데 저쪽은 실패」가 보이면 먼저 **시험 파일 판을 맞출 것**
흙깎기 장비 이름이 표에 없고 [주]① 이 지정 기초잡석 운반 표에 「덤프트럭(15ton)」 줄만 있고 시간이 빔 — 10-12 가 거리로 냄(같은 15ton) 커플링밴드 표 「EA | (빈칸) | 필요시적용」 — [주]① 「1EA/6m 이며 필요시 별도 산정」
**⇒ 빈 칸을 만나면 그 표의 [주]·비고·앞뒤 절 참조를 먼저 훑을 것.** 셋 다 **표만 보면 「없음」**이었고
**[주]를 보면 있었음.**
**⇒ 사유 문구를 갈라 쓸 것 — 다음 사람이 볼 때 뜻이 아주 다름**
「원문에 값이 없음」 ⇒ 영영 막힌 것으로 읽힘. 지어내지 말라는 뜻 「[주]에 있음 — 조건이 붙음」 ⇒ 조건만 정하면 서는 것 「다른 절이 냄 — 거리/규격 필요」 ⇒ 그 값이 오면 저절로 섬
⚠ 셋을 뭉쳐 「값 없음」으로 적으면 **사용자가 없는 것을 정하러 감.** → ㉲
⚠ **㉢(밑수 단위가 표 밖)과 같은 집안이나 다른 것임** — 그건 **단위**가 표 밖에 있는 것이고
이것은 **값 자체**가 표 밖에 있는 것임. 둘 다 「표만 읽는 코드」가 못 잡음.
#### ㉵ ⚠⚠ **`0` 과 「없음」을 같은 것으로 두지 말 것** (2026-09-09, 하루에 **세 번**)
표토 대상 면적이 0 ㎡ 인데 0 ㎥ 를 「값 있음」으로 냄 ⇒ 받는 쪽이 「표토가 없는 노선」으로 읽음. 두께 미입력은 막고 있었는데 면적 0 만 통과 사토장 구조물을 지웠는데 설계 결과가 0.0 을 늘 실어 횡단도·면적표에 계속 남아 있었음 ⇒ 「칸이 있는 것」과 「값이 있는 것」이 달랐음 말풍선 폭을 이분법으로 찾아 남은 0.0063㎥ 에 「⚠ 못 담음」 경고가 늘 떴음 ⇒ 표시 자릿수에서 안 보이는 몫을 「남았다」고 말했음
**⇒ 세 가지 다 「0 이라는 값」이 거짓말을 한 것임.** 값이 없어서가 아니라 **있어서** 안 걸림.
**⇒ 지킬 것**
- **「없음」은 `None`(빈 값)으로 낼 것.** `0` 은 **「재 보니 0 이었다」**는 뜻으로만 쓸 것.
- **얹는 코드를 쓰면 지우는 길도 함께 쓸 것.** 사토장이 그 자리였음 — 얹기만 하고 안 지워
**구조물을 없앤 뒤에도 값이 남았음.** 시험은 「놓았을 때」만 보고 「지웠을 때」를 안 봤음.
- **경고는 사람이 보는 자릿수로 판정할 것.** 0.0063 처럼 화면에 안 보이는 몫을 경고하면
**경고 전체가 믿을 것이 못 됨.**
⚠ **셋 다 시험은 통과했고 화면에서 잡혔음.** 「있다」와 「돈다」의 그 자리임 — **지우는 길·빈 자료·
표시 자릿수는 시험이 잘 안 훑는 세 곳**임.
### ⚠ 좁은 폭에서 화면이 깨지면 볼 자리 셋 (2026-09-09 B03 업로드 현황에서 셋이 한꺼번에)
셋 다 **넓은 화면에서는 안 보이다가 창을 줄이면 터짐.** 다른 페이지도 같은 짜임이면 같이 깨짐.
- **`minmax(260px, 1fr)` 는 「260보다 좁아질 수 없다」는 뜻** — 컨테이너가 그보다 좁아지면
**격자가 컨테이너를 뚫음.** ⇒ `minmax(min(260px, 100%), 1fr)` 로 적을 것.
- **접는 분기가 아예 없는 2열** — `repeat(2, minmax(0,1fr))` 는 좁아져도 2열을 고집해
열마다 카드 하나도 못 담음. ⇒ `repeat(auto-fit, minmax(min(360px,100%), 1fr))`.
- **flex 자식의 `min-width: 0` 누락** — 기본값이 `auto` 라 **내용보다 안 줄어듦.**
안쪽 격자가 넘치면 **페이지 몸통이 통째로 가로로 밀림.**
**판정은 눈이 아니라 숫자로** — 폭을 여러 개(1400·1000·760·620·480) 돌며
`scrollWidth − clientWidth` 가 0 인지 볼 것. 창이 눈에 안 따라와도 **뷰포트 폭만 바꾸면
레이아웃은 다시 계산되므로 측정은 됨.**
**⚠ 같은 짜임이 다른 화면에도 있음 — 훑은 목록** (2026-09-09, 아직 안 고침)
㉡ 접는 분기 없는 고정 2열 — 아홉 곳 (B03 에서 깨진 것과 같은 짜임) B01_Dashboard_UI_Style.css:22 · :134 · :166 B02_ProjRegister_UI_Style.css:18 ← 등록 폼, 사용자가 자주 봄 B05_Profile_UI_Style.css:303 · :338 · :436 B05_Profile_UI_Style_Structures.css:157 B06_Section_UI_Style.css:286 B06_Section_UI_Style_Cross_Controls.css:314 B07_DesignDetail_UI_Style.css:55 (1fr 1fr) ⚠ B05·B06 은 좌측 패널 안이라 폭이 원래 좁음 — B03 보다 먼저 깨질 수 있음 ㉢ min-width:0 누락 — 62 곳. 전부가 문제는 아니고 ㉡ 와 겹치는 자리부터 볼 것 ㉠ minmax(고정px) — B01_Dashboard_UI_Style.css:231 한 곳뿐(150px 라 위험 낮음) ㉣ @media 가 아예 없는 화면 — B05_* · B06_* · B08_* · B09_* ⇒ 좁은 폭 대응을 안 한 화면이 넷임
**고칠 순서 제안** — ① B02 등록 폼 ② B05·B06 좌측 패널 2열 ③ 나머지.
### ⚠ **`reload()` 만으로는 vite 가 옛 모듈을 물고 있을 수 있음 — 캐시부터 비울 것** (2026-09-09)
지침이 「페이지·공용 코드는 `page.reload()` 한 번(vite dev)」이라 적고 있으나 **그것으로 안 걷힌 자리**가 나왔음. **한 증상을 두고 세 창이 차례로 헛짚었음.**
증상 벽 터파기가 화면에 0건 (관 터파기는 뜸) 헛짚음 ① 「그리기 가드가 먹는다」 ② 「초안 경로에서만 그려진다」 ③ 「백엔드 재시작을 안 했다」 실측 백엔드 stale:false · API 상세에 revetment.foundation="기초유" 이미 옴 · 화면만 옛것 답 CDP Network.clearBrowserCache + sessionStorage.clear + reload → 바로 뜸
⇒ **TS 를 고쳤는데 화면이 옛것 같으면 「캐시부터」.** `page.goto`·`reload` 만으로는 부족할 수 있음.
⚠ **브라우저 창은 재시작하지 말 것** — 캐시 비우기로 끝남(지침 4장 그대로).
### ⚠ 공용 이름을 **갈거나 지울 때는 창들에 먼저 알릴 것** (2026-09-09, 하루에 세 번)
**값을 한 벌로 두어도 이름이 바뀌면 깨진다.** 「공용 상수를 직접 읽으니 저절로 따라온다」가
**반만 맞는 말**임 — 값은 따라오고 **이름은 안 따라옴.**
① BLANK_DRAWINGS·BLANK_LABELS 를 걷어냄 → 남의 tmp/tests 가 수집 단계에서 터져 267건이 통째로 멈춤 ② tmp/tests 는 git 밖 → 병합에 안 실림. 지운 쪽이 알리는 것 말고 길이 없음 ③ 두께 상수 이름 셋을 갈이 → 남의 표준도 그림이 KeyError 로 죽음 thickness_base_m·_top_coeff·_bottom_coeff → _top_add_m·_slope_per_m·_height_base_m
⇒ **새로 넣는 것은 안전함. 갈거나 지우는 것만 알리면 됨.**
⇒ 셋 다 **실화면·실행에서만** 드러났음 — 코드만 봐서는 안 잡힘.
### ⚠ **[저장]은 횡단 설계를 다시 계산하지 않음 — 새 키를 넣었으면 「재생성」을 돌릴 것** (2026-09-09)
**설계 엔진에 키를 새로 넣었는데 저장분에 안 들어오는 자리.** 하루를 「값이 0 이다」로 보냄.
[저장] 편집을 적용하고 Node 로 구조물 면적·유토곡선만 다시 냄(_recompute_stored_designs) ⇒ 저장분이 옛 34키 그대로 — 새 키(bench_cut_length_m 등)가 안 들어감 재생성 파이썬 설계 엔진이 전 측점을 새로 냄 ⇒ design 키가 38개로 늘어남
**세 창에 돌린 절차 (순서를 지킬 것)**
① git sync ② npm run build:server-calc ⚠ 번들은 git 밖 — 창마다 각자 해야 함 ③ 백엔드 재시작 ⚠ @lru_cache 가 옛 등록부·config 를 물고 있음 ④ B06 열고 카드가 다 뜰 때까지 기다림 ⑤ POST /api/projects/{pid}/sections/{routeId}/regenerate body {"cross_half_width_m": <지금 쓰는 반폭>} (routeId·반폭은 GET /api/projects/{pid}/sections/context 의 route_id·defaults) ⑥ 확인: GET …/sections/{routeId}/detail → design 키 38개
⚠ **[확정]은 필요 없음** — 저장·재생성만으로 정본이 섬.
⚠ **추정치를 그대로 쓰지 말 것** — 같은 노선에서 추정 12,931㎡ → 실측 **13,699.7㎡ (+6%)** 로 갈렸음.
### ⚠ 창 크기를 바꿀 때 `page.set_viewport_size` 를 부르지 말 것 — `resize(w, h)` (2026-09-09)
**그 한 줄이 화면을 그 크기에 박아** 사용자가 창을 끌어도 안 따라옴. `Emulation.
clearDeviceMetricsOverride` 로도 안 풀림(Playwright 가 다시 걺) — **드라이버 재시작 말고는
푸는 길이 없음.** 데스크탑이 그렇게 하루를 그 상태로 보냈고, **랩탑이 멀쩡했던 것은
그 호출을 안 썼기 때문**이지 배율·인자 차이가 아니었음.
- 드라이버에 **`resize(w, h)`** 를 넣었음 — CDP `Browser.setWindowBounds` 로 **창 자체**를 바꿔
화면이 따라옴. `page.set_viewport_size` 는 이제 **막힘 문구와 함께 거부**됨.
- ⚠ **`.claude/` 는 git 밖이라 커밋으로 안 건너감** — 시놀로지 동기화에 기대거나 창마다 붙여야 함.
붙었는지는 `grep -n "def resize" .claude/browser_driver.py` 로 확인.
- **화면이 안 따라와도 폭 측정은 됨** — 뷰포트 폭만 바꾸면 레이아웃은 다시 계산되므로
`scrollWidth − clientWidth` 로 재는 검증은 그대로 유효함. 눈으로 보는 확인만 뒤로 미룰 것.
### ⚠ 브라우저 명령 파일은 **다른 이름으로 쓴 뒤 `mv` 로 넣을 것** (2026-09-09, 하루에 두 번)
`tmp/browser/cmd/` 에 파일을 **직접 쓰면 드라이버(1초 폴링)가 쓰는 도중에 집어감.**
**실행은 되고 `OK` 도 뜨는데 내용이 비어 아무 일도 안 일어남** — driver.log 에도 안 남음.
⇒ **딴 이름으로 다 쓴 다음 `mv` 로 옮길 것.** 「도는 척만 하는 검사」와 같은 계열이라 특히 나쁨(㉢).
### 공용 브라우저가 로그인 화면에서 멈췄을 때 (2026-09-08 — 두 창이 같은 자리에서 막힘)
**튕기면 서버가 아니라 쿠키를 의심할 것.** 세션은 DB 표(`sessions`)라 **서버 재시작으로 안 지워진다.**
날아가는 것은 브라우저 쿠키 쪽이다(새 프로필·만료·캐시 비우기에 함께).
쿠키는 포트를 안 가려 **8000·5173 중 한 번만 로그인하면 둘 다 붙는다.**
**되살리는 법** — 자격증명은 `tmp/aislo_cred.json`(git 밖, 사용자가 유지 — **지우지 말 것**).
없으면 **짐작하지 말고 사용자에게 요청**할 것. 명령 파일에서:
```python
import json
cred = json.load(open("tmp/aislo_cred.json", encoding="utf-8"))
api = page.context.request # ⚠ 브라우저 컨텍스트의 요청 — 쿠키를 공유한다
if api.get("http://localhost:8000/api/auth/session").status != 200:
api.post("http://localhost:8000/api/auth/login/request", data=cred)
log(api.get("http://localhost:8000/api/auth/session").status) # 200 이어야 함
⚠ page.evaluate 안에서 fetch 로 하지 말 것 — 로그인 화면이 그 사이 이동해
Execution context was destroyed 로 죽는다(2026-09-08 두 번 겪음). page.context.request 는
페이지 이동과 무관하다.
⚠ dev_up.py·browser_driver.py 에 로그인 처리가 없는 것이 맞다 — 드라이버는 창만 띄우고
로그인은 명령 파일 몫이다. grep 해도 안 나온다.
⚠ shot() 은 확장자를 붙일 것 — shot("이름") 은 unsupported mime type "" 로 죽는다.
page.screenshot(path="tmp/browser/shots/이름.png") 로 쓰는 편이 안전하다.
⚠ 값을 만지기 전에 「어느 프로젝트가 열려 있나」부터 볼 것 —
localStorage['frd_current_project_id']. 사용자 프로젝트(5cff3920)면 읽기만 한다.
검증 함정 모음 — 재기 전에 볼 것 (2026-09-07 정리)
끝난 절을 plans/ 로 옮기며, 다시 걸리면 또 오진할 것들만 여기로 건져 왔음.
괄호는 원래 절 번호(docs/raw/plans/2026-09-07_plan_completed_items.md 에 원문 있음).
-
⚠ 시험을 저장소 실물에 매지 말 것 — 만든 창에서만 통과함 (2026-09-09).
test_prj_identify.py::test_compound_vertical_prj가 특정 프로젝트의…/input/prj/result.prj를 실경로로 열어 epsg 를 확인하는데, 그 프로젝트가 지워지자 두 PC 에서FileNotFoundError로 깨졌음.tmp/tests는 git 밖이지만 시놀로지로 파일은 건너오고 저장소 자료는 창마다 다름 — 그래서 남의 PC 에서만 깨지는 시험이 됨. ⇒ 실물 파일이 필요하면 없을 때skip하게 가드를 붙일 것. 같은 파일의 다른 넷은 이미 그렇게 돼 있었고 하나만 빠져 있었음. 깨진 것을 「병합이 망가뜨렸다」로 오진하기 쉬운 자리임. -
옛 코드로 도는 서버에 속지 말 것 — 속도·화면을 재기 전에 ① 백엔드를 확실히 재시작하고 ② 그 수정의 로그나 새 응답 항목이 실제로 있는지 먼저 볼 것. 하루에 두 번 속았고, 한 번은 응답에 새 항목이 아예 없는데 화면은 정상처럼 보였음(다른 값으로 세는 폴백). (0-12)
-
캐드(B07) 화면은
npm run build+ 캐시 비우기 를 해야 바뀜 — 안 하면 옛 화면을 봄. (4-4) -
화면이 백지가 되면 옛 vite 프로세스를 먼저 볼 것 (2026-09-07 보조 창, 하루 세 번 겪음) — 증상: 해시 이동은 되는데
document.body가 빈 문자열, 콘솔에ERR_CONNECTION_RESET. 원인: 백엔드를 다시 띄우면main.py가 vite 를 새로 띄우는데 옛 vite 가 남아 탭이 죽은 소켓을 물고 있음(실측: 5174 를 쥔 node 하나 + 유령 둘). 캐시만 비워서는 안 살아남. 되살리는 순서 — ①Get-NetTCPConnection -LocalPort <포트>로 주인 확인, 유령 node 정리 ② 백엔드 재시작 ③about:blank→http://localhost:<포트>/(wait "load") → 그다음 해시. 해시로 곧장 가면 계속 백지였고, 루트를 먼저 거치면 살아남. -
조정창은 두 벌이고 조작이 갈려 있음 (2026-09-07 두 창이 각각 헛짚음) — 좌측 [횡단 조정] dock 에는 이동 십자(▲▼◀▶)·집수정 9키가 CSS 로 숨겨져 있고(
_Style_Cross_Controls.css:244~), 그 십자는 도면 위에 뜨는 오버레이 창에만 있음. 반대로 오버레이에는 값·형식 행이 숨겨져 있음(2026-08-29 「값은 좌측, 위치제어는 도면 위」). dock 에서 ◀ 를 찾으면 DOM 에는 있는데vis:false인 것이 정상임 — 결함으로 오해하지 말 것. -
요소가 보이는지는
offsetParent로 재지 말 것 (2026-09-07, 두 창이 같이 걸림) — 고정 위치(position: fixed) 요소는 보이든 안 보이든offsetParent가 늘null이라 「안 보인다」로 오판함. 크기로 잴 것 —getBoundingClientRect()의 width/height, 또는offsetWidth || offsetHeight. 둘 다 0 이면 실제로 안 그려진 것임. -
UI 를 붙였으면 크기도 같이 잴 것 (2026-09-07) — 알약 레인을 종단 패널에 넣고 「알약이 뜬다」만 보고 넘겼다가, 잰 높이에서 레인 몫을 안 빼 되먹임이 생겨 패널이 16,664px 로 부풀었음. 그 상태에서는 카드·알약을 아예 못 눌러 다음 검증이 통째로 막혔음.
-
3D 클릭을 잴 때 —
__corridorScene.project()좌표는 DOM 이 덮고 있는지를 안 봄. 클릭 직전에document.elementFromPoint(x, y) === document.querySelector('canvas')를 확인하거나 종단 오버레이 핸들(.ui-workflow-overlay__handle)을 먼저 접을 것. 이걸 몰라 두 번 오진. (2-2) -
조정창은 셋으로 쪼개져 있음 — 「단 수」는 어느 조정창에도 없음 (2026-09-07, 3-7 에서 한참 헤맴). ① 카드 위 조정창 = 이동 십자·집수정 9키 전용 ② 좌측 [횡단 조정] dock = 높이·길이·기준측점 전/후 ③ 단 수(추가 기슭막이)와 옵션(연동·경사) 은 둘 다 아니고 좌측 구조물 폼의 유입구/유출구 칸(
.b05-structure__adjust-slot)으로 옮겨 붙음. 카드 조정창 안에도 그 행의 DOM 은 있지만 CSS 로display:none이라 눌리지 않음 —innerText로만 보면 「있는데 왜 안 눌리지」로 헤매게 됨. 크기(rect)로 볼 것. -
B06 조정창을 볼 때 — 두 번 걸린 함정임(3-4 · 3-7).
.b06-structure-panel은 카드마다 하나씩 있음(66~67개). 목록에서find로 아무거나 집으면 다른 카드의 빈 패널이 먼저 잡혀 크기 0 ·is-hidden으로 나옴. 2026-09-07 에는 이것 때문에 두 창이 「십자 단추가 안 그려진다 = 사용자도 벽을 못 옮긴다」로 잘못 결론냈다가 되물렀음(고른 벽의 카드에서 재니 조정창 124×185, 이동 행 107×86 으로 멀쩡했음). 반드시 그 카드 안의 것(card.querySelector)을 볼 것. 또 벽을 안 그리는 카드를 고르면 굳히기 루프가 0회 도니card.querySelector('.b06-chart__culvert-revet-hit')로 먼저 거를 것. -
화면 서버(vite)는 백엔드(
main.py)의 자식임 (main.py → npm → vite,.claude/dev_up.py:40). 백엔드를 트리째 끄면 화면 서버도 같이 죽고 열려 있던 탭이 옛 모듈을 붙들어 백지가 됨. 재시작이 비싼 진짜 까닭은 서버가 아니라 이쪽임. 조작 전에 8000·5173(또는 8001·5174) 둘 다 200 인지 볼 것. (옛 「7. 개발 환경」에서 건져 온 것) -
로그인 세션은 DB 표(
sessions,common_util/common_util_auth.py:115)라 재시작으로 안 지워짐. ⚠ 그래도 브라우저 쪽 세션은 끊김 — 2026-09-08 데스크탑 두 창이 같은 자리에서 막혔음. 화면 검증 전에#/a06-login으로 튀는지 먼저 볼 것. (로그인하는 절차는 랩탑 창 확인 중) -
⚠ 화면이 막혀도 엔진은 파이썬에서 직접 부를 수 있음 — 라우터가 인계를 함수로 부르므로(
from B08_Quantity… import get_handoff) HTTP·로그인을 안 탐. ⚠ 다만await init_db_pool()을 먼저 부를 것 — 안 부르면 예외가 응답 본문으로 나가 빈 응답처럼 보이고 「자료가 없다」로 잘못 읽힘(2026-09-08 실측). 그리고 한 이벤트 루프 안에서 다 끝낼 것(따로 돌리면Event loop is closed가 쏟아짐). -
⚠ 되받기 전후로 인계 응답을 파일로 떠 둘 것 — 「합계가 221원 줄었다」를 짚을 때 어느 줄이 얼마나 바뀌었는지를 대조할 자료가 없으면 짐작이 됨(2026-09-08). 마침 화면 로그에 옛 수량이 남아 있어 짚었으나 그건 운이었음. ⚠ 다만 「재시작하면 다시 로그인해야 했다」는 기록이 있으므로 다른 까닭이 있을 수 있음 — 실측은 안 해 봤음.
-
🔴 횡단 카드를 확대·이동하면 그 측점의 면적이 달라질 수 있음 (2026-09-07 3-9 뒷정리에서 발견). 확대·이동은 그 측점의 「표시 반폭」(
display_half_width_m)을 바꾸고(실측 12 → 27m), 사면이 반폭 안에서 지반을 못 만나는 측점은 잘린 만큼 면적이 달라짐(성토 57.45 → 62.79㎡). 세션crossw에 남으므로 검증하러 확대하는 것만으로 수치가 흔들림. · 설계상 그런 자리는slope_unclosed경고가 이미 뜨므로 결함이라기보다 「반폭이 좁으면 면적이 잘린다」는 성질임. 다만 검증할 때는 확대 전 반폭을 적어 두고 끝나면 되돌릴 것. -
화면 요소가 보이는지
offsetParent로 재지 말 것 — 고정 위치 요소는 늘null이라 늘 안 보이는 것으로 나옴.getBoundingClientRect()크기로 잴 것. (3-7) -
단계바
.ui-workflow-layout__step은 0번이 대시보드 — 종단설계는 3번. (2-7) -
살아 있는 프로젝트에 검증용
solve_route를 돌리지 말 것 —route_main.geojson은 프로젝트당 한 벌이라 노선 행이 늘어도 파일은 덮임(실제로 덮였고 되돌렸음). (0-10) -
이미 만든 프로젝트는 그대로임 — 노선이 폴리라인 기준이 되려면 새로 업로드해야 함. (0-10)
-
곡선 생략(내각 155°) 규칙을 쓰지 않기로 해 곡선 개수가 늘었음(용화 13 → 26곳) — 평면 R 을 읽는 자리(3-1 확폭 · 2-6 구조물)는 그것을 감안할 것. (0-12)
-
3-5 물량 파급을 되돌릴 자리 —
Cross_Culvert_Geom.ts의extendTrimSlope위 주석. 사용자가 「그대로 둠」으로 확정했으므로 근거로만 남긴 것. (3-5) -
확폭이 수량에 실리는 것은 B08 재작업 때 —
carriageway_width_m(= 3.0 + 확폭)을 쓰면 됨. (3-1)