feat(cli): kebab reset (p9-fb-06) #49
Reference in New Issue
Block a user
Delete Branch "feat/p9-fb-06-reset"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
kebab reset [--all | --data-only | --vector-only | --config-only] [--yes]추가. 도그푸딩 후 사용자가 여러 config / 모델 조합 테스트 시 4 개 XDG 경로를 수동rm -rf해야 했던 막힘 (도그푸딩 강도 1위) 을 단일 명령 + TTY confirm 으로 해소.--yes없으면 exit 2 + hint).--vector-only가 SQLiteembedding_records도 함께 truncate — off-disk Lance dir 만 wipe 했을 때 store 가 사라진 row 를 가리키는 orphan 상태 회피.kebab init자동 호출은 안 함 —--all/--config-only후에는 hint 출력.--json모드는 frozenreset_report.v1스키마 (schema_version/scope/removed_paths/embedding_rows_truncated).confirm_destructivehelper (std::io::IsTerminal).Scope (p9-fb-06)
tasks/p9/p9-fb-06-data-reset-command.mddocs/superpowers/plans/2026-05-02-p9-fb-06-reset-command.mdtasks/p9/p9-dogfooding-feedback.md항목 4변경 사항
crates/kebab-store-sqlite:truncate_embedding_records()helper + 통합 테스트.crates/kebab-app:reset모듈 (ResetScope,ResetReport,enumerate_paths,estimate_size_bytes,execute).crates/kebab-cli:Cmd::Resetclap variant (mutually-exclusive scope flags viagroup = "reset_scope") + handler +confirm_destructivehelper + 4 통합 테스트.crates/kebab-cli/src/wire.rs:wire_resethelper.docs/wire-schema/v1/reset_report.schema.json: 새 schema.README.md,HANDOFF.md: 명령 표 + cleanup 절 + dated entry. ARCHITECTURE.md 는 무영향 (crate graph / locked-in decision 변경 없음).Plan deviation (회차 1 sweep 에서 짚었으나 자기-fix)
truncate_embedding_records가 원래Result<()>였는데Result<u64>로 bump (DELETE rowcount 직접 리턴 — 별도 COUNT 우회).kebab-app::reset::truncate_embeddings가SqliteStore::open(path)가정이었는데 실제는&Config. plan 의 caveat 문구 그대로 fix.config.toml = "schema_version = 1"가 Config parser 의 필수 section 검사에 걸려 marker 파일로 대체.Config::load(None)의 "파일 없으면 defaults" fallback 활용.Test plan
cargo test -p kebab-store-sqlite --test truncate_embeddings(2 PASS)cargo test -p kebab-app --lib reset(5 PASS)cargo test -p kebab-cli(전체 — wire 6 + reset_cli 4 PASS, 다른 통합 테스트 회귀 0)cargo clippy -p kebab-store-sqlite -p kebab-app -p kebab-cli --all-targets -- -D warningsclean후속
tasks/p9/p9-fb-06-data-reset-command.mdfrontmatter 를in_progress→completed로 한 줄 commit.kebab resetcommand with TTY confirm gate 286ac68c12회차 1 — critical 1건 + nit 1건 + 칭찬 3건.
핵심 actionable:
embeddings.rs의 truncate_embedding_records 위치 —mark_embedding_records_committed의 doc comment 14 줄을 흡수. Rust 의///가 다음 항목에 attach 되는 규칙 때문에 위쪽 mark_committed 함수의 doc 이 truncate 함수로 옮겨지고 mark_committed 는 doc 없이 남음. truncate 를 impl block 끝으로 옮기면 plan 의 원래 의도와도 일치 + mark_committed 의 design rationale (WHERE status='pending'이유 등) 보존.removed_paths길이 assert 보강 — idempotency 약속 ("존재하지 않는 path 는 omit") 묶어 검증.전체 인상: store/app/cli/wire/test/docs 6 commit 이 명확히 layer 별 분리. plan deviation 3건 모두 commit 메시지에 명시. clap ArgGroup 으로 mutually-exclusive scope 강제 + integration test 로 edge case 4 종 cover. 위 1건 정리하면 머지 가능.
(칭찬)
data_only: _,pattern binding +// The data_only: _ binding above is intentional ...코멘트가 미래 reader 의 "왜 unused 인가" 의문을 코드 옆에서 즉시 차단. clapgroup = "reset_scope"의 mutual exclusion 보장이 코드 옆 한 줄로 명시되어,data_only자체가 resolution 에 영향 없는 이유까지 설명.(칭찬) Non-TTY +
--yes부재 케이스를anyhow::bail!로 처리해 자동으로 exit 2 (default error path) 로 빠지면서eprintln!+ 메시지 한 번에 — silent destruction 금지 가드를 minimum surface 로 구현. integration testreset_no_yes_in_non_tty_aborts_with_exit_2가 정확히 이 경로 검증.(보강 권장)
data_only가 data + cache + state 3 dir 모두 wipe 하는데 test 가 그 셋 모두 not exists 검증 — 좋음. 다만removed_paths의 길이 (Vec<PathBuf>) 도 함께 assert 하면execute가 "존재하지 않는 path 는 omit" 한다는 idempotency 약속을 묶어서 검증 가능.Why: 현재
--json테스트는removed_paths가 array 인 것만 확인. data 만 만들고 cache/state 는 만들지 않은 케이스가 있으면 length 가 1 임을 명시 검증.How to apply:
reset_data_only_yes_json_emits_reset_report_v1에assert_eq!(v.get("removed_paths").and_then(|a| a.as_array()).map(|a| a.len()), Some(1));한 줄 추가 — data 만 만들고 cache/state 는 안 만들었으니 길이=1. 이번 PR 안에서 해소 권장 (작은 변경).@@ -107,6 +107,22 @@ impl SqliteStore {/// WHERE embedding_id IN (?, ?, …)`) inside one transaction —/// avoids the per-row `execute()` round-trip the previous/// implementation paid./// Wipe every row from `embedding_records`, returning the count of(critical / doc 흡수 버그)
truncate_embedding_records의 doc comment 가mark_embedding_records_committed함수의 doc comment 직후에 인접 — Rust 의///는 다음 항목에 attach 되므로 위쪽 14 줄짜리 mark_committed doc 이 truncate 의 doc 으로 흡수되고, mark_committed 자체는 doc 없이pub fn만 남음.Why: 이 함수의 doc 은 phase-3 commit 의 "왜 WHERE status='pending' 만 대상인가 / 왜 단일 transaction 인가" 같은 design rationale 을 담고 있어서 잃어버리면 미래 reader 가
WHERE status='pending'의 의도 (tombstone 보존, 중복 batch 방지) 를 추적 불가.How to apply:
truncate_embedding_records를impl SqliteStore블록 끝 (mark_committed 의 닫는}다음) 으로 옮긴다. plan 의 원래 의도 ("Append at the end ofimpl SqliteStore") 와도 일치. 옮긴 후 mark_committed 의 doc comment 14 줄이 다시 그 함수에 attach 되는지 확인.@@ -0,0 +6,4 @@"type": "object","required": ["schema_version","scope",(칭찬) 기존 sibling schema 들 (
ingest_report.v1,doctor.v1등) 의$idURL pattern (https://kb.local/wire/v1/...) 을 정확히 따르고,additionalProperties필드를 명시 안 한 것까지 sibling 일관 (sibling 들도 명시 안 함). frozen wire schema 의 가족 일원이 됨.회차 2 — 회차 1 critical (truncate doc 흡수) + nit (removed_paths idempotency assert) 모두 정확히 반영. 추가 actionable 0. APPROVE.