# Creative: Runtime Logs Cleanup & Tail (CP-3)

📌 **CREATIVE PHASE START: Cleanup Semantics & Tail Limits**
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

## 1️⃣ PROBLEM

**Description:** Sync cleanup больших `.log` файлов на HTTP worker; tail/preview без OOM. Нужны чёткие лимиты и режимы очистки, совместимые с sidecar `docker logs -f >> file` (файл пересоздаётся при рестарте sidecar).

**Requirements:**
- Cleanup — **синхронный** HTTP (решение заказчика)
- Audit: `size_before`, `size_after`, `action`
- Sidecar продолжает писать в тот же путь после truncate
- Защита от чтения гигабайтных файлов в tail

**Constraints:**
- Без `jobs.Registry` для cleanup
- Request timeout: разумный предел на handler (context с deadline 60s для cleanup)
- Файлы: только allowlisted basenames (CP-4)

## 2️⃣ OPTIONS — Cleanup mode

| Option | Описание |
|--------|----------|
| **A** | **Truncate** по умолчанию (`os.Truncate(0)` или `O_TRUNC`) — файл остаётся, inode может сохраниться |
| **B** | **Delete** по умолчанию — `os.Remove`, sidecar создаст при следующей записи |
| **C** | Rotate: rename to `.old` + create new |
| **D** | Truncate только &lt; N MB, иначе reject |

## 3️⃣ ANALYSIS — Cleanup

| Criterion | A Truncate | B Delete | C Rotate | D Size gate |
|-----------|------------|----------|----------|-------------|
| Sidecar совместимость | ⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐ | ⭐⭐⭐ |
| Predictable filename | ⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐ | ⭐⭐⭐⭐ |
| Sync latency | ⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐⭐ |
| Audit clarity | ⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐ |

**Key insight:** sidecar открывает файл через shell redirect `>>`; **truncate** обнуляет содержимое без смены имени в list — оператор видит тот же `evobgp-all.log`. Delete допустим как явная опция (файл исчезнет из list до следующей строки sidecar).

## 4️⃣ DECISION — Cleanup

**Default:** `mode=truncate` (query param, default when omitted).

**Optional:** `mode=delete` — только operator, UI second action «Удалить файл полностью».

**Max file size for cleanup:** **512 MiB** — выше reject `413` / problem `file_too_large` (защита sync worker). Документировать в OpenAPI.

**Handler timeout:** `60s` context на cleanup; для типичных log &lt; 512 MiB truncate/delete — миллисекунды.

**Audit:** всегда запись после успешной операции; при ошибке — no audit, `500`.

## 2️⃣ OPTIONS — Tail / preview

| Option | Lines default | Bytes cap |
|--------|---------------|-----------|
| **T1** | 200 lines | 256 KiB |
| **T2** | 500 lines | 1 MiB |
| **T3** | 1000 lines | 512 KiB |

## 4️⃣ DECISION — Tail

**Query params** `GET /v1/runtime-logs/files/{filename}`:

| Param | Default | Max | Note |
|-------|---------|-----|------|
| `lines` | 200 | 2000 | Читать с конца файла |
| `bytes` | — | 262144 (256 KiB) | Альтернатива lines; если оба — **min** лимит |
| `grep` | — | max 128 chars | Опционально; фильтр после чтения tail chunk |

**Implementation:** read last N bytes (cap 256 KiB), split lines, take last `lines` (cap 2000). Не mmap всего файла.

**grep:** простой `strings.Contains` post-filter (не regex) — снижает ReDoS risk.

## 5️⃣ IMPLEMENTATION NOTES

- `internal/runtimelogs/tail.go` — `TailFile(path, opts) ([]byte, truncated bool, err)`
- `internal/runtimelogs/cleanup.go` — `Cleanup(path, mode) (sizeBefore, sizeAfter int64, err)`
- OpenAPI enum `RuntimeLogCleanupMode: truncate | delete`
- Response cleanup: `{ "audit_id", "filename", "action", "size_before", "size_after" }`
- UI: primary button «Очистить (обнулить)»; secondary «Удалить файл»

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
📌 **CREATIVE PHASE END: Cleanup & Tail**
