docs(api): Gemini reasoning 정규화 계획을 추가한다

This commit is contained in:
toki 2026-08-14 05:46:28 +09:00
parent ebf1357481
commit 165cdde2d6
2 changed files with 289 additions and 0 deletions

View file

@ -0,0 +1,103 @@
<!-- task=gemini_reasoning_compat plan=0 tag=API -->
# Code Review Reference - API
> **[IMPLEMENTING AGENT — READ FIRST]** Implement the plan through the existing normalization boundary, run verification, fill every implementation-owned section, leave active files in place, and report ready for review. Do not append a verdict, archive, write `complete.log`, or ask the user.
## Overview
date=2026-08-14
task=gemini_reasoning_compat, plan=0, tag=API
## For the Review Agent
> **[REVIEW AGENT ONLY]** Compare source with the plan, rerun fresh verification, and finalize only through the code-review skill.
## Implementation Item Completion
| Item | Status |
|---|---|
| API-1 Correct Gemini profile levels | [ ] |
| API-2 Prove bridge inheritance and synchronize contracts | [ ] |
## Implementation Checklist
- [ ] Implement API-1 the Gemini portable effort levels inside the existing profile normalization.
- [ ] Implement API-2 focused config and Responses-bridge regression tests plus contract/spec synchronization.
- [ ] Run fresh local verification and the exact-source dev Gemini reasoning cycles.
- [ ] Fill implementation-owned sections in CODE_REVIEW-*-G??.md with actual implementation notes and verification output.
## Review-Only Checklist
> **[REVIEW AGENT ONLY]** Implementers must not modify this section.
- [ ] Append PASS/WARN/FAIL and routing signals.
- [ ] Verify dimensions and finding classifications.
- [ ] Run and record fresh verification.
- [ ] Record reviewer evidence, root cause, one selected fix, targets, and acceptance commands for Required/Suggested findings.
- [ ] Archive review as `code_review_cloud_G04_0.log` and plan as `plan_local_G04_0.log`.
- [ ] Verify managed `.gitignore`; on PASS write `complete.log` and archive the task directory, otherwise write only the required next state.
## Deviations from Plan
_Replace with actual deviations or `None`._
## Key Design Decisions
_Record actual decisions._
## Reviewer Checkpoints
- Only Gemini profile levels changed; generic normalization remains the owner.
- low/medium/high are exact, xhigh/max fall to high, none fails closed.
- No direct-handler normalizer, model/caller branch, extension, `thinking_level`, or `thinking_budget` synthesis exists.
- Responses bridge inherits the mapping through `selectProviderOperation`.
- Gemini-native thinking config and thought signatures remain unchanged.
## Verification Results
### Profile Mapping
```bash
go test -count=1 ./packages/go/config -run 'TestGeminiProtocolProfileReasoningEffortScale|TestProtocolProfileEffortNormalizationOverlayAndValidation'
```
_Paste actual stdout/stderr._
### Responses Bridge
```bash
go test -count=1 ./apps/edge/internal/openai -run 'TestResponsesProtocolProfileGeminiEffortFallsBackToHigh|TestResponsesProtocolProfileBridgesToGeminiChat'
```
_Paste actual stdout/stderr._
### Full Verification
```bash
gofmt -w packages/go/config/protocol_profile.go packages/go/config/protocol_profile_test.go apps/edge/internal/openai/responses_protocol_profile_test.go
go test -count=1 ./packages/go/config
go test -count=1 ./apps/edge/internal/openai
git diff --check
```
_Paste actual stdout/stderr._
### Contract and Dev Evidence
```bash
rg --sort path -n 'Gemini.*reasoning_effort|xhigh|max.*high' agent-contract/inner/edge-config-runtime-refresh.md agent-contract/outer/openai-compatible-api.md agent-spec/input/openai-compatible-surface.md
```
_Paste document output and sanitized exact-source dev low/high/max cycle evidence. Never paste credentials or provider payloads._
## Section Ownership
| Section | Owner |
|---|---|
| Fixed header/overview/instructions/checkpoints | Fixed |
| Item Completion/Implementation Checklist | Implementer checks only |
| Review-Only Checklist | Reviewer |
| Deviations/Key Decisions | Implementer |
| Verification Results | Implementer, then reviewer |
| Code Review Result | Reviewer appends |

View file

