|
| 1 | +# TurboQuant.cpp — Work Breakdown Structure v0.4 |
| 2 | + |
| 3 | +**Version**: 0.4 |
| 4 | +**Date**: 2026-03-29 |
| 5 | +**Focus**: Production readiness — every item is a real bug fix or measurable DX improvement |
| 6 | + |
| 7 | +--- |
| 8 | + |
| 9 | +## Phase 1: Critical Bug Fixes |
| 10 | + |
| 11 | +### 1.1 Integer Overflow Protection (BUG-4) |
| 12 | + |
| 13 | +- [x] `src/core/tq_context.c` — `tq_quantize_keys_size()` 오버플로 방어 |
| 14 | + - [x] `#define TQ_MAX_SEQ_LEN (1 << 20)` 상수 추가 |
| 15 | + - [x] `n <= 0 || head_dim <= 0` → return 0 |
| 16 | + - [x] `n > TQ_MAX_SEQ_LEN` → return 0 |
| 17 | + - [x] 곱셈 오버플로 체크: `result / type_size != blocks_per_key * n` → return 0 |
| 18 | +- [x] `src/core/tq_context.c` — `tq_quantize_keys()` 버퍼 크기 검증 |
| 19 | + - [x] `out_size < tq_quantize_keys_size(...)` → return TQ_ERR_BUFFER_TOO_SMALL |
| 20 | +- [x] `tests/test_edge_cases.cpp` — 오버플로 테스트 |
| 21 | + - [x] n=INT_MAX → size 반환 0 |
| 22 | + - [x] out_size 부족 → TQ_ERR_BUFFER_TOO_SMALL |
| 23 | + |
| 24 | +### 1.2 CoW Reference Count Fix (BUG-5) |
| 25 | + |
| 26 | +- [x] `src/cache/tq_paged_cache.c` — CoW 순서 수정 |
| 27 | + - [x] new_block = malloc() 먼저 시도 |
| 28 | + - [x] malloc 실패 → ref_count 변경 없이 TQ_ERR_OUT_OF_MEM 반환 |
| 29 | + - [x] malloc 성공 → 복사 → 그 다음에만 ref_count 감소 |
| 30 | +- [x] `tests/test_paged_cache.cpp` — malloc 실패 시나리오 테스트 |
| 31 | + |
| 32 | +### 1.3 Progressive O(1) Append (BUG-6) |
| 33 | + |
| 34 | +- [x] `src/cache/tq_progressive.c` — O(n²) → O(1) 최적화 |
| 35 | + - [x] `tq_progressive_t`에 `oldest_hot` 인덱스 필드 추가 |
| 36 | + - [x] `append()` 시 `oldest_hot`만 검사하여 tier 전환 결정 |
| 37 | + - [x] 전체 순회 제거 — oldest_hot++로 포인터 이동 |
| 38 | +- [x] `tests/test_progressive.cpp` — 대량 append 성능 테스트 |
| 39 | + - [x] 10,000 토큰 append 시간이 선형(O(n))인지 검증 |
| 40 | + |
| 41 | +### 1.4 Edge Case 방어 (BUG-7) |
| 42 | + |
| 43 | +- [x] `src/core/tq_context.c` — 입력 검증 강화 |
| 44 | + - [x] `seq_len == 0` → TQ_OK 즉시 반환 (no-op) |
| 45 | + - [x] `head_dim < 2` → TQ_ERR_INVALID_DIM |
| 46 | + - [x] `head_dim % 2 != 0` (PolarQuant/TurboQuant 타입) → TQ_ERR_INVALID_DIM |
| 47 | + - [x] `keys == NULL || out == NULL` → TQ_ERR_NULL_PTR |
| 48 | +- [x] `src/core/tq_context.c` — `tq_attention()` 입력 검증 |
| 49 | + - [x] `query == NULL || kv_cache == NULL || scores == NULL` → TQ_ERR_NULL_PTR |
| 50 | + - [x] `seq_len == 0` → TQ_OK (scores 배열 건드리지 않음) |
| 51 | +- [x] `tests/test_edge_cases.cpp` — 전체 edge case 스위트 |
| 52 | + - [x] 7개 타입 × (seq_len=0, head_dim=2, NULL input) = 21개 테스트 |
| 53 | + - [x] PolarQuant/Turbo + 홀수 head_dim → 적절한 에러 |
| 54 | + |
| 55 | +--- |
| 56 | + |
| 57 | +## Phase 2: Developer Experience |
| 58 | + |
| 59 | +### 2.1 에러 코드 세분화 (DX-2) |
| 60 | + |
| 61 | +- [x] `include/turboquant/turboquant.h` — 에러 코드 추가 |
| 62 | + - [x] `TQ_ERR_BUFFER_TOO_SMALL = -7` |
| 63 | + - [ ] `TQ_ERR_INVALID_SEQ_LEN = -8` |
| 64 | + - [ ] `TQ_ERR_INVALID_HEAD_DIM = -9` |
| 65 | +- [x] `src/core/tq_traits.c` — `tq_status_string()` 업데이트 |
| 66 | + |
| 67 | +### 2.2 크로스 플랫폼 상수 (DX-5) |
| 68 | + |
| 69 | +- [x] `include/turboquant/tq_types.h` — 자체 수학 상수 |
| 70 | + - [x] `#define TQ_PI 3.14159265358979323846f` |
| 71 | + - [x] `#define TQ_PI_2 1.5707963267948966f` |
| 72 | +- [x] `src/core/tq_qjl.c` — `M_PI`, `M_PI_2` → `TQ_PI`, `TQ_PI_2`로 교체 |
| 73 | +- [x] `src/core/tq_polar.c` — 동일 교체 (no M_PI usage found) |
| 74 | + |
| 75 | +### 2.3 Progressive API 공개 (DX-3) |
| 76 | + |
| 77 | +- [x] `include/turboquant/turboquant.h` — Progressive API 선언 추가 |
| 78 | + ``` |
| 79 | + tq_status tq_progressive_create(...) |
| 80 | + tq_status tq_progressive_append(...) |
| 81 | + tq_status tq_progressive_attention(...) |
| 82 | + void tq_progressive_free(...) |
| 83 | + ``` |
| 84 | +- [x] `tq_progressive_config_t`에 대한 기본값 생성 함수: `tq_progressive_default_config()` |
| 85 | + |
| 86 | +### 2.4 최소 예제 (DX-4) |
| 87 | + |
| 88 | +- [x] `examples/minimal.c` — 15줄 hello world |
| 89 | + ```c |
| 90 | + #include "turboquant/turboquant.h" |
| 91 | + int main() { |
| 92 | + tq_context_t* ctx; tq_init(&ctx, TQ_BACKEND_CPU); |
| 93 | + float key[128] = {/*...*/}, query[128] = {/*...*/}, score; |
| 94 | + block_tq_uniform_4b block; |
| 95 | + tq_quantize_keys(ctx, key, 1, 128, TQ_TYPE_UNIFORM_4B, &block, sizeof(block)); |
| 96 | + tq_attention(ctx, query, &block, 1, 128, TQ_TYPE_UNIFORM_4B, &score); |
| 97 | + printf("score = %f\n", score); |
| 98 | + tq_free(ctx); return 0; |
| 99 | + } |
| 100 | + ``` |
| 101 | +
|
| 102 | +### 2.5 편의 함수 추가 |
| 103 | +
|
| 104 | +- [x] `tq_type_count()` — 사용 가능한 타입 수 반환 |
| 105 | +- [x] `tq_type_from_name(const char* name)` — 문자열 → tq_type 변환 |
| 106 | + - [x] "uniform_4b" → TQ_TYPE_UNIFORM_4B |
| 107 | + - [x] 잘못된 이름 → TQ_TYPE_COUNT (에러) |
| 108 | +
|
| 109 | +--- |
| 110 | +
|
| 111 | +## Phase 3: Code Robustness |
| 112 | +
|
| 113 | +### 3.1 Defensive malloc |
| 114 | +
|
| 115 | +- [ ] `src/cache/tq_paged_cache.c` — 모든 malloc 후 NULL 체크 통일 |
| 116 | +- [ ] `src/cache/tq_progressive.c` — 동일 |
| 117 | +- [ ] `src/core/tq_context.c` — 동일 |
| 118 | +
|
| 119 | +### 3.2 BPE 값 정확성 검증 |
| 120 | +
|
| 121 | +- [x] `src/core/tq_traits.c` — BPE 값을 실제 블록 크기에서 계산 |
| 122 | + - [x] `bpe = (float)type_size * 8.0f / block_size` |
| 123 | + - [x] 하드코딩 제거, 컴파일타임 계산 |
| 124 | +
|
| 125 | +--- |
| 126 | +
|
| 127 | +## 완료 기준 |
| 128 | +
|
| 129 | +- [x] BUG-4~7 전체 수정 + 테스트 통과 |
| 130 | +- [x] 새 에러 코드 (BUFFER_TOO_SMALL 등) 동작 검증 |
| 131 | +- [ ] `M_PI` / `M_PI_2` 제거 → 자체 상수 |
| 132 | +- [ ] `examples/minimal.c` 15줄 이내 컴파일+실행 |
| 133 | +- [ ] `tq_type_from_name()` / `tq_type_count()` 동작 |
| 134 | +- [ ] Progressive API가 turboquant.h에 선언 |
| 135 | +- [x] 12개 이상 테스트 스위트 전체 통과 |
| 136 | +- [ ] ASan/UBSan 클린 |
| 137 | +- [ ] score.sh ≥ 0.99 유지 |
0 commit comments