Skip to content

feat: PACKET_ASK_EFFORT 로 기본 effort 를 두되 출처를 함께 기록한다 - #57

Open
ictechgy wants to merge 3 commits into
mainfrom
feature/effort-env-default
Open

feat: PACKET_ASK_EFFORT 로 기본 effort 를 두되 출처를 함께 기록한다#57
ictechgy wants to merge 3 commits into
mainfrom
feature/effort-env-default

Conversation

@ictechgy

@ictechgy ictechgy commented Sep 2, 2026

Copy link
Copy Markdown
Owner

--effort 를 매번 치지 않아도 되게 한다.

왜 사용자 TOML 이 아닌가

[providers.glm] effort = "max"거절 목록 두 군데를 어긴다.

  1. _assert_safe_id 가 내장 id 를 이름으로 쓰는 것 자체를 거절한다 (provider_builtin_override)
  2. 사용자 overlay 는 paste 별명뿐이다 (mode != "paste" 거절, 금지 키 15개)

env 는 기존 8개와 같은 결이고 그 규칙과 무관하다.

무엇

$ PACKET_ASK_EFFORT=high packet-ask review --provider glm --preview ...
... timeout=1800s(auto,applies) ... effort=high(env) ...

$ PACKET_ASK_EFFORT=max packet-ask review --provider glm --preview --effort low ...
... effort=low(explicit) ...

$ PACKET_ASK_EFFORT=ultra packet-ask review --provider glm --preview ...
PACKET_ASK_EFFORT must be one of low, medium, high, xhigh, max.   # exit 2

우선순위는 플래그 > env > 벤더 기본값. --timeoutexplicit > auto 와 같다.

effort_sourceenv 값이 하나 더 붙는다. #56 에서 값과 출처를 나눠 둔 덕에
additive 다. GLM 이 그 리뷰에서 제안한 설계가 바로 다음 배치를 싸게 만들었다.

조용한 기본값이 되지 않게

출처 기록 effort_sourceexplicit/env/vendor-default. 이게 없으면 "왜 이 실행이 751초 걸렸나" 를 못 푼다
오타 거절 argparse choices플래그만 본다. env 를 따로 안 막으면 오타가 조용히 벤더 기본값으로 떨어진다. exit 2
빈 값 "설정하지 않음". 거절하면 unset 하기가 어려워진다
우회로 차단 프로바이더 검증이 해석된 값을 본다. 플래그 경로만 막으면 env 가 우회로가 된다
자식 격리 minimal_child_env 화이트리스트라 벤더가 이 변수를 자기 설정으로 읽지 못한다. 테스트로 고정

거절 메시지가 --effort 를 지목하고 있었는데 env 로 설정한 경우엔 부정확해서
둘 다 덮게 고쳤다.

검증

uv run pytest      507 passed   (기존 501 + 신규 6)
uv build           wheel + sdist
smoke ×2           ok / ok
변이 결과
env 값 검증 제거 test_invalid_env_effort_is_rejected_not_ignored 실패
우선순위 뒤집기 test_flag_wins_over_env 외 5건 실패
프로바이더 검증이 해석 전 플래그를 봄 test_env_effort_is_rejected_for_providers_that_cannot_take_it 실패

같이 고친 표면

docs/AGENTS.md 의 환경 변수 표대로 전부 갱신했다 — .env.example,
SECURITY 영/한 변수 표, README 영/한, 번들 SKILL.md, docs/design.md 44.

알아 둘 것

SECURITY 영/한 변수 표가 이미 갈라져 있었다. 한국어 쪽에 PACKET_ASK_LEDGER
PACKET_ASK_LANG 이 없다. 이번 변수는 양쪽에 넣었고 기존 누락은 범위 밖이라
손대지 않았다. 별도로 정리할 대상이다.

🤖 Generated with Claude Code

ictechgy and others added 3 commits September 2, 2026 23:42
매번 `--effort` 를 치지 않아도 되게 한다. 벤더별 기본값을 사용자 TOML 로
받는 길은 열지 않는다. 그쪽은 거절 목록 두 군데를 어긴다 — 내장 id 를
이름으로 쓰는 것 자체를 `_assert_safe_id` 가 막고, 사용자 overlay 는 paste
별명뿐이다. env 는 기존 8개와 같은 결이고 그 규칙과 무관하다.

우선순위는 플래그 > env > 벤더 기본값이다. `--timeout` 의 explicit > auto 와
같다.

`effort_source` 에 `env` 값이 하나 더 붙는다. #56 에서 값과 출처를 나눠 둔
덕에 additive 다. 이 기록이 없으면 "왜 이 실행이 751초 걸렸나" 를 나중에 풀
수 없고, 그것이 조용한 기본값과 아닌 것의 차이다.

env 값은 별도로 검증한다. argparse `choices` 는 플래그만 본다. 여기서 안
막으면 오타가 조용히 벤더 기본값으로 떨어진다. `PACKET_ASK_LEDGER` 가 잘못된
경로일 때 벤더를 안 띄우는 것과 같은 결이어야 한다. exit 2 로 거절한다.
다만 빈 문자열은 "설정하지 않음" 으로 본다. 거절하면 unset 하기가 어려워진다.