@ -0,0 +1,186 @@
<!-- task=gemini_reasoning_compat plan=0 tag=API -->
# Gemini Reasoning Normalization Plan
## For the Implementing Agent
기존 operation-scoped `normalization.effort` 경계만 사용한다. 구현·검증 뒤 `CODE_REVIEW-cloud-G04.md`의 구현 담당 섹션에 실제 결과를 기록하고 active pair를 둔 채 review 준비 완료를 보고한다. verdict, archive, `complete.log`, 사용자 질문은 구현 담당 범위가 아니다.
## Background
Gemini profile은 이미 `normalization.effort` 방식으로 reasoning grade를 처리하지만 현재 levels가 IOP 전체 등급의 identity mapping이라 Gemini Chat의 portable 상한을 넘는 `xhigh|max`도 그대로 전달한다. 별도 adapter나 `thinking_level` 변환기를 만들지 않고 profile mapping만 교정해 기존 normalization 흐름이 올바른 provider value를 선택하게 한다.
## Analysis
### Files Read
- `packages/go/config/protocol_profile.go`
- `packages/go/config/protocol_profile_test.go`
- `apps/edge/internal/openai/provider_normalization.go`
- `apps/edge/internal/openai/responses_protocol_profile_test.go`
- `agent-contract/inner/edge-config-runtime-refresh.md`
- `agent-contract/outer/openai-compatible-api.md`
- `agent-spec/input/openai-compatible-surface.md`
- `agent-test/dev/rules.md`
- `agent-ops/rules/project/domain/platform-common/rules.md`
### SDD Criteria
not applicable. 기존 normalization profile의 작은 호환성 결함 수정이다.
### Verification Context
- 최신 `dev` 기준 `protocol_profile.go`의 Gemini Chat effort는 `identityEffortMapping(...)`이며 `none|low|medium|high|xhigh|max`를 모두 그대로 매핑한다.
- 공통 `MapReasoningEffort`는 exact level이 없으면 가장 가까운 명시적 하위 등급을 고르고 상향하지 않는다. 이 함수가 source of truth다.
- 진행 중인 `responses_provider_bridge``selectProviderOperation`에서 동일한 profile mapping을 사용하므로 변환 코드를 추가할 필요가 없다.
- Gemini 공식 OpenAI-compatible Chat은 `reasoning_effort`를 지원한다. `thinking_level`/`thinking_budget`을 함께 보내면 안 되므로 IOP가 native field를 합성하지 않는다.
- fresh test는 `-count=1`로 실행한다.
#### External Verification Preflight
- runner/workdir: `ssh toki@toki-labs.com`, `/Users/toki/agent-work/iop-dev`
- clean `dev`에서 `HEAD == origin/dev == approved implementation SHA`를 확인한다.
- exact source로 dev-runtime Edge/참여 Node를 rebuild/redeploy/restart하고 `18083/18084` listener와 binary identity를 확인한다.
- existing copied CA 및 SOPS/age-managed token을 사용하며 secret 원문은 evidence에 남기지 않는다.
- Gemini direct route에서 standard Responses caller의 `low`, `high`, `max` 한 cycle씩 확인한다. extension이나 `thinking_level` 우회는 사용하지 않는다.
### Test Coverage Gaps
| Behavior | Existing coverage | Gap |
|---|---|---|
| nearest-lower mapping | custom OpenAI profile | built-in Gemini mapping 없음 |
| Gemini tools + effort | profile은 `WithTools=true` | xhigh/max fallback 회귀 없음 |
| Responses→Gemini | 진행 중 bridge가 공통 selector 사용 | corrected mapping 상속 assertion 없음 |
### Symbol References
rename/remove 없음. `MapReasoningEffort``selectProviderOperation` call sites는 변경하지 않는다.
### Split Judgment
단일 plan이다. compact invariant는 “Gemini profile의 declared levels가 기존 공통 nearest-lower normalization을 통해 provider-supported grade만 반환한다”이다.
### Scope Rationale
- `provider_normalization.go`의 알고리즘과 handler/adapter에 새 정규화 경계를 추가하지 않는다.
- `thinking_level`, `thinking_budget`, model-name 분기, caller/agent 분기, extension 우회를 추가하지 않는다.
- Gemini-native `thinkingConfig`, response reasoning text, `thought_signature`는 변경하지 않는다.
- portable scale은 `low|medium|high`로 둔다. `xhigh|max`는 기존 규칙으로 `high`, `none`은 지원 mapping이 없어 fail closed한다.
### Final Routing
- evaluation_mode: `first-pass`; finalizer=`finalize-task-policy.sh`, mode=`pair`
- build/review closures: all true
- build scores: scope=1,state=0,blast=1,evidence=1,verification=1; route=`local/G04`, basis=`local-fit`
- review scores: scope=1,state=0,blast=1,evidence=1,verification=1; route=`cloud/G04`, basis=`official-review`
- large_indivisible_context=false
- positive loop risks: `boundary_contract`, `variant_product` (2); risk boundary=false
- recovery signals: review_rework_count=0, evidence_integrity_failure=false; capability gap 없음
- canonical files: `PLAN-local-G04.md`, `CODE_REVIEW-cloud-G04.md`
## Implementation Checklist
- [ ] Implement API-1 the Gemini portable effort levels inside the existing profile normalization.
- [ ] Implement API-2 focused config and Responses-bridge regression tests plus contract/spec synchronization.
- [ ] Run fresh local verification and the exact-source dev Gemini reasoning cycles.
- [ ] Fill implementation-owned sections in CODE_REVIEW-*-G??.md with actual implementation notes and verification output.
### [API-1] Correct Gemini profile levels
#### Problem
```go
// packages/go/config/protocol_profile.go:251
string(OperationChatCompletions): identityEffortMapping(ProtocolEffortWireGeminiChat, true, true),
```
Identity mapping declares unsupported upper/disable grades instead of letting the common normalizer choose a supported lower grade or reject.
#### Solution
Replace only the Gemini Chat levels with explicit `low`, `medium`, `high`. Retain `Wire=gemini_openai_chat`, `WithTools=true`, and the existing token-budget fact. Do not change `MapReasoningEffort`.
```go
// after: existing MapReasoningEffort supplies xhigh/max -> high
ProtocolEffortMappingConf{
Wire: ProtocolEffortWireGeminiChat,
WithTools: true,
TokenBudget: true,
Levels: map[string]string{"low":"low", "medium":"medium", "high":"high"},
}
```
#### Modified Files and Checklist
- [ ] `packages/go/config/protocol_profile.go`: Gemini Chat levels only.
#### Test Strategy
Write `TestGeminiProtocolProfileReasoningEffortScale` in `protocol_profile_test.go`: low/medium/high exact, xhigh/max→high, none unsupported, with-tools true, and `base: gemini` inheritance.
#### Verification
```bash
go test -count=1 ./packages/go/config -run 'TestGeminiProtocolProfileReasoningEffortScale|TestProtocolProfileEffortNormalizationOverlayAndValidation'
```
Expected: all cases pass without changing generic normalization.
### [API-2] Prove bridge inheritance and synchronize contracts
#### Problem
No regression test proves that Responses ingress selecting Gemini Chat consumes the corrected profile mapping; documentation does not state Gemini's portable IOP grade behavior.
#### Solution
After `responses_provider_bridge` is present, add a focused assertion that a Responses request with effort `max` selects Gemini Chat and sends `reasoning_effort=high`. Do not add conversion logic in the test's production path. Document that direct native provider fields remain passthrough, while profile-normalized bridges use low/medium/high with nearest-lower fallback and no synthetic native thinking field.
#### Modified Files and Checklist
- [ ] `packages/go/config/protocol_profile_test.go`: profile mapping coverage.
- [ ] `apps/edge/internal/openai/responses_protocol_profile_test.go`: bridge inheritance coverage only.
- [ ] `agent-contract/inner/edge-config-runtime-refresh.md`: Gemini operation-scoped levels.
- [ ] `agent-contract/outer/openai-compatible-api.md`: Responses→Gemini reasoning semantics.
- [ ] `agent-spec/input/openai-compatible-surface.md`: living implementation state/change history.
#### Test Strategy
Write `TestResponsesProtocolProfileGeminiEffortFallsBackToHigh`. Assert selected operation is Chat, provider body contains `reasoning_effort=high`, tools still admit the candidate, and no `thinking_level`/`thinking_budget` is synthesized.
#### Verification
```bash
go test -count=1 ./apps/edge/internal/openai -run 'TestResponsesProtocolProfileGeminiEffortFallsBackToHigh'
rg --sort path -n 'Gemini.*reasoning_effort|xhigh|max.*high' agent-contract/inner/edge-config-runtime-refresh.md agent-contract/outer/openai-compatible-api.md agent-spec/input/openai-compatible-surface.md
```
Expected: bridge test and documents agree with the profile mapping.
## Modified Files Summary
| File | Items |
|---|---|
| `packages/go/config/protocol_profile.go` | API-1 |
| `packages/go/config/protocol_profile_test.go` | API-1, API-2 |
| `apps/edge/internal/openai/responses_protocol_profile_test.go` | API-2 |
| `agent-contract/inner/edge-config-runtime-refresh.md` | API-2 |
| `agent-contract/outer/openai-compatible-api.md` | API-2 |
| `agent-spec/input/openai-compatible-surface.md` | API-2 |
| `agent-task/gemini_reasoning_compat/CODE_REVIEW-cloud-G04.md` | API-1, API-2 evidence |
## Final Verification
```bash
gofmt -w packages/go/config/protocol_profile.go packages/go/config/protocol_profile_test.go apps/edge/internal/openai/responses_protocol_profile_test.go
go test -count=1 ./packages/go/config
go test -count=1 ./apps/edge/internal/openai -run 'TestResponsesProtocolProfileGeminiEffortFallsBackToHigh|TestResponsesProtocolProfileBridgesToGeminiChat'
go test -count=1 ./apps/edge/internal/openai
git diff --check
```
Expected: fresh tests pass and the implementation diff contains no handler/adapter reasoning normalizer or native thinking field synthesis.
After an approved exact commit reaches `dev`, perform the recorded dev preflight/rebuild and Gemini Responses `low`, `high`, `max` cycles. Expected: all complete, `max` uses provider effort `high`, and no extension workaround is active.
After completing all code changes, fill implementation-owned sections in `CODE_REVIEW-*-G??.md`.