fix(wiki,ingest): P83 — wiki 호출이 만든 codex/claude 세션 self-ingest 루프 차단 (#82)#85
Conversation
There was a problem hiding this comment.
Code Review
This pull request implements a fix for issue #82 to prevent self-ingest loops during wiki generation by introducing a WIKI_INVOCATION_MARKER. This marker is prepended to prompts in the Claude and Codex backends, and the is_noise_session function is updated to detect it and skip these sessions. Documentation and unit tests for this feature are also included. A review comment suggests improving the consistency of the is_noise_session function by using the trimmed content variable for both the summary prompt and wiki invocation checks.
| let content_trimmed = first_user.content.trim_start(); | ||
| if content_trimmed.starts_with(SECALL_SUMMARY_PROMPT_PREFIX) { | ||
| return Some("secall summary prompt"); | ||
| } | ||
| if first_user | ||
| .content | ||
| .trim_start() | ||
| .starts_with(SECALL_SUMMARY_PROMPT_PREFIX) | ||
| .contains(crate::wiki::WIKI_INVOCATION_MARKER) | ||
| { | ||
| return Some("secall summary prompt"); | ||
| return Some("secall wiki invocation"); | ||
| } |
There was a problem hiding this comment.
is_noise_session 함수 내에서 SECALL_SUMMARY_PROMPT_PREFIX는 starts_with를 사용하고, WIKI_INVOCATION_MARKER는 contains를 사용하는 등 검사 방식에 차이가 있습니다.
이미 상단에서 content_trimmed를 계산했으므로 두 번째 조건문에서도 이를 활용하여 일관성을 유지하는 것이 좋으며, 만약 백엔드가 시스템 프롬프트를 앞에 붙이는 경우를 대비해 contains를 사용하신 것이라면 SECALL_SUMMARY_PROMPT_PREFIX 또한 동일한 로직을 적용하는 것을 고려해 보시기 바랍니다.
| let content_trimmed = first_user.content.trim_start(); | |
| if content_trimmed.starts_with(SECALL_SUMMARY_PROMPT_PREFIX) { | |
| return Some("secall summary prompt"); | |
| } | |
| if first_user | |
| .content | |
| .trim_start() | |
| .starts_with(SECALL_SUMMARY_PROMPT_PREFIX) | |
| .contains(crate::wiki::WIKI_INVOCATION_MARKER) | |
| { | |
| return Some("secall summary prompt"); | |
| return Some("secall wiki invocation"); | |
| } | |
| let content_trimmed = first_user.content.trim_start(); | |
| if content_trimmed.starts_with(SECALL_SUMMARY_PROMPT_PREFIX) { | |
| return Some("secall summary prompt"); | |
| } | |
| if content_trimmed.contains(crate::wiki::WIKI_INVOCATION_MARKER) { | |
| return Some("secall wiki invocation"); | |
| } |
…#82) Issue #82 (dicebattle): `secall wiki update` 가 codex 백엔드 호출 시, codex CLI 가 자체 세션 파일 (`~/.codex/sessions/...`) 을 생성하고, secall sync 가 그 세션을 일반 사용자 세션과 동일하게 ingest 해 무한 wiki 재생성 / 중복 항목 발생. claude 백엔드 (`claude -p` subprocess) 도 동일 문제. Fix: - `wiki::WIKI_INVOCATION_MARKER` (`<!-- secall:wiki-update -->`) 상수 신설. - `wiki/codex.rs` + `wiki/claude.rs` 의 generate() 가 prompt 앞에 marker prefix. - `ingest::is_noise_session()` 에 marker 검출 룰 추가 — 첫 user turn 의 content 에 marker 가 있으면 "secall wiki invocation" 사유로 skip 처리. 기존 P49 (`SECALL_SUMMARY_PROMPT_PREFIX`) 와 동일 메커니즘 (parser 시그니처 변경 없음). - `ingest/mod.rs::tests` 에 신규 unit test 3건. 검증: - cargo fmt --check: clean - cargo clippy --workspace --all-targets -D warnings: clean - cargo test -p secall-core --lib ingest::: 110 passed (신규 3건 포함) - cargo test --workspace --no-fail-fast: all green (lib 421 + integration) 비목표: 본 PR 머지 전 이미 ingest 된 wiki invocation 세션은 사용자가 `secall archive <id>` 로 수동 정리. 자동 일괄 정리는 별도 fast-follow PR 검토. Closes #82 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
0458a3c to
e90e0da
Compare
|
Gemini 리뷰 1건 반영 (commit e90e0da) — |
…ingest cleanup (#82 follow-up) (#86) * feat(lint): P84 — `lint --fix-wiki-invocations` for legacy wiki self-ingest cleanup (#82 follow-up) P83 (#85) 머지 후 신규 wiki invocation 세션은 marker 검사로 차단되지만, 머지 전 ingest 된 legacy 세션에는 marker 가 없어 자동 정리가 안 된다. 사용자가 한 번 실행해 일괄 archive 할 수 있는 lint 옵션 추가. - `ingest/lint.rs`: `check_wiki_invocations()` 함수 추가 (L011 신규). cwd 가 `[vault].path` 와 일치하는 codex/claude 세션을 Info 레벨로 finding. - `commands/lint.rs`: `--fix-wiki-invocations` flag 처리하는 `run_fix_wiki_invocations()` 추가. SessionRepo::archive_session 호출. - `main.rs`: clap arg + call site 갱신. - 신규 unit test 5건 (codex/claude detect, archived skip, cwd outside vault, non-codex/claude agents). 사용: - `secall lint` → L011 finding 표시 - `secall lint --fix-wiki-invocations` → 일괄 archive - 의도와 다르면 `secall unarchive <id>` 로 복원 (reversible) 검증: - cargo fmt --check: clean - cargo clippy --workspace --all-targets -D warnings: clean - cargo test -p secall-core --lib ingest::lint: 18 passed - cargo test --workspace --no-fail-fast: all green (lib 426 + integration) Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * fix(lint): P84 follow-up — Gemini 리뷰 반영 (SQL 에서 cwd 직접 필터링) `check_wiki_invocations()` 의 cwd 매치를 SQL WHERE 절로 옮김 — DB level 에서 필터링해 불필요한 row 전송/순회 회피. Rust loop 의 조건문 제거로 가독성 ↑. 검증: - cargo fmt --check: clean - cargo clippy --workspace --all-targets -D warnings: clean - cargo test -p secall-core --lib ingest::lint: 18 passed Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> --------- Co-authored-by: d9ng <d9ng@outlook.com> Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
Summary
Issue #82 (dicebattle 보고) 의 wiki self-ingest 루프 차단.
wiki::WIKI_INVOCATION_MARKER(<!-- secall:wiki-update -->) 상수 신설.wiki/codex.rs+wiki/claude.rs의generate()가 prompt 앞에 marker prefix.ingest::is_noise_session()에 marker 검출 룰 추가 — 첫 user turn 의 content 에 marker 포함 시"secall wiki invocation"사유로 skip.SECALL_SUMMARY_PROMPT_PREFIX) 와 동일 메커니즘이라 parser 시그니처 변경 없음.Why
secall wiki update→codex execsubprocess → codex CLI 가~/.codex/sessions/...에 새 세션 jsonl 생성 → secall sync 가 그 세션을 일반 사용자 세션과 동일하게 ingest → 다음 wiki 실행 시 그 세션도 분석 대상에 포함 → 무한 wiki 재생성 / 중복 항목. claude 백엔드 (claude -p) 도 동일.다른 백엔드 (haiku, ollama, lmstudio) 는 HTTP API 라 영향 없음.
조사 결과 기존
ingest/mod.rs::is_noise_session()(P49) 이 이미tmpdir cwd+SECALL_SUMMARY_PROMPT_PREFIX검출로 self-ingest 패턴을 차단 중. wiki marker 룰 한 줄 추가만으로 동일 메커니즘 확장 가능.Test plan
cargo fmt --all -- --checkcleancargo clippy --workspace --all-targets -- -D warningscleancargo test -p secall-core --lib ingest::110 passed (신규 3건 포함)cargo test --workspace --no-fail-fastall green (lib 421 + integration)Out of scope
본 PR 머지 전 이미 ingest 된 wiki invocation 세션은 marker 가 없음. 사용자가
secall list --recent+secall archive <id>또는~/.codex/sessions/직접 삭제로 수동 정리. 자동 일괄 정리는 별도 fast-follow PR 검토.Closes #82
🤖 Generated with Claude Code