프로바이더 검증이 해석된 값을 본다. 플래그 경로만 막으면 env 가 우회로가
된다. paste 와 kimi 는 env 로 들어와도 거절한다.

거절 메시지가 `--effort` 를 지목하고 있었는데 env 로 설정한 경우엔 부정확하다.
둘 다 덮게 고친다.

자식 환경에 새지 않는 것도 고정한다. `minimal_child_env` 가 화이트리스트라
기본적으로 안 새지만, 벤더가 이 변수를 자기 설정으로 읽는 일이 없어야 한다.

뮤테이션 3건으로 확인했다. env 값 검증을 지우면, 우선순위를 뒤집으면,
프로바이더 검증이 해석 전 플래그를 보면 각각 해당 테스트가 깨진다.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ag1VwUtyEUgBckaLaLiZLG
동작 커밋과 분리한다. 44 는 새 번호를 붙이지 않고 기존 항목에 이어 적는다.
같은 노브의 기본값 경로이지 별개 불변식이 아니다.

docs/AGENTS.md 의 표대로 환경 변수 추가에 필요한 곳을 전부 고친다.
`.env.example`, SECURITY 영/한 변수 표, README 영/한, 번들 SKILL.md 다.

"기본값과 조용한 기본값의 차이는 출처 기록" 이라는 근거를 문서에도 적는다.
이 기능을 나중에 손대는 사람이 `effort_source` 를 군더더기로 볼 수 있다.

알아 둘 것: SECURITY 영/한 변수 표가 이미 갈라져 있었다. 한국어 쪽에
`PACKET_ASK_LEDGER` 와 `PACKET_ASK_LANG` 이 없다. 이번 변수는 양쪽에 넣었고
기존 누락은 범위 밖이라 손대지 않았다. 별도로 정리할 대상이다.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ag1VwUtyEUgBckaLaLiZLG
blocker 0, major 1, minor 6, 확인 필요 5. 전부 실측했다.

M1 이 옳았다. 새 테스트 6개가 전부 `--preview` 를 쓰는데 preview 는
`_finish_task` 앞에서 끝난다. 그래서 호출부에서 effort 인자를 빼도 **507개가
전부 통과했다.** `_finish_task` 의 파라미터가 기본값 None 이라 조용히
사라진다. 이 배치가 싸우는 "조용한 기본값" 이 정확히 그 모양이었다. 런처가
받은 effort 를 캡처하는 non-preview 테스트를 넣는다.

직전 리뷰의 M1 과 같은 부류인데 방향이 반대다. 그때는 순수 함수만 보고 결로를
놓쳤고, 이번엔 결로의 다른 끝을 안 봤다. 세 번 연속이라 tests/AGENTS.md 의
"판별력 있는 단언" 절이 실제로 필요한 이유다.

확인 필요 A 가 가장 날카로웠다. `EFFORT_LEVELS` 와 `EFFORT_TIMEOUT_SECONDS` 는
지금 집합이 같지만 그것을 강제하는 것이 없었다. 레벨만 늘리면
`.get(effort or "", 0)` 이 0 을 돌려 그 레벨의 deadline 만 조용히 크기 tier 로
떨어진다. 집합 동일성을 고정한다.

m1/m2 반영. `build_receipt` 의 `effort_source` 기본값을 없애고 required 로
바꾼다. effort 는 넘기고 출처를 빠뜨리면 explicit 인데 vendor-default 로 거짓
기록된다. 출처를 정확히 남기는 것이 이 배치의 존재 이유이므로 미전달을
시끄럽게 실패시킨다. 값과 출처가 어긋난 조합도 거절한다.

m5 반영. 메시지가 레벨 목록을 하드코딩한다. 레벨이 바뀌면 메시지가 거짓말을
한다. 메시지를 고정 문장으로 두는 대신 모든 레벨이 들어 있는지 테스트로 묶는다.

m4 반영. paste + 잘못된 env 에서 `effort_env_invalid` 가 먼저 나오는 순서를
테스트로 고정한다. 둘 다 거절이라 결과는 같지만, 고정하지 않으면 가드를 옮길
때 문구가 조용히 바뀐다. 0.5.1 에서 같은 이유로 순서를 고정한 적이 있다.

m3 반영. paste 거부 테스트가 stderr 만 봤다. stdout 비움도 단언한다.

확인 필요 C 반영. env 격리 테스트가 `minimal_child_env` 만 봤다. 런처가 그것을
쓰는지는 확인하지 못한다. 런처의 실제 호출 지점인 `isolated_env` 까지 내려간다.

m6 과 확인 필요 E 는 문서화한다. env 는 모든 task 실행에 걸리고 review 와
research 가 같은 경로다. 설정한 채로 paste 를 부르면 거절된다. 플래그와
일관되지만 변수는 셸 프로필에 박아두고 잊기 쉽다. README 양쪽과 설계 44 에
적는다.

확인 필요 B 는 해소됐다. `_finish_task` 호출처와 `args.effort` 읽는 곳이 각각
하나뿐이다.

뮤테이션 3건으로 확인했다. `_finish_task` 호출에서 effort 누락, tier dict 에서
레벨 제거, receipt 불변식 제거에서 각각 해당 테스트가 깨진다.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ag1VwUtyEUgBckaLaLiZLG
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant