BimRevisionService::run | error: "BimRevisionService::runBimCompare | end - validation failed (error
RCA: BimRevisionService runBimCompare validation failed (errorCode: REV141)
Overview#
What Happened#
2026-06-24 23:07 KST에 cupixworks-any-bimrevision-agent (us-west-2) 가 bimRevisionId: 24612 (BIM 19655, facility drdm2z, V1 → V2) 의 BIM 리비전 비교를 실행하던 중 runBimCompare 단계에서 REV141 (BimRevisionExcessiveRemoval) 검증 실패로 종료되었다. Forge 비교 결과 제거 비율이 26.0% 로 facility 에 설정된 임계값 15% 를 초과하여 안전 장치가 발동했고, 해당 리비전 1건의 비교가 Error 상태로 마감되었다.
Quick Facts#
| Field | Value |
|---|---|
| exception.class | Error (generic, thrown in runBimCompare) |
| exception.message | BimRevisionService::runBimCompare | end - validation failed (errorCode: REV141) |
| top_frame | packages/cupix-tesla-bim-revision-agent/src/bim-revision-service.ts:690 |
| error_code | REV141 (BimRevisionExcessiveRemoval, AGT* family) |
| agent_version | 10.98.0 |
| env | production, region us-west-2 |
Affected Teams#
| Team / Domain | Error Count | Impact |
|---|---|---|
exyte (BIM revision pipeline, facility drdm2z) |
1 | BIM 리비전 비교가 실패하여 bim_comparison_state 가 Error 로 기록됨. 24시간 창에서는 동일 클러스터 1건이지만, 14일 창에서 동일 메시지(REV141) 가 6건 발생하여 BIM 별 반복 사례가 존재. |
Timeline#
- 2026-06-24 23:06:45 KST —
BaseService::runByMessage | id: 24612— SQS 메시지 수신, 리비전 처리 시작 - 2026-06-24 23:06:45 KST —
BimRevisionService::loadAllElements | begin - bimId: 19655, facilityKey: drdm2z— 기존 element 로드 시작 - 2026-06-24 23:06:47 KST —
BimRevisionService::REVISE-BEGIN—cp_elements_count: 77, cp_elements_created_count: 77, cp_elements_deleted_count: 0,V1(prev) →V2(src) - 2026-06-24 23:07:04 KST —
CPBimRevision::validateBimComparerResult | excessive removal detected - bimRevisionId: 24612, bimId: 19655, trigger: ratio 26.0% >= 15% - 2026-06-24 23:07:04 KST —
BimRevisionService::run | error: "BimRevisionService::runBimCompare | end - validation failed (errorCode: REV141)"(cluster representative log) - 2026-06-24 23:07:04 KST —
BimRevisionService::REVISE-END—elapsed_ms: 19388, status: "error", 모든 counts 0
Error Log#
BimRevisionService::run | error: "BimRevisionService::runBimCompare | end - validation failed (errorCode: REV141)"
Impact#
- Service:
cupixworks-any-bimrevision-agent - Team: exyte
- 발생 횟수: 1 (cluster 단위)
- 최초 발생: 2026-06-24 23:07 KST
- 최근 발생: 2026-06-24 23:07 KST
- 누적 (14일): 동일
REV141메시지가 6건 더 관측됨 (bim_id: 174462건,bim_id: 27603건,bim_id: 196551건). 즉 단발이 아니라 facility 별로 반복 발생하는 패턴.
Root Cause Summary#
BimRevisionService.runBimCompare 가 forge-agents 자식 프로세스의 비교 결과를 CPBimRevision.validateBimComparerResult 에 넘겼고, 그 안의 hasExcessiveRemoval 가드가 “이번 리비전에서 제거된 element 비율이 facility 임계값을 넘었다”고 판단해 의도적으로 false 를 반환했다. 이번 케이스는 facility drdm2z 의 bim_revision_removed_ratio_threshold 가 15(%) 로 설정되어 있고, Forge 비교가 26.0% 의 제거를 보고하여 가드가 발동한 것이다. bypassThreshold 가 false 였기 때문에 _validationErrorCode = REV141 이 세팅된 채 검증 실패로 처리되어 상위에서 throw new Error(... errorCode: REV141) 로 정상적인 안전 정지 흐름을 탔다. 즉 코드 결함이 아니라 데이터 안전 가드의 정상 동작이며, 실제로 의문스러운 대량 제거가 일어난 것인지 vs. 임계값이 너무 보수적인지에 대한 비즈니스 판단이 root cause 결정의 핵심이다.
Technical Analysis#
Code Path#
- Entry point:
packages/cupix-tesla-bim-revision-agent/src/bim-revision-service.ts:150(run) run→runBimCompare호출 (bim-revision-service.ts:177)runBimCompare가 forge 자식 프로세스 결과(bimCompareResults) 를 받아cpBimRevision.validateBimComparerResult(bimCompareResults, threshold)호출 (bim-revision-service.ts:680)- 검증 실패 시 throw (
bim-revision-service.ts:687-690) - 검증 실패는
hasExcessiveRemoval가드에서 발생 (packages/cupix-tesla-bim-revision-agent/src/model/cpbim-revision.ts:177-179,:234-265) - 외부
try/catch가 잡아서 cluster representative 로그를 출력하고bim_comparison_state를Error로 갱신 (bim-revision-service.ts:188-191) - Failure point:
model/cpbim-revision.ts:260(_validationErrorCode = ErrorCode.Agent.BimRevisionExcessiveRemoval)
if (cpBimRevision.validateBimComparerResult(bimCompareResults, threshold)) {
this.updateBimModelsFromComparison(cpBimRevision, report);
if (!cpBimRevision.saveBimRevisionResults()) {
this.setErrorCode(ErrorCode.Agent.BimRevisionFailedToSaveResult);
throw new Error('BimRevisionService::runBimCompare | end - failed to save bim compare results');
}
} else {
const validationErrorCode = cpBimRevision.validationErrorCode ?? ErrorCode.Agent.BimRevisionExtractorInvalidResult;
this.setErrorCode(validationErrorCode);
throw new Error(`BimRevisionService::runBimCompare | end - validation failed (errorCode: ${validationErrorCode})`);
}
if (report) {
if (this.hasExcessiveRemoval(report, cpBim, threshold)) {
return false;
}
private hasExcessiveRemoval = (report: ForgeAgent.Report, cpBim: CPBim, threshold: BimRevisionThreshold): boolean => {
const forgeRemovedCount = report.removed.length;
const forgeModifiedCount = report.modified.length;
const forgeExistCount = report.exist.length;
const elementCreatedCount = cpBim.cpElementsCreated.length;
const elementDeletedCount = cpBim.cpElementsDeleted.length;
const elementTotalCount = cpBim.cpElements.size;
const removedRatio = elementCreatedCount > 0 ? (forgeRemovedCount / elementCreatedCount) * 100 : 0;
if (forgeRemovedCount >= threshold.countThreshold || (elementCreatedCount > 0 && removedRatio >= threshold.ratioThreshold)) {
const logLevel = threshold.bypassThreshold ? 'warn' : 'error';
const trigger = forgeRemovedCount >= threshold.countThreshold ? `count ${forgeRemovedCount} >= ${threshold.countThreshold}` : `ratio ${removedRatio.toFixed(1)}% >= ${threshold.ratioThreshold}%`;
// ... logger[logLevel] (...)
if (threshold.bypassThreshold) {
logger.warn('CPBimRevision::validateBimComparerResult | bypass enabled, continuing');
return false;
}
this._validationErrorCode = ErrorCode.Agent.BimRevisionExcessiveRemoval;
return true;
}
return false;
};
} catch (ec: any) {
logger.error('BimRevisionService::run | error: %s', JSON.stringify(ec.message));
await this.updateBimRevisionBimComparisonState(targetId, TESLA.UpdateBimRevisionRequest.BimComparisonStateEnum.Error, this.errorCode);
}
기대 동작은 “Forge 비교에서 제거 비율이 facility 가 정한 안전 한계를 넘으면 자동 적용을 중단하고 사람의 확인을 요구한다”이고, 실제 로그가 보여주는 동작도 정확히 그것이다. 즉 throw 자체는 의도된 안전 정지(graceful safety abort) 이며, 호출부가 이를 cluster 의 error 레벨로 기록한 것이 error-sweeper 에 잡힌 원인이다.
Log Evidence#
쿼리 (재현용):
service:cupixworks-any-bimrevision-agent "REV141"
service:cupixworks-any-bimrevision-agent "excessive removal"
service:cupixworks-any-bimrevision-agent (24612 OR 19655)
발생 시점 전후 핵심 로그 (KST 변환):
{"timestamp":"2026-06-24 23:06:45 KST","status":"info","message":"BaseService::runByMessage | id: 24612"}
{"timestamp":"2026-06-24 23:06:47 KST","status":"info","message":"BimRevisionService::REVISE-BEGIN | {\"bim_id\":19655,\"src_revision_id\":24612,\"src_revision_name\":\"V2\",\"prev_revision_id\":23776,\"prev_revision_name\":\"V1\",\"agent_version\":\"10.98.0\",\"si_trace_id\":\"bcddea93-45fb-4478-93b0-fccc9d6b0c7f\",\"cp_elements_count\":77,\"cp_elements_created_count\":77,\"cp_elements_deleted_count\":0,\"src_forge_urn\":\"dXJuOmFkc2sud2lwZW1lYTpmcy5maWxlOnZmLlN1M29lUFVzUS1TajlaeVY1QkFwMXc_dmVyc2lvbj0z\",\"prev_forge_urn\":\"dXJuOmFkc2sud2lwZW1lYTpmcy5maWxlOnZmLlN1M29lUFVzUS1TajlaeVY1QkFwMXc_dmVyc2lvbj0y\"}"}
{"timestamp":"2026-06-24 23:07:04 KST","status":"error","message":"CPBimRevision::validateBimComparerResult | excessive removal detected - bimRevisionId: 24612, bimId: 19655, trigger: ratio 26.0% >= 15%"}
{"timestamp":"2026-06-24 23:07:04 KST","status":"error","message":"BimRevisionService::run | error: \"BimRevisionService::runBimCompare | end - validation failed (errorCode: REV141)\""}
{"timestamp":"2026-06-24 23:07:04 KST","status":"info","message":"BimRevisionService::REVISE-END | {\"bim_id\":19655,\"src_revision_id\":24612,\"prev_revision_id\":23776,\"si_trace_id\":\"bcddea93-45fb-4478-93b0-fccc9d6b0c7f\",\"elapsed_ms\":19388,\"status\":\"error\",\"error_message\":\"BimRevisionService::runBimCompare | end - validation failed (errorCode: REV141)\",\"counts\":{\"total\":0,\"modified\":0,\"removed\":0,\"exist\":0},\"cycle_state_changes\":{},\"model_id_changes\":{},\"external_id_changed_count\":0,\"bounds_changed_count\":0,\"anomaly_count\":0}"}
REVISE-END 의 counts.removed: 0 은 “REV141 발동으로 가드가 먼저 빠져나갔기 때문에 적용 단계까지 가지 않았다”는 뜻이다 — validateBimComparerResult 가 hasExcessiveRemoval 분기에서 즉시 false 를 리턴해 setRemoved() 등 적용 루프를 실행하지 않는다 (cpbim-revision.ts:177-179).
14일 창에서 동일 메시지가 다른 BIM 에서도 반복 발생:
2026-06-18 22:42 KST bim_id 17446 rev 24299 (vs 22131) REV141
2026-06-18 19:32 KST bim_id 17446 rev 24282 (vs 22131) REV141
2026-06-18 12:52 KST bim_id 2760 rev 3554 (vs 3112) REV141
2026-06-18 10:58 KST bim_id 2760 rev 3552 (vs 3112) REV141
2026-06-18 10:33 KST bim_id 2760 rev 3551 (vs 3112) REV141
(bim_id: 17446, bim_id: 2760 은 동일 prev_revision 으로 여러 번 재시도된 흔적 — facility 가 임계값에 걸리는 변경이 들어오자 사용자가 같은 비교를 반복적으로 실행한 것으로 보임.)
기본 ratio threshold 는 40 % 이지만 (config/constants.ts:47 DefaultBimRevisionRemovedRatioThreshold = 40) 이번 facility (drdm2z) 는 entity parameter bim_revision_removed_ratio_threshold 가 15 로 override 되어 있어 트리거 비교 메시지가 15% 로 출력된 것이다 (bim-revision-service.ts:765).
Hypotheses Considered#
| # | Hypothesis | Evidence for | Evidence against | Verdict |
|---|---|---|---|---|
| H1 | Forge 비교에서 보고된 제거 비율이 facility 임계값(15%) 을 넘어 hasExcessiveRemoval 가드가 의도적으로 검증 실패시키고 REV141 을 throw 함 (안전 정지) |
excessive removal detected ... trigger: ratio 26.0% >= 15% 로그 (2026-06-24 23:07:04 KST). 코드 경로 cpbim-revision.ts:243 가 removedRatio >= threshold.ratioThreshold 에서 true 반환 → validateBimComparerResult 가 false 반환 → bim-revision-service.ts:687-690 에서 validationErrorCode: REV141 로 throw. REVISE-END.counts.removed: 0 (적용 단계 미진입) 일치. |
— | Confirmed |
| H2 | Forge 자식 프로세스가 잘못된 응답을 반환해 runBimCompare 가 BimRevisionForgeInvalidResponse (AGT1908) 로 실패한 케이스 |
bim-revision-service.ts:674-678 에 해당 분기 존재 |
실제 로그 메시지가 forge response is invalid 가 아니라 validation failed (errorCode: REV141) 이며, excessive removal detected 가드가 명시적으로 발동된 흔적이 있음 |
Rejected |
| H3 | Forge 자체의 critical 에러 (ForgeErrorMapper.mapForgeErrorToRevisionError) 가 매핑되어 throw 된 케이스 |
bim-revision-service.ts:663-672 에 분기 존재. 비슷한 throw 메시지 형태 가능. |
forgeErrorCode: %s warn 로그 흔적 없음. 실제 throw 메시지는 Forge error: ... 이 아니라 validation failed (errorCode: REV141) 형태 |
Rejected |
| H4 | 단순 transient 네트워크/Tesla API 실패로 인해 loadBimRevision 등 초기 단계에서 throw |
— | REVISE-BEGIN 가 정상 출력 (revision 메타와 prev URN 모두 채워짐), cp_elements_created_count: 77. 즉 element/level 로드는 성공했고 forge 비교까지 도달함 |
Rejected |
| H5 | 임계값(15%) 이 facility drdm2z 의 실제 변경 패턴 대비 너무 보수적이라 정상적 리비전이 반복적으로 차단되는 chronic 문제 |
14일 창에서 같은 prev_revision(22131, 3112) 으로 여러 번 재시도된 흔적 (bim_id 17446, 2760). 동일 BIM 에서 REV141 반복. |
단일 데이터 포인트만으로 “보수적” 단정 불가 — 비즈니스/안전 정책 결정 영역 | Inconclusive — 비즈니스 결정 필요 |
Fix Recommendation#
즉시 조치 (Critical)#
코드 변경 불필요. 본 에러는 bim-revision-service.ts:687-690 의 의도적인 안전 정지(safety abort) 가 정상 동작한 결과이며, cpbim-revision.ts:234-265 의 hasExcessiveRemoval 가드는 의도적으로 설계된 데이터 보호 장치다. 운영 측 조치만 필요:
- 데이터 검토:
bimRevisionId: 24612(bim_id: 19655, facilitydrdm2z, V1 → V2) 가 실제로 26% element 가 제거되어야 하는 의도된 변경인지 facility 담당자(exyte 팀) 확인.- 의도된 변경 → facility entity parameter
bim_revision_bypass_threshold를 일시적으로true로 설정 후 재실행 (bim-revision-service.ts:767-775). - 의도되지 않은 변경 → 사용자가 V2 forge URN 을 수정/재업로드 후 새 revision 으로 재시도.
- 의도된 변경 → facility entity parameter
단기 개선 (1주 이내)#
-
로그 레벨 재고:
REV141은 “정책 위반에 의한 안전 정지” 라서 error-sweeper 에 cluster 로 잡혀 매번 RCA 가 돌게 된다 (운영 부담).bim-revision-service.ts:189의 catch 에서ec.message가 REV141 같이 “안전 정지 계열 errorCode” 일 때는logger.warn으로 격하하는 것을 검토. 코드 결함이 아닌 정책 발동을 cluster type=error 로 끌어올리는 것은 신호/잡음 비를 떨어뜨린다 (memory: AUTH20022/AUTH20023 다운그레이드 episode 와 동일 패턴). -
에러 메시지에 trigger 정보 포함: 현재 throw 메시지는
validation failed (errorCode: REV141)까지만 알려주고 “비율 26.0% vs 임계값 15%” 정보는 별도 로그에만 존재한다. throw message 에 trigger 컨텍스트(ratio 26.0% >= 15%등) 를 포함시키면 cluster representative log 만 봐도 즉시 진단 가능. 변경 위치는cpbim-revision.ts:260부근에서 trigger 문자열을 인스턴스 필드로 보존,bim-revision-service.ts:687-690에서 throw 시 합치는 형태. -
모니터링 수치 분리: REV141 (정책 발동) vs AGT1908/AGT1904/AGT1905 (실제 에러) 를 Datadog 대시보드에서 다른 패널로 분리하여 운영 알림이 “정책 발동” 으로 깨지지 않도록.
장기 개선 (재발 방지)#
- Facility 별 임계값 운영 가이드: facility
drdm2z처럼 ratio threshold 를 15 로 낮춘 facility 가 14일 창에서 반복 REV141 을 일으키는지 정기적으로 점검. 너무 낮으면 사용자 워크플로 차단, 너무 높으면 안전 장치 무력화. 임계값 조정 책임 주체와 변경 이력을 entity parameter audit 으로 추적. - 사용자 노출 메시지 정합성:
bim_comparison_state: Error로 기록되었을 때 사용자(facility 운영자) UI 가 “과도한 제거가 감지되어 안전 차단됨, 차이를 검토 후 bypass 또는 수정” 같이 actionable 한 사유를 보여주는지 확인. 단순 "Error" 로만 노출되면 사용자는 시스템 결함으로 오해.
Monitoring#
-
REV141 발동 추이 (정책 발동, 비율 표기)
textsum:trace.express.request.errors\{service:cupixworks-any-bimrevision-agent,error.message:*REV141*\}.as_count() -
REV141 facility 별 빈도 (excessive removal 가드 발동) — 로그 facet 기반:
textlogs("service:cupixworks-any-bimrevision-agent \"excessive removal detected\"").index("*").rollup("count").by("@bimId").last("1d") -
BIM 리비전 비교 실패율 (모든 errorCode 포함, 단일 line)
textlogs("service:cupixworks-any-bimrevision-agent \"REVISE-END\" \"\\\"status\\\":\\\"error\\\"\"").index("*").rollup("count").last("1d") -
알람 추천: facility 단일 키(
@bimId혹은@facilityKey) 에서 동일 prev_revision 으로 24h 내 REV141 가 3회 이상 → 임계값 조정 또는 사용자 가이드 필요 신호.
Risk Assessment#
- Risk level: low — 코드 결함이 아니라 의도된 안전 정지의 정상 동작. 데이터 손상이나 다운스트림 장애 없음.
- 예상 복잡도: trivial — 코드 변경 자체는 즉시 불필요. 단기 개선 2번(throw 메시지에 trigger 포함) 은 5-10줄 변경, throw site 두 곳 동기화만 하면 됨. 운영/임계값 결정은 비즈니스 결정으로 분리 추적.