From 38144cdc335c87673de20218b0b8639c080de73a Mon Sep 17 00:00:00 2001 From: Son Seong Jun <166786347+SonAIengine@users.noreply.github.com> Date: Mon, 26 Oct 2026 14:53:39 +0900 Subject: [PATCH] =?UTF-8?q?=EC=8B=A0=EB=A2=B0=20=EB=AA=A8=EB=93=9C?= =?UTF-8?q?=EC=9D=98=20goal=EB=8B=B9=20=EA=B8=B0=EB=B3=B8=20model=20turn?= =?UTF-8?q?=EC=9D=84=2024=EC=97=90=EC=84=9C=2096=EC=9C=BC=EB=A1=9C=20?= =?UTF-8?q?=EC=98=AC=EB=A0=B8=EB=8B=A4=20(ADR-0062)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Claude Code 비교 실험에서 rename 작업(참조 137개)과 저장소 상태 조회 작업(저장소 24개)이 둘 다 24 turn 예산을 다 쓰고 멈췄다. 신뢰 모드는 사람이 단계마다 보지 않는 개인용 모드라 승인 모드와 같은 짧은 예산이 맞지 않는다. - --trust일 때만 기본값 96, 승인 모드는 24 유지. --max-model-turns가 항상 우선한다. - 96 x 10 tick = 960으로 MAX_TICKS(1,024) 안에 든다는 것을 컴파일 시점에 검사한다. - rename 재실행 2회: 1회는 164초에 완료(테스트 47개 통과, 남은 참조 3개), 1회는 정상 제안 70개 뒤 capability_unavailable 3연속 거절로 멈췄다(별도 과제). Co-Authored-By: Claude Opus 5.5 --- README.md | 2 +- crates/xgen-cli/src/main.rs | 26 ++++++++++++--- docs/adr/0059-trust-mode.md | 3 +- docs/adr/0062-trusted-turn-budget.md | 48 ++++++++++++++++++++++++++++ docs/development/interactive-repl.md | 2 ++ 5 files changed, 75 insertions(+), 6 deletions(-) create mode 100644 docs/adr/0062-trusted-turn-budget.md diff --git a/README.md b/README.md index 69a1195..9f3da8b 100644 --- a/README.md +++ b/README.md @@ -68,7 +68,7 @@ xgen model check --compatibility # 상세 durable progress 로그가 필요할 때 xgen --debug -# 요청 하나가 쓸 수 있는 model turn 수를 바꿀 때 (기본 24) +# 요청 하나가 쓸 수 있는 model turn 수를 바꿀 때 (기본 24, --trust면 96) xgen --max-model-turns 48 ``` diff --git a/crates/xgen-cli/src/main.rs b/crates/xgen-cli/src/main.rs index 8dcb0c1..2b6f1a7 100644 --- a/crates/xgen-cli/src/main.rs +++ b/crates/xgen-cli/src/main.rs @@ -42,14 +42,14 @@ struct Cli { /// Show durable progress events instead of the interactive Thinking display. #[arg(long)] debug: bool, - /// Model turns each interactive goal may use before it stops without an answer. + /// Model turns each interactive goal may use before it stops without an answer + /// [default: 24, or 96 with --trust]. #[arg( long, value_name = "TURNS", - default_value_t = REPL_MODEL_TURNS, value_parser = clap::value_parser!(u32).range(1..=i64::from(xgen_cli::MAX_HOST_MODEL_TURNS)) )] - max_model_turns: u32, + max_model_turns: Option, /// Start the interactive session with model/read/write/execute allowed, asking nothing. #[arg(long)] trust: bool, @@ -387,7 +387,12 @@ fn main() -> ExitCode { } match cli.command { Some(Command::Tools { command }) => tools::run(command), - None => interactive_command(cli.debug, cli.max_model_turns, cli.trust), + None => interactive_command( + cli.debug, + cli.max_model_turns + .unwrap_or_else(|| default_repl_model_turns(cli.trust)), + cli.trust, + ), Some(Command::Licenses) => print_licenses(), Some(Command::Protocol { command: ProtocolCommand::Check, @@ -508,10 +513,23 @@ fn executable_catalog(named: Vec, include_path: bool) -> Vec { // The bare workspace budget (8 turns) ends a read-edit-test task before it can answer. // 24 turns is the budget the project evals already use for Node.js and Python work. const REPL_MODEL_TURNS: u32 = 24; +// Trust mode (ADR-0062) is the personal mode where nobody approves each step, so a goal like a +// rename across 17 files should not stop at 24 turns. 96 turns keep a foreground invocation +// inside MAX_TICKS (1_024) at ten ticks per turn. +const TRUSTED_REPL_MODEL_TURNS: u32 = 96; +const _: () = assert!(TRUSTED_REPL_MODEL_TURNS * REPL_TICKS_PER_MODEL_TURN <= xgen_cli::MAX_TICKS); // Ticks only bound one foreground invocation; the manifest budget bounds the Run. Ten // per turn covers plan, admission, effect and verification with room for recovery. const REPL_TICKS_PER_MODEL_TURN: u32 = 10; +const fn default_repl_model_turns(trust: bool) -> u32 { + if trust { + TRUSTED_REPL_MODEL_TURNS + } else { + REPL_MODEL_TURNS + } +} + const fn repl_max_ticks(max_model_turns: u32) -> u32 { let ticks = max_model_turns.saturating_mul(REPL_TICKS_PER_MODEL_TURN); if ticks > xgen_cli::MAX_TICKS { diff --git a/docs/adr/0059-trust-mode.md b/docs/adr/0059-trust-mode.md index db142ea..420a959 100644 --- a/docs/adr/0059-trust-mode.md +++ b/docs/adr/0059-trust-mode.md @@ -26,7 +26,8 @@ session에서 승인은 각각 3회였다. 매번 `/permissions KIND allow`를 바뀌지 않는 것: - journal, Receipt 검증, 끝난 뒤 `Changes` 표시(ADR-0057), Ctrl+C, `/resume`. -- 실행 파일 catalog. 이 옵션은 이미 catalog에 있는 것의 승인만 생략한다. +- 실행 파일 catalog. 이 옵션은 이미 catalog에 있는 것의 승인만 생략한다. (이후 ADR-0060이 shell을, + ADR-0062가 더 큰 기본 turn 예산을 신뢰 모드에 더했다.) - Core의 action 단위 authorization. 각 effect는 실행 직전에 기존 검증을 거친다. - 비대화형 `xgen run`/`resume`의 승인 플래그. diff --git a/docs/adr/0062-trusted-turn-budget.md b/docs/adr/0062-trusted-turn-budget.md new file mode 100644 index 0000000..bb2293f --- /dev/null +++ b/docs/adr/0062-trusted-turn-budget.md @@ -0,0 +1,48 @@ +# ADR-0062: 신뢰 모드의 기본 turn 예산 + +- 상태: Accepted +- 기준일: 2026-10-26 +- 변경 분류: 범용 REPL 기본값. 특정 작업·도구·업무 규칙 없음. +- 기존 경계: ADR-0059(신뢰 모드), ADR-0061(거절된 응답 재시도) +- protocol·SQLite schema·journal 변경: 없음. 예산은 지금처럼 Run manifest에 기록된다. + +## 문제 + +REPL goal 하나는 기본 24 model turn을 쓴다. 승인을 묻는 기본 모드에서는 사람이 단계마다 보고 있으므로 +짧은 예산이 비용과 폭주를 막는다. 신뢰 모드(ADR-0059)는 사람이 단계마다 보지 않는 개인용 모드라 같은 +예산이 일을 끝내기 전에 멈추는 원인이 됐다. + +Claude Code 비교 실험(devhub-social 사본, deepseek flash, `--trust`)에서: + +- rename 작업(참조 137개, 17개 파일): 거절 재시도(ADR-0061)를 넣은 뒤 2회 모두 정상 제안 24개를 + 처리하고 `model_turn_budget_exhausted`로 멈췄다. 참조 86개가 남았다. +- 저장소 상태 조회 작업(`~/projects/app` 아래 저장소 24개): 2회 모두 예산을 다 쓰고 답하지 못했다. + +두 작업은 서로 다른 종류(편집, 조회)인데 모두 24 turn 안에 끝나지 않았다. 반면 버그 수정, 기능 추가, +후속 대화, 새 스크립트 작업은 24 turn 안에 끝났다. + +## 결정 + +1. `xgen --trust`의 goal당 기본 model turn을 96으로 한다. 기본 모드는 24 그대로다. +2. `--max-model-turns N`을 주면 모드와 관계없이 그 값이 우선한다. +3. 96은 foreground 호출의 tick 상한(`MAX_TICKS` 1,024, turn당 10 tick) 안에 들어가는 값이다. 이 관계는 + 컴파일 시점에 검사한다. +4. 나머지 예산(model call, planned step, tool call)은 지금처럼 turn 수에서 2:1:1로 정해진다. context + 상한(512 KiB)은 바꾸지 않는다. + +## 대안 + +- **기본 예산을 모든 모드에서 올리기:** 승인 모드의 비용 상한까지 바뀐다. 필요성을 보인 것은 신뢰 모드뿐이다. +- **예산이 끝난 Run을 `/resume`으로 연장:** manifest의 예산을 바꾸는 계약 변경이라 이번 범위에 넣지 않았다. +- **예산 제한 없음:** 같은 실수를 반복하는 모델이 끝없이 call을 쓴다. 상한은 남긴다. + +## 검증 + +- `xgen --help`가 `[default: 24, or 96 with --trust]`를 보인다. +- rename 작업을 새 binary로 2회 실행: + - 1회는 164초에 완료했다. 테스트 47개가 통과했고 참조 137개 중 3개가 남았다(call 61개, 거절 7개 + 재시도 후 진행). + - 1회는 215초 동안 정상 제안 70개를 처리한 뒤 존재하지 않는 capability를 3번 연속 요청해 + `proposal_rejected.capability_unavailable`로 멈췄다. 예산이 아닌 다른 문제다. 거절 이유를 다음 + context에 넣지 않아 같은 요청이 반복된 것으로 보이며 후속 과제로 남긴다. +- 저장소 상태 조회 작업은 workspace 밖 경로 안내 변경과 함께 다시 잰다. diff --git a/docs/development/interactive-repl.md b/docs/development/interactive-repl.md index 92cdc9c..12c6f7e 100644 --- a/docs/development/interactive-repl.md +++ b/docs/development/interactive-repl.md @@ -31,6 +31,8 @@ Session 허용은 파일에 저장하지 않고 process가 끝나면 사라진 신뢰 모드는 사용자의 shell(`SHELL`이 bash·zsh·sh면 그것, 아니면 PATH의 bash→zsh→sh, Windows는 pwsh→powershell)도 catalog에 넣는다([ADR-0060](../adr/0060-trusted-shell-executable.md)). 모델은 이것으로 파이프와 catalog에 없는 명령을 실행한다. +신뢰 모드의 goal당 model turn 기본값은 24가 아니라 96이다([ADR-0062](../adr/0062-trusted-turn-budget.md)). +`--max-model-turns`를 주면 그 값이 우선한다. ```text xgen> 프로젝트 구조를 보고 테스트 실패를 수정해줘.