세션 도구 결과에 이어보기 커서 — 절단이 손실로 끝나지 않게 (#4854) - #4863
Closed
kevin9327 wants to merge 1 commit into
Closed
Conversation
edwardkim#3787 S7 의 자원 상한(maxMatches·maxChars)은 컨텍스트 범람을 막지만 이어보기와 짝을 이루지 않았다. 그래서 호출자는 "상한을 켜고 뒤쪽을 잃거나" "상한을 끄고 범람하거나" 둘 중 하나만 고를 수 있었다. hwp_doc_search 가 특히 분명했다. 입력이 docId·query·caseSensitive·maxMatches 넷뿐이고 구현이 take(n) 이라 **n+1 번째 이후 매치에 도달할 인자 자체가 없었다**. 실측(samples/hwp3-sample.hwp, "의" 276건, maxMatches=3): offset 을 0·3·6 으로 바꿔도 devel 은 매번 같은 앞 3건을 돌려준다 — 273건이 도달 불가. 추가 전용으로 창을 옮길 수단을 준다. - hwp_doc_search 에 offset, hwp_doc_text 에 charOffset (둘 다 0 이상, 기본 0) - 두 봉투에 nextOffset — **남은 분량이 있을 때만** 싣는다. 있음/없음 자체가 "더 있다"의 신호라 호출자가 총량 산술로 끝을 추론하지 않아도 된다. truncated 는 "이 응답이 전체가 아니다"라는 뜻이라 마지막 창에서도 true 일 수 있어 종료 판정에 쓸 수 없다. - totalMatchCount 는 창과 무관하게 고정 — 흔들리면 "몇 건 중 몇 건" 계약이 무너진다. - 오프셋의 0 은 유효값이라 opt_limit 이 아닌 opt_offset 을 뒀다. -1·2.5·"3" 은 거부 — 오타를 "생략"으로 뭉개면 창이 처음으로 되돌아가 같은 구간을 무한히 다시 읽는다. - 총량을 넘긴 오프셋은 오류가 아니라 빈 결과 + nextOffset 없음. 여기서 오류를 내면 성실한 호출자의 마지막 한 번이 항상 실패한다. - 다 건너뛴 쪽도 pages[] 에서 빼지 않는다 — 빼면 pageCount 가 줄어 문서가 실제보다 짧아 보인다(edwardkim#3787 S7 이 절단에서 지킨 규칙과 같은 이유). 인자를 생략하면 종전과 바이트까지 같은 봉투가 나간다(계약 테스트가 원문 비교로 고정). 검증: 신규 tests/mcp_result_cursor_contract.rs 8본 통과(창 1·2·3·7 에서 이어 붙인 결과가 전수와 정확히 일치 — 중복 0·누락 0·순서 보존), 인접 계약 72본 회귀 통과, clippy --all-targets -D warnings 통과. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
Collaborator
|
통합 PR #4883(4412546)로 병합 완료했습니다. 원 head와 CI를 다시 확인해 누적 반영했고, 상세 검토·메인터너 보정·검증 근거는 archive 검토 기록에 남겼습니다. 중복 병합을 막기 위해 이 원 PR을 닫습니다. 감사합니다. |
Collaborator
|
통합 PR #4883(4412546)로 병합 완료했습니다. 원 head와 CI를 다시 확인해 누적 반영했고, 상세 검토·메인터너 보정·검증 근거는 archive 검토 기록에 남겼습니다. 중복 병합을 막기 위해 이 원 PR을 닫습니다. 감사합니다. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
이슈 #4854 의 처리 결과다.
문제
#3787 S7 의 자원 상한(
maxMatches·maxChars)은 컨텍스트 범람을 막지만 이어보기와 짝을이루지 않았다. 그래서 호출자는 둘 중 하나만 고를 수 있었다 — 상한을 켜고 뒤쪽을 잃거나,
상한을 끄고 범람하거나.
hwp_doc_search가 특히 분명했다. 입력이docId·query·caseSensitive·maxMatches넷뿐이고 구현이
take(n)이라 n+1 번째 이후 매치에 도달할 인자 자체가 없었다.전/후 실측
같은 문서·같은 검색어·같은 창 크기로 똑같은 요청 3건을 두 바이너리에 던졌다. BEFORE 는
src/mcp_serve.rs·src/main.rs가upstream/devel627c8c49a와 동일한 빌드다.변경
추가 전용(additive)이다. 인자를 생략하면 종전과 바이트까지 같은 봉투가 나간다.
hwp_doc_searchoffset(0 이상, 기본 0)hwp_doc_textcharOffset(0 이상, 기본 0)nextOffsetoffset·charOffset에코설계에서 지킨 것.
nextOffset의 있음/없음이 유일한 종료 신호다.truncated는 "이 응답이 전체가아니다"라는 뜻이라 마지막 창에서도 true 일 수 있어 종료 판정에 쓸 수 없다 — 스키마 설명에
이 구별을 명시했다.
totalMatchCount가 오프셋에 따라 흔들리면 "몇 건 중몇 건"이라는 계약이 무너진다.
0은 유효값이다. 상한의0("아무것도 주지 마라")과 뜻이 정반대라opt_limit이 아니라 별도opt_offset을 뒀다.-1·2.5·"3"은 거부한다 — 오타를"생략"으로 뭉개면 창이 조용히 처음으로 되돌아가 같은 구간을 무한히 다시 읽는다.
nextOffset없음으로 성공 처리한다.여기서 오류를 내면 성실한 호출자의 마지막 한 번이 항상 실패한다.
pages[]에서 빼지 않는다 — 빼면pageCount가줄어 문서가 실제보다 짧아 보인다([보안 설계] 간접 프롬프트 인젝션 내성 — 문서가 에이전트를 조종하지 못하게 (#3630 보안 확장) #3787 S7 이 절단에서 지킨 규칙과 같은 이유).
검증
cargo test --test mcp_result_cursor_contractboundary_integrity_contractmcp_session_query_contractmcp_server_contractmcp_spec_ledger_contractmcp_arg_validation_contractmcp_tool_annotations_contractmcp_next_call_contractcargo clippy --all-targets -- -D warningsrustfmt --check(변경 파일)신규 계약이 못 박는 것 중 핵심 셋.
search_offset_reaches_matches_beyond_max_matches—maxMatches:1로 창을 넘겨 전수276건 도달. 종전에는 존재할 수 없던 검사다.
search_window_partition_is_exact_for_larger_windows— 창 2·3·7 에서 이어 붙인 결과가전수와 정확히 일치(중복 0·누락 0·순서 보존).
omitting_offset_keeps_legacy_envelope_byte_identical— 인자 생략 =offset:0, 봉투원문이 바이트 동일.
알려진 비용·비목표
page를 생략한hwp_doc_text는 호출마다 전 쪽을 추출하므로 창을 잘게 쪼갤수록전체 훑기가 제곱으로 비싸진다. 이 PR 이 만든 비용이 아니라 종전 호출 비용이 홉 수만큼
곱해지는 것이다. 쪽을 아는 경우
page로 좁히면 비용은 그 쪽에만 든다.무상태 CLI 표면도 건드리지 않는다. 커서를 불투명 토큰으로 만들지 않는다 — 정수 오프셋이
결정론적이고 제3자가 손으로 검증할 수 있다.
처리 결과 문서:
mydocs/report/task_m100_4854_report.mdCloses #4854