- fb-26 (progress.rs): Fixed Aborted unconditional writeln (TTY duplicate output) and Completed TTY path missing summary line. Added KEBAB_PROGRESS=plain env override and quiet field to ProgressMode. - fb-28 (main.rs): Added --readonly / --quiet global flags with KEBAB_READONLY env. Readonly blocks mutating commands (ingest/ingest-file/ingest-stdin/reset) with exit code 1; error.v1 code "readonly_mode" in --json mode. Quiet suppresses all human progress/hint stderr while preserving errors. - Updated task spec status for p9-fb-26 and p9-fb-28 to 'merged'. - Updated tasks/INDEX.md and HANDOFF.md with merge status and summary entries. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
74 lines
3.9 KiB
Markdown
74 lines
3.9 KiB
Markdown
---
|
|
phase: P9
|
|
component: kebab-cli
|
|
task_id: p9-fb-26
|
|
title: "Ingest 로그 출력 일관성 (in-place vs 새 줄 혼재)"
|
|
status: merged
|
|
target_version: 0.3.0
|
|
depends_on: [p9-fb-02]
|
|
unblocks: []
|
|
contract_source: ../../docs/superpowers/specs/2026-04-27-kebab-final-form-design.md
|
|
contract_sections: [§7 ingest, §10 UX, §2.4a IngestEvent]
|
|
source_feedback: 사용자 도그푸딩 2026-05-05 — `kebab ingest` 진행 로그가 어떨 땐 새 라인으로, 어떨 땐 기존 라인 in-place 갱신으로 나와 일관성 떨어짐.
|
|
---
|
|
|
|
# p9-fb-26 — Ingest 로그 출력 일관성
|
|
|
|
> ⏳ **백로그 only — 미구현.** 본 spec 은 도그푸딩 피드백 skeleton. 구현 착수 전 [superpowers:brainstorming](../../docs/superpowers/) 으로 설계 단계 선행 필요. 옵션 A/B/C 중 결정 + behavior contract 확정 후 implementation PR 진행.
|
|
|
|
## 증상
|
|
|
|
`kebab ingest` 실행 중 진행 출력이 두 패턴 혼재:
|
|
|
|
- **TTY**: indicatif `ProgressBar` 단일 라인 in-place 갱신 (`ScanStarted` / `ScanCompleted` / `AssetStarted` / `AssetFinished`). 마지막 `Completed` / `Aborted` summary 만 별도 새 라인.
|
|
- **non-TTY (pipe / less / CI)**: 매 event 마다 `writeln!` 새 라인.
|
|
- 같은 세션 안에서도 환경 변경 (예: `kebab ingest 2>&1 | tee log`) 시 출력 형식 바뀜.
|
|
|
|
사용자 인지: "어떨 땐 새 라인, 어떨 땐 기존 라인 업데이트". 시각적 노이즈 + 스크롤백에 진행 흔적 일부만 남거나 전체 남는 비대칭.
|
|
|
|
## 원인
|
|
|
|
[crates/kebab-cli/src/progress.rs:99-188](../../crates/kebab-cli/src/progress.rs#L99-L188):
|
|
|
|
- TTY branch 는 `bar.set_message` / `bar.set_position` 으로 단일 라인 갱신.
|
|
- non-TTY branch (`if !tty { writeln!(err, ...) }`) 가 모든 event 마다 추가 라인.
|
|
- Completed / Aborted 는 TTY 에서도 `writeln!` 항상 호출 — bar finish 후 summary 한 줄.
|
|
|
|
## Goal
|
|
|
|
진행 로그의 출력 형식을 환경 무관하게 예측 가능하게 만든다. 사용자는 한 가지 형식을 보고 다른 환경에서도 같은 형식을 기대해야 함.
|
|
|
|
## Behavior contract (제안 — brainstorming 단계, 머지 전 사용자 확인)
|
|
|
|
옵션 A — **TTY = in-place, non-TTY = append-only, 둘 다 명시적**:
|
|
- TTY: 진행 라인은 in-place, summary 도 마지막에 같은 라인 commit (현재 처럼 새 줄 X) 또는 한 줄 띄우고 명시적 final.
|
|
- non-TTY: 매 event 한 줄 (현재 동작 유지) — pipe / log redirect 에서 진행 흔적 남는 게 정답.
|
|
- summary 라인은 두 모드 동일한 prefix (`ingest: complete (...)` / `ingest: aborted (...)`) 로 통일.
|
|
|
|
옵션 B — **항상 append-only**:
|
|
- TTY 에서도 spinner 끄고 매 event 새 라인. 단순, 진행 흔적 보존.
|
|
- 단점: bar UX 손실 — long ingest 에서 화면 가득.
|
|
|
|
옵션 C — **항상 in-place (TTY 만)**:
|
|
- non-TTY 면 마지막 summary 한 줄만, 중간 event silent.
|
|
- 단점: CI / log redirect 에서 진행 알 수 없음.
|
|
|
|
권장: **옵션 A** — 환경별 의미 명확, 두 형식 다 의도된 것임을 README 에 명시.
|
|
|
|
## 검증 / 테스트
|
|
|
|
- `kebab ingest` TTY 모드: spinner 한 라인만 차지, 종료 후 summary 한 줄.
|
|
- `kebab ingest 2>&1 | cat`: append-only 형식, 매 asset / scan event 한 줄.
|
|
- `kebab ingest --json`: 기존 ndjson 동작 유지 (영향 없음).
|
|
- snapshot test: non-TTY 스트림 포맷 안정.
|
|
|
|
## 관련 항목
|
|
|
|
- p9-fb-01 / p9-fb-02 (progress 인프라). 본 항목은 그 위의 일관성 follow-up.
|
|
- 사용자 visible surface — README **명령** 표 / Quick start 의 ingest 출력 예시 갱신 필요.
|
|
|
|
## Risks / notes
|
|
|
|
- indicatif `ProgressDrawTarget::stderr()` 가 일부 터미널 (TUI multiplexer, 일부 ssh client) 에서 in-place 갱신 fallback 으로 새 라인 그릴 수 있음 — 조사 필요.
|
|
- CI 가 TTY-emulating wrapper (예: GitHub Actions 일부) 면 의도 안 한 in-place 모드 진입 가능. 명시적 `KEBAB_PROGRESS=plain` env override 검토.
|