Codex Lab 환경(iran-airstrike-replay-codex)에서 검증 완료된 어구 모선 자동 추론 + 검토 워크플로우 전체를 이식. ## Python (prediction/) - gear_parent_inference(1,428줄): 다층 점수 모델 (correlation + name + track + prior bonus) - gear_parent_episode(631줄): Episode 연속성 (Jaccard + 공간거리) - gear_name_rules: 모선 이름 정규화 + 4자 미만 필터 - scheduler: 추론 호출 단계 추가 (4.8) - fleet_tracker/kcgdb: SQL qualified_table() 동적화 - gear_correlation: timestamp 필드 추가 ## DB (database/migration/ 012~015) - 후보 스냅샷, resolution, episode, 라벨 세션, 제외 관리 테이블 9개 + VIEW 2개 ## Backend (Java) - 12개 DTO/Controller (ParentInferenceWorkflowController 등) - GroupPolygonService: parent_resolution LEFT JOIN + 15개 API 메서드 ## Frontend - ParentReviewPanel: 모선 검토 대시보드 - vesselAnalysis: 10개 신규 API 함수 + 6개 타입 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
515 lines
17 KiB
Markdown
515 lines
17 KiB
Markdown
# Gear Parent Inference Algorithm Spec
|
|
|
|
## 문서 목적
|
|
|
|
이 문서는 현재 구현된 어구 모선 추적 알고리즘을 모듈, 메서드, 파라미터, 판단 기준, 저장소, 엔드포인트, 영향 관계 기준으로 정리한 구현 명세다. `GEAR-PARENT-INFERENCE-DATAFLOW-PAPER.md`가 서술형 통합 문서라면, 이 문서는 구현과 후속 변경 작업에 바로 연결할 수 있는 참조 스펙이다.
|
|
|
|
## 1. 시스템 요약
|
|
|
|
### 1.1 현재 목적
|
|
|
|
- 최근 24시간 한국 수역 AIS를 캐시에 유지한다.
|
|
- 어구 이름 패턴과 위치를 기준으로 어구 그룹을 만든다.
|
|
- 주변 선박/오분류 어구를 correlation 후보로 평가한다.
|
|
- 후보 중 대표 모선 가능성이 높은 선박을 추론한다.
|
|
- 사람의 라벨/제외를 별도 저장소에 남겨 향후 모델 평가와 자동화 전환에 활용한다.
|
|
|
|
### 1.2 현재 점수 구조의 역할 구분
|
|
|
|
- `gear_correlation_scores.current_score`
|
|
- 후보 스크리닝용 correlation score
|
|
- EMA 기반 단기 메모리
|
|
- `gear_group_parent_candidate_snapshots.final_score`
|
|
- 모선 추론용 최종 후보 점수
|
|
- coverage-aware 보정과 이름/안정성/episode/lineage/label prior 반영
|
|
- `gear_group_parent_resolution`
|
|
- 그룹별 현재 추론 상태
|
|
- `gear_group_episodes`, `gear_group_episode_snapshots`
|
|
- `sub_cluster_id`와 분리된 continuity memory
|
|
- `gear_parent_label_tracking_cycles`
|
|
- 라벨 세션 동안의 자동 추론 성능 추적
|
|
|
|
## 2. 현재 DB 저장소와 유지 기간
|
|
|
|
| 저장소 | 역할 | 현재 유지 규칙 |
|
|
| --- | --- | --- |
|
|
| `group_polygon_snapshots` | `1h/1h-fb/6h` 그룹 스냅샷 | `7일` cleanup |
|
|
| `gear_correlation_raw_metrics` | correlation raw metric 시계열 | `7일` retention partition |
|
|
| `gear_correlation_scores` | correlation EMA score 현재 상태 | `30일` 미관측 시 cleanup |
|
|
| `gear_group_parent_candidate_snapshots` | cycle별 parent candidate snapshot | 현재 자동 cleanup 없음 |
|
|
| `gear_group_parent_resolution` | 그룹별 현재 추론 상태 1행 | 현재 자동 cleanup 없음 |
|
|
| `gear_group_episodes` | active/merged/expired episode 현재 상태 | 현재 자동 cleanup 없음 |
|
|
| `gear_group_episode_snapshots` | cycle별 episode continuity 스냅샷 | 현재 자동 cleanup 없음 |
|
|
| `gear_parent_candidate_exclusions` | 그룹/전역 후보 제외 | 기간 종료 또는 수동 해제까지 |
|
|
| `gear_parent_label_sessions` | 정답 라벨 세션 | 만료 시 `EXPIRED`, row는 유지 |
|
|
| `gear_parent_label_tracking_cycles` | 라벨 세션 cycle별 추적 | 현재 자동 cleanup 없음 |
|
|
|
|
## 3. 모듈 인덱스
|
|
|
|
### 3.1 시간/원천 적재
|
|
|
|
| 모듈 | 메서드 | 역할 |
|
|
| --- | --- | --- |
|
|
| `prediction/time_bucket.py` | `compute_safe_bucket()` | DB 적재 완료 전 bucket 차단 |
|
|
| `prediction/time_bucket.py` | `compute_initial_window_start()` | 초기 24h window 시작점 |
|
|
| `prediction/time_bucket.py` | `compute_incremental_window_start()` | overlap backfill 시작점 |
|
|
| `prediction/db/snpdb.py` | `fetch_all_tracks()` | safe bucket까지 초기 bulk 적재 |
|
|
| `prediction/db/snpdb.py` | `fetch_incremental()` | backfill 포함 증분 적재 |
|
|
| `prediction/cache/vessel_store.py` | `load_initial()` | 초기 메모리 캐시 구성 |
|
|
| `prediction/cache/vessel_store.py` | `merge_incremental()` | 증분 merge + dedupe |
|
|
| `prediction/cache/vessel_store.py` | `evict_stale()` | 24h sliding window 유지 |
|
|
|
|
### 3.2 어구 identity / 그룹
|
|
|
|
| 모듈 | 메서드 | 역할 |
|
|
| --- | --- | --- |
|
|
| `prediction/fleet_tracker.py` | `track_gear_identity()` | 어구 이름 파싱, identity log 관리 |
|
|
| `prediction/algorithms/gear_name_rules.py` | `normalize_parent_name()` | 모선명 정규화 |
|
|
| `prediction/algorithms/gear_name_rules.py` | `is_trackable_parent_name()` | 짧은 이름 제외 |
|
|
| `prediction/algorithms/polygon_builder.py` | `detect_gear_groups()` | 어구 그룹 및 서브클러스터 생성 |
|
|
| `prediction/algorithms/polygon_builder.py` | `build_all_group_snapshots()` | `1h/1h-fb/6h` 스냅샷 저장용 생성 |
|
|
|
|
### 3.3 correlation / parent inference
|
|
|
|
| 모듈 | 메서드 | 역할 |
|
|
| --- | --- | --- |
|
|
| `prediction/algorithms/gear_correlation.py` | `run_gear_correlation()` | raw metric + EMA score 계산 |
|
|
| `prediction/algorithms/gear_correlation.py` | `_compute_gear_vessel_metrics()` | proximity/visit/activity 계산 |
|
|
| `prediction/algorithms/gear_correlation.py` | `update_score()` | EMA + freeze/decay 상태 전이 |
|
|
| `prediction/algorithms/gear_parent_episode.py` | `build_episode_plan()` | continuity source와 episode assignment 계산 |
|
|
| `prediction/algorithms/gear_parent_episode.py` | `compute_prior_bonus_components()` | episode/lineage/label prior bonus 계산 |
|
|
| `prediction/algorithms/gear_parent_episode.py` | `sync_episode_states()` | `gear_group_episodes` upsert |
|
|
| `prediction/algorithms/gear_parent_episode.py` | `insert_episode_snapshots()` | episode snapshot append |
|
|
| `prediction/algorithms/gear_parent_inference.py` | `run_gear_parent_inference()` | 최종 모선 추론 실행 |
|
|
| `prediction/algorithms/gear_parent_inference.py` | `_build_candidate_scores()` | 후보별 상세 점수 계산 |
|
|
| `prediction/algorithms/gear_parent_inference.py` | `_name_match_score()` | 이름 점수 규칙 |
|
|
| `prediction/algorithms/gear_parent_inference.py` | `_build_track_coverage_metrics()` | coverage-aware evidence 계산 |
|
|
| `prediction/algorithms/gear_parent_inference.py` | `_select_status()` | 상태 전이 규칙 |
|
|
|
|
### 3.4 backend read model / workflow
|
|
|
|
| 모듈 | 메서드 | 역할 |
|
|
| --- | --- | --- |
|
|
| `GroupPolygonService.java` | group list/review/detail SQL | 최신 `1h` live + stale suppression read model |
|
|
| `ParentInferenceWorkflowController.java` | exclusion/label API | 사람 판단 저장소 API |
|
|
|
|
## 4. 메서드 상세
|
|
|
|
## 4.1 `prediction/time_bucket.py`
|
|
|
|
### `compute_safe_bucket(now: datetime | None = None) -> datetime`
|
|
|
|
- 입력:
|
|
- 현재 시각
|
|
- 출력:
|
|
- `safe_delay`를 뺀 뒤 5분 단위로 내림한 KST naive bucket
|
|
- 기준:
|
|
- `SNPDB_SAFE_DELAY_MIN`
|
|
- 영향:
|
|
- 초기 적재, 증분 적재, eviction 기준점
|
|
|
|
### `compute_incremental_window_start(last_bucket: datetime) -> datetime`
|
|
|
|
- 입력:
|
|
- 현재 캐시의 마지막 처리 bucket
|
|
- 출력:
|
|
- `last_bucket - SNPDB_BACKFILL_BUCKETS * 5m`
|
|
- 의미:
|
|
- 늦게 들어온 같은 bucket row 재흡수
|
|
|
|
## 4.2 `prediction/db/snpdb.py`
|
|
|
|
### `fetch_all_tracks(hours: int = 24) -> pd.DataFrame`
|
|
|
|
- 역할:
|
|
- safe bucket까지 최근 `N`시간 full load
|
|
- 핵심 쿼리 조건:
|
|
- bbox: `122,31,132,39`
|
|
- `time_bucket > window_start`
|
|
- `time_bucket <= safe_bucket`
|
|
- 출력 컬럼:
|
|
- `mmsi`, `timestamp`, `time_bucket`, `lat`, `lon`, `raw_sog`
|
|
|
|
### `fetch_incremental(last_bucket: datetime) -> pd.DataFrame`
|
|
|
|
- 역할:
|
|
- overlap backfill 포함 증분 load
|
|
- 핵심 쿼리 조건:
|
|
- `time_bucket > from_bucket`
|
|
- `time_bucket <= safe_bucket`
|
|
- 주의:
|
|
- 이미 본 bucket도 일부 다시 읽는 구조다
|
|
|
|
## 4.3 `prediction/cache/vessel_store.py`
|
|
|
|
### `load_initial(hours: int = 24) -> None`
|
|
|
|
- 역할:
|
|
- 초기 bulk DataFrame을 MMSI별 track cache로 구성
|
|
- 파생 효과:
|
|
- `_last_bucket` 갱신
|
|
- static info refresh
|
|
- permit registry refresh
|
|
|
|
### `merge_incremental(df_new: pd.DataFrame) -> None`
|
|
|
|
- 역할:
|
|
- 증분 batch merge
|
|
- 기준:
|
|
- `timestamp`, `time_bucket` 정렬
|
|
- `timestamp` 기준 dedupe
|
|
- 영향:
|
|
- 같은 bucket overlap backfill에서도 최종 row만 유지
|
|
|
|
### `evict_stale(hours: int = 24) -> None`
|
|
|
|
- 역할:
|
|
- sliding 24h 유지
|
|
- 기준:
|
|
- `time_bucket` 있으면 bucket 기준
|
|
- 없으면 timestamp fallback
|
|
|
|
## 4.4 `prediction/fleet_tracker.py`
|
|
|
|
### `track_gear_identity(gear_signals, conn) -> None`
|
|
|
|
- 역할:
|
|
- 어구 이름 패턴에서 `parent_name`, `gear_index_1`, `gear_index_2` 추출
|
|
- `gear_identity_log` insert/update
|
|
- 입력:
|
|
- gear signal list
|
|
- 주요 기준:
|
|
- 정규화 길이 `< 4`면 건너뜀
|
|
- 같은 이름, 다른 MMSI는 identity migration 처리
|
|
- 영향:
|
|
- `gear_correlation_scores.target_mmsi`를 새 MMSI로 이전 가능
|
|
|
|
## 4.5 `prediction/algorithms/polygon_builder.py`
|
|
|
|
### `detect_gear_groups(vessel_store) -> list[dict]`
|
|
|
|
- 역할:
|
|
- 어구 이름 기반 raw group 생성
|
|
- 거리 기반 서브클러스터 분리
|
|
- 근접 병합
|
|
- 입력:
|
|
- `all_positions`
|
|
- 주요 기준:
|
|
- 어구 패턴 매칭
|
|
- `440/441` 제외
|
|
- `is_trackable_parent_name()`
|
|
- `MAX_DIST_DEG = 0.15`
|
|
- 출력:
|
|
- `parent_name`, `parent_mmsi`, `sub_cluster_id`, `members`
|
|
|
|
### `build_all_group_snapshots(vessel_store, company_vessels, companies) -> list[dict]`
|
|
|
|
- 역할:
|
|
- `FLEET`, `GEAR_IN_ZONE`, `GEAR_OUT_ZONE`의 `1h/1h-fb/6h` snapshot 생성
|
|
- 주요 기준:
|
|
- 같은 `parent_name` 전체 기준 1h active member 수
|
|
- `GEAR_OUT_ZONE` 최소 멤버 수
|
|
- parent nearby 시 `isParent=true`
|
|
|
|
## 4.6 `prediction/algorithms/gear_correlation.py`
|
|
|
|
### `run_gear_correlation(vessel_store, gear_groups, conn) -> dict`
|
|
|
|
- 역할:
|
|
- 그룹당 후보 탐색
|
|
- raw metric 저장
|
|
- EMA score 갱신
|
|
- 입력:
|
|
- `gear_groups`
|
|
- 출력:
|
|
- `updated`, `models`, `raw_inserted`
|
|
|
|
### `_compute_gear_vessel_metrics(gear_center_lat, gear_center_lon, gear_radius_nm, vessel_track, params) -> dict`
|
|
|
|
- 출력 metric:
|
|
- `proximity_ratio`
|
|
- `visit_score`
|
|
- `activity_sync`
|
|
- `composite`
|
|
- 한계:
|
|
- raw metric은 짧은 항적에 과대 우호적일 수 있음
|
|
- 이 문제는 parent inference 단계의 coverage-aware 보정에서 완화
|
|
|
|
### `update_score(prev_score, raw_score, streak, last_observed, now, gear_group_active_ratio, shadow_bonus, params) -> tuple`
|
|
|
|
- 상태:
|
|
- `ACTIVE`
|
|
- `PATTERN_DIVERGE`
|
|
- `GROUP_QUIET`
|
|
- `NORMAL_GAP`
|
|
- `SIGNAL_LOSS`
|
|
- 의미:
|
|
- correlation score는 장기 기억보다 short-memory EMA에 가깝다
|
|
|
|
## 4.7 `prediction/algorithms/gear_parent_inference.py`
|
|
|
|
### `run_gear_parent_inference(vessel_store, gear_groups, conn) -> dict[str, int]`
|
|
|
|
- 역할:
|
|
- direct parent 보강
|
|
- active exclusion/label 적용
|
|
- 후보 점수 계산
|
|
- 상태 전이
|
|
- snapshot/resolution/tracking 저장
|
|
|
|
### `_load_existing_resolution(conn, group_keys) -> dict`
|
|
|
|
- 역할:
|
|
- 현재 그룹의 이전 resolution 상태 로드
|
|
- 현재 쓰임:
|
|
- `PREVIOUS_SELECTION` 후보 seed
|
|
- `stable_cycles`
|
|
- `MANUAL_CONFIRMED` 유지
|
|
- reject cooldown
|
|
|
|
### `_build_candidate_scores(...) -> list[CandidateScore]`
|
|
|
|
- 후보 집합 원천:
|
|
- 상위 correlation 후보
|
|
- registry name exact bucket
|
|
- previous selection
|
|
- 제거 규칙:
|
|
- global exclusion
|
|
- group exclusion
|
|
- reject cooldown
|
|
- 점수 항목:
|
|
- `base_corr_score`
|
|
- `name_match_score`
|
|
- `track_similarity_score`
|
|
- `visit_score_6h`
|
|
- `proximity_score_6h`
|
|
- `activity_sync_score_6h`
|
|
- `stability_score`
|
|
- `registry_bonus`
|
|
- `china_mmsi_bonus` 후가산
|
|
|
|
### `_name_match_score(parent_name, candidate_name, registry) -> float`
|
|
|
|
- 규칙:
|
|
- 원문 동일 `1.0`
|
|
- 정규화 동일 `0.8`
|
|
- prefix/contains `0.5`
|
|
- 숫자 제거 후 문자 부분 동일 `0.3`
|
|
- else `0.0`
|
|
|
|
### `_build_track_coverage_metrics(center_track, vessel_track, gear_center_lat, gear_center_lon) -> dict`
|
|
|
|
- 역할:
|
|
- short-track 과대평가 방지용 증거 강도 계산
|
|
- 핵심 출력:
|
|
- `trackCoverageFactor`
|
|
- `visitCoverageFactor`
|
|
- `activityCoverageFactor`
|
|
- `coverageFactor`
|
|
- downstream:
|
|
- `track`, `visit`, `proximity`, `activity` raw score에 곱해 effective score 생성
|
|
|
|
## 4.8 `prediction/algorithms/gear_parent_episode.py`
|
|
|
|
### `build_episode_plan(groups, previous_by_lineage) -> EpisodePlan`
|
|
|
|
- 역할:
|
|
- 현재 cycle group을 이전 active episode와 매칭
|
|
- `NEW`, `CONTINUED`, `SPLIT_CONTINUE`, `SPLIT_NEW`, `MERGE_NEW` 결정
|
|
- 입력:
|
|
- `GroupEpisodeInput[]`
|
|
- 최근 `6h` active `EpisodeState[]`
|
|
- continuity score:
|
|
- `0.75 * member_jaccard + 0.25 * center_support`
|
|
- 기준:
|
|
- `member_jaccard`
|
|
- 중심점 거리 `12nm`
|
|
- continuity score threshold `0.45`
|
|
- merge score threshold `0.35`
|
|
- 출력:
|
|
- assignment map
|
|
- expired episode set
|
|
- merged target map
|
|
|
|
### `compute_prior_bonus_components(...) -> dict[str, float]`
|
|
|
|
- 역할:
|
|
- 동일 candidate에 대한 episode/lineage/label prior bonus 계산
|
|
- 입력 집계 범위:
|
|
- episode prior: `24h`
|
|
- lineage prior: `7d`
|
|
- label prior: `30d`
|
|
- cap:
|
|
- `episode <= 0.10`
|
|
- `lineage <= 0.05`
|
|
- `label <= 0.10`
|
|
- `total <= 0.20`
|
|
- 출력:
|
|
- `episodePriorBonus`
|
|
- `lineagePriorBonus`
|
|
- `labelPriorBonus`
|
|
- `priorBonusTotal`
|
|
|
|
### `sync_episode_states(conn, observed_at, plan) -> None`
|
|
|
|
- 역할:
|
|
- active/merged/expired episode 상태를 `gear_group_episodes`에 반영
|
|
- 기준:
|
|
- merge 대상은 `MERGED`
|
|
- continuity 없는 old episode는 `EXPIRED`
|
|
|
|
### `insert_episode_snapshots(conn, observed_at, plan, payloads) -> int`
|
|
|
|
- 역할:
|
|
- cycle별 continuity 결과와 top candidate/result를 `gear_group_episode_snapshots`에 저장
|
|
- 기록:
|
|
- `episode_id`
|
|
- `parent_episode_ids`
|
|
- `top_candidate_mmsi`
|
|
- `top_candidate_score`
|
|
- `resolution_status`
|
|
|
|
### `_select_status(top_candidate, margin, stable_cycles) -> tuple[str, str]`
|
|
|
|
- 상태:
|
|
- `NO_CANDIDATE`
|
|
- `AUTO_PROMOTED`
|
|
- `REVIEW_REQUIRED`
|
|
- `UNRESOLVED`
|
|
- auto promotion 조건:
|
|
- `target_type == VESSEL`
|
|
- `CORRELATION` source 포함
|
|
- `final_score >= 0.72`
|
|
- `margin >= 0.15`
|
|
- `stable_cycles >= 3`
|
|
- review 조건:
|
|
- `final_score >= 0.60`
|
|
|
|
## 5. 현재 엔드포인트 스펙
|
|
|
|
## 5.1 조회 계열
|
|
|
|
### `/api/kcg/vessel-analysis/groups/parent-inference/review`
|
|
|
|
- 역할:
|
|
- 최신 전역 `1h` 기준 검토 대기 목록
|
|
- 조건:
|
|
- stale resolution 숨김
|
|
- candidate count는 latest candidate snapshot 기준
|
|
|
|
### `/api/kcg/vessel-analysis/groups/{groupKey}/parent-inference`
|
|
|
|
- 역할:
|
|
- 특정 그룹의 현재 live sub-cluster 상세
|
|
- 주의:
|
|
- “현재 최신 전역 `1h`에 실제 존재하는 sub-cluster만” 반환
|
|
|
|
### `/api/kcg/vessel-analysis/parent-inference/candidate-exclusions`
|
|
|
|
- 역할:
|
|
- 그룹/전역 제외 목록 조회
|
|
|
|
### `/api/kcg/vessel-analysis/parent-inference/label-sessions`
|
|
|
|
- 역할:
|
|
- active 또는 전체 라벨 세션 조회
|
|
|
|
## 5.2 액션 계열
|
|
|
|
### `POST /candidate-exclusions/global`
|
|
|
|
- 역할:
|
|
- 전역 후보 제외 생성
|
|
- 영향:
|
|
- 다음 cycle부터 모든 그룹에서 해당 MMSI 제거
|
|
|
|
### `POST /groups/{groupKey}/parent-inference/{subClusterId}/exclude`
|
|
|
|
- 역할:
|
|
- 그룹 단위 후보 제외 생성
|
|
- 영향:
|
|
- 다음 cycle부터 해당 그룹에서만 제거
|
|
|
|
### `POST /groups/{groupKey}/parent-inference/{subClusterId}/label`
|
|
|
|
- 역할:
|
|
- 기간형 정답 라벨 세션 생성
|
|
- 영향:
|
|
- 다음 cycle부터 tracking row 누적
|
|
|
|
## 6. 현재 기억 구조와 prior bonus
|
|
|
|
### 6.1 short-memory와 long-memory의 분리
|
|
|
|
- `gear_correlation_scores`
|
|
- EMA short-memory
|
|
- 미관측 시 decay
|
|
- 현재 후보 seed 역할
|
|
- `gear_group_parent_resolution`
|
|
- 현재 상태 1행
|
|
- same-episode가 아니면 `PREVIOUS_SELECTION` carry를 직접 사용하지 않음
|
|
- `gear_group_episodes`
|
|
- continuity memory
|
|
- `candidate_snapshots`
|
|
- bonus 집계 원천
|
|
|
|
### 6.2 현재 final score의 장기 기억 반영
|
|
|
|
현재는 과거 점수를 직접 carry하지 않고, 약한 prior bonus만 후가산한다.
|
|
|
|
```text
|
|
final_score =
|
|
current_signal_score
|
|
+ china_mmsi_bonus
|
|
+ prior_bonus_total
|
|
```
|
|
|
|
여기서 `prior_bonus_total`은:
|
|
|
|
- `episode_prior_bonus`
|
|
- `lineage_prior_bonus`
|
|
- `label_prior_bonus`
|
|
|
|
의 합이며 총합 cap은 `0.20`이다.
|
|
|
|
### 6.3 왜 weak prior인가
|
|
|
|
과거 점수를 그대로 넘기면:
|
|
|
|
- 다른 episode로 잘못 관성이 전이될 수 있다
|
|
- split/merge 이후 잘못된 top1이 고착될 수 있다
|
|
- 오래된 오답이 장기 drift로 남을 수 있다
|
|
|
|
그래서 현재 구현은 과거 점수를 “현재 score 자체”가 아니라 “작은 bonus”로만 쓴다.
|
|
|
|
## 7. 현재 continuity / prior 동작
|
|
|
|
### 7.1 episode continuity
|
|
|
|
- 같은 lineage 안에서 최근 `6h` active episode를 불러온다.
|
|
- continuity score가 높은 이전 episode가 있으면 `CONTINUED`
|
|
- 1개 parent episode가 여러 current cluster로 이어지면 `SPLIT_CONTINUE` + `SPLIT_NEW`
|
|
- 여러 previous episode가 하나 current cluster로 모이면 `MERGE_NEW`
|
|
- 어떤 current와도 연결되지 못한 old episode는 `EXPIRED`
|
|
|
|
### 7.2 prior 집계
|
|
|
|
| prior | 참조 범위 | 현재 집계 값 |
|
|
| --- | --- | --- |
|
|
| episode prior | 최근 동일 episode `24h` | seen_count, top1_count, avg_score, last_seen_at |
|
|
| lineage prior | 동일 이름 lineage `7d` | seen_count, top1_count, top3_count, avg_score, last_seen_at |
|
|
| label prior | 라벨 세션 `30d` | session_count, last_labeled_at |
|
|
|
|
### 7.3 구현 시 주의
|
|
|
|
- 과거 점수를 직접 누적하지 말 것
|
|
- prior는 bonus로만 사용하고 cap을 둘 것
|
|
- split/merge 이후 parent 후보 관성은 약하게만 상속할 것
|
|
- stale live sub-cluster와 vanished old sub-cluster를 혼동하지 않도록, aggregation도 최신 episode anchor를 기준으로 할 것
|
|
|
|
## 8. 참조 문서
|
|
|
|
- [GEAR-PARENT-INFERENCE-DATAFLOW-PAPER.md](/Users/lht/work/devProjects/iran-airstrike-replay-codex/docs/GEAR-PARENT-INFERENCE-DATAFLOW-PAPER.md)
|
|
- [GEAR-PARENT-INFERENCE-WORKFLOW-V2.md](/Users/lht/work/devProjects/iran-airstrike-replay-codex/docs/GEAR-PARENT-INFERENCE-WORKFLOW-V2.md)
|
|
- [GEAR-PARENT-INFERENCE-WORKFLOW-V2-PHASE1.md](/Users/lht/work/devProjects/iran-airstrike-replay-codex/docs/GEAR-PARENT-INFERENCE-WORKFLOW-V2-PHASE1.md)
|