Repository navigation
리뷰 확정 43건 수정: API 계약·프록시, 엔진 복구, 클라이언트 재전송 규칙, handover 판정, 웹 실행 분리 - #11
Merged
Merged
Conversation
…장 한도와 신뢰 IP 헤더, 의존성 고정 - POST /exports가 인수인계 결과와 100점 도달 실행을 거부하던 422 수정 - 벤더 호출을 httpx.AsyncClient로 전환해 이벤트 루프 차단 제거, 읽기 한도는 출력 상한 비례 - 응답 읽기 시간 초과·단절은 504(재시도 금지), 연결 단계 실패는 502 - exports IP별 속도 제한, DB 총량 상한(507), HARNEST_TRUSTED_IP_HEADER, CORS 기본값 localhost - requirements 버전 고정, CI api 잡, 배포는 테스트 통과 후
- 저장 실패를 CheckpointSaveError로 감싸고 라운드 오류 경로에서는 원래 오류를 우선 - 원샷 생성 뒤 채점·저장이 실패하면 같은 핸들의 재시작에서 원샷을 재사용 - IndexedDB 열기 실패가 영구 캐시되지 않게, keys/deleteExcept 추가 - 라운드 도중 일시정지·동시 start·구버전 정규화·저장 실패 테스트 추가
- Gemini·Claude·OpenRouter·Ollama 비스트리밍 응답도 절단·실패 신호를 오류로 - 스트리밍 절대 한도 제거, 바이트 도착 기준 유휴 600초 - 출력 상한 바닥 low 4096 / medium 8192 / high 16384 - 스트림이 열린 뒤 실패·빈 스트림·공유 프록시 504는 재전송 금지, 429·5xx만 비스트리밍 백오프 - Ollama relaxed 재시도는 think 제거, Claude fable·mythos 갈래 인식, 첨부 크기 사전 검사
- 차단 키를 거듭 고르면 예외 대신 허용 전략으로 대체 - 안정성 판정을 case_answerability 기준·100/(2×케이스 수) 단계로 유도 - 프롬프트에 document/response 태그, 채점자 지시 주입 프로브 추가 - 전략 선택 프롬프트는 자료 발췌·질문만, 불변 블록을 앞에 배치 - criteria/gates 라벨 숫자 포맷을 로케일과 무관하게
- 화면을 떠나도 루프와 홀드아웃 채점이 이어지고 같은 runId에 엔진이 겹치지 않음 - 검사관 배터리 진행·오류를 Provider에 다이제스트 결속, 억제 상태에 점검 시작 버튼 - Web Locks 잠금과 스냅샷 판 번호 CAS로 읽기 전용 탭 처리 - 판정 모델·빌더 어휘 복원, 공유 키 연결 테스트를 실제 모델로, 허용 모델 목록 제한 - 케이스 용도 배지를 compile 결과에서 표시, ErrorNote·이탈 경고·합계 산식 조정 항
There was a problem hiding this comment.
🔵 Needs a closer look
엔진·웹·API·계약/문서까지 광범위한 변경이 한 PR에 포함되어 회귀 위험이 커 최종 인간 리뷰가 필요합니다.
Pull request overview
이 PR은 계약·엔진·템플릿(handover)·모델 클라이언트·웹 UI·선택형 API·문서/테스트 전반에서 리뷰로 확정된 수정 사항을 반영해, 실행/복구/프록시/재전송/사전점검/멀티탭 동작을 정책(SPEC)과 일치시키는 정합성 작업입니다.
Changes:
- handover 템플릿의 전략 차단 처리, 프롬프트 신뢰 경계(/), examiner 배터리(안정성 산식·지시 주입 프로브) 강화 및 테스트 확장
- loop-engine의 체크포인트 저장 실패 구분(CheckpointSaveError)·라운드0 재시도 최적화·IndexedDB/스토어 유틸 확장, 웹의 실행 오케스트레이션/멀티탭 읽기 전용/오류 표시 컴포넌트 정비
- 선택형 API/프록시/내보내기 거부 사유 표기 개선, 배포/CI 파이프라인 및 문서(SPEC/README/ROADMAP/PHILOSOPHY/docs) 최신화
File summaries
| File | Description |
|---|---|
| templates/handover/src/runtime.ts | 차단 전략 오류 타입 도입, 차단 반복 시 결정적 대체 로직 추가 |
| templates/handover/src/prompts.ts | 전략 프롬프트 비용 절감(자료 발췌/질문만), / 태그 및 배치 정비 |
| templates/handover/src/probes.ts | 지시 주입 프로브 추가 및 설명 보강 |
| templates/handover/src/index.ts | 케이스 id 규약 함수화, 숫자 표기 로케일 비의존화(formatCount), 케이스 id 부여 규칙 수정 |
| templates/handover/src/handover.test.ts | 케이스 id/formatCount/차단 전략 폴백/프롬프트 태그/자료 발췌 등 테스트 추가 |
| templates/handover/src/examiner.ts | 안정성 임계 산식(stabilityStep) 및 judgeStability 도입, 프로브 3종으로 확장 |
| templates/handover/src/examiner.test.ts | 안정성 산식·지시 주입 프로브·호출 수 등 배터리 테스트 확장 |
| SPEC.md | 공유 키 프록시 예외(§7.1), 재전송 규칙(§8), 실행/멀티탭/라운드0 복구 등 계약 갱신 |
| ROADMAP.md | 공유 키 경로의 남은 과제 및 라운드0 초안 영속 보관(보류) 정리 |
| README.md | 사용자 흐름/사전 점검/서버 경유 예외/재전송·타임아웃 등 설명 최신화 |
| PHILOSOPHY.md | 신뢰 경계 및 공유 키 예외를 포함한 원칙 문구 최신화 |
| packages/loop-engine/src/stores.ts | Memory/IndexedDB 체크포인트 스토어에 keys/deleteExcept 추가, IndexedDB open 실패 캐시 방지 |
| packages/loop-engine/src/index.ts | CheckpointStore 선택 메서드 확장, LoopHandle에 isActive/hasPendingInitial 추가, CheckpointSaveError export |
| packages/loop-engine/src/engine.ts | CheckpointSaveError 도입, 라운드0 pendingInitial 재사용, commit 저장 실패 처리 보강 |
| fly.toml | 신뢰 IP 헤더 설정 및 /health 헬스체크 추가 |
| docs/user-scenario.md | 실행 화면 이탈/멀티탭/공유 키 경유 등 시나리오 문구 업데이트 |
| docs/terminology-inventory.md | 선택형 백엔드/최종 확인용 배지 등 용어/표현 업데이트 |
| docs/current-loop-structure.md | runController 중심 구조, 라운드0 재시도, 저장 실패, 멀티탭/정리 스윕 등 설명 보강 |
| apps/web/src/templates.tsx | 템플릿 등록소에 checkCards/caseIdAt 확장 연결(handover에 제공) |
| apps/web/src/styles.flow.css | 케이스 용도(최종 확인/중간 점검) 스타일 반영 |
| apps/web/src/styles.css | error-note/readonly-banner 스타일 및 aria-invalid 시각 피드백 추가 |
| apps/web/src/pages/ResultsPage.tsx | ErrorNote로 오류 영역 일원화, 라운드0 홀드아웃 표기 보정 |
| apps/web/src/pages/BuilderPage.tsx | 읽기 전용 탭에서 모델 호출 차단 및 ErrorNote 사용 |
| apps/web/src/pages/ApprovalPage.tsx | 배터리 진행 상태를 프로젝트에 귀속, 카드 문구를 템플릿에서 주입, 읽기 전용 차단 강화 |
| apps/web/src/lib/useSyncedState.ts | Provider 상태 동기 ref+안정 세터 유틸 추가 |
| apps/web/src/lib/useSyncedState.test.ts | 세터 정체성/동기 ref 동작 회귀 테스트 추가 |
| apps/web/src/lib/useBlueprint.ts | 위저드 라이브 블루프린트 컴파일 훅 분리 |
| apps/web/src/lib/templateVoice.ts | 제출 시 유지해야 하는 어휘 키(VOICE_KEYS) 및 pickVoice 추가 |
| apps/web/src/lib/templateVoice.test.ts | pickVoice 동작 테스트 추가 |
| apps/web/src/lib/runNarration.ts | 활동 콘솔 서술(채점 산식/채택 사유) 추가 |
| apps/web/src/lib/runNarration.test.ts | 산식/표기 테스트 추가 |
| apps/web/src/lib/readOnlyCheckpointStore.ts | 읽기 전용 탭의 체크포인트 save 차단 래퍼 추가 |
| apps/web/src/lib/projectLock.ts | Web Locks 기반 프로젝트 단일 탭 소유권 획득 로직 추가 |
| apps/web/src/lib/projectLock.test.ts | 잠금/미지원/실패 케이스 테스트 추가 |
| apps/web/src/lib/project-snapshot.ts | 스냅샷 revision CAS 및 SnapshotConflictError, running 체크포인트 투영 규칙 추가 |
| apps/web/src/lib/project-snapshot.test.ts | revision CAS/투영 규칙 테스트 추가 |
| apps/web/src/lib/project-export.ts | 홀드아웃 채점 시점 판단(holdoutPhaseToScore) 추가 |
| apps/web/src/lib/project-export.test.ts | holdoutPhaseToScore 규칙 테스트 추가 |
| apps/web/src/lib/modelChoice.ts | pickModel에 preferred 지원 및 Claude 갈래 필터 확장 |
| apps/web/src/lib/modelChoice.test.ts | preferred/pickModel 동작 테스트 확장 |
| apps/web/src/lib/judgeSelection.ts | 저장된 compiled에서 저지 선택 복원 유틸 추가 |
| apps/web/src/lib/judgeSelection.test.ts | judgeSelectionOf 테스트 추가 |
| apps/web/src/lib/examinerCards.ts | 승인 화면 검사 카드 기본 문구 + 템플릿 덮어쓰기 유틸 추가 |
| apps/web/src/lib/examinerCards.test.ts | 문구 덮어쓰기 및 handover 주입 검증 테스트 추가 |
| apps/web/src/lib/examinerBattery.ts | 배터리 진행/오류의 다이제스트 결속 상태 모델 추가 |
| apps/web/src/lib/examinerBattery.test.ts | 오류 결속 규칙 테스트 추가 |
| apps/web/src/lib/caseSplit.ts | compile 결과 holdoutPolicy를 입력 순서로 되돌려 용도 배지 생성 |
| apps/web/src/lib/caseSplit.test.ts | 용도 배지 규칙 테스트 추가 |
| apps/web/src/lib/attachText.ts | PDF/DOCX 바이트 상한 및 한국어 오류 래핑/텍스트 조기 거부 추가 |
| apps/web/src/lib/attachText.test.ts | 추출기 오류 안내/상한 동작 테스트 추가 |
| apps/web/src/lib/api.ts | /exports 거부 detail 발췌/상태별 코드(429/507) 구분 및 메시지 개선 |
| apps/web/src/lib/api.test.ts | 거부 detail/HTML 발췌/plainTextExcerpt 테스트 추가 |
| apps/web/src/components/WizardCaseList.tsx | 질문 용도 배지(개선/중간 점검/최종 확인) 표시로 UI 개선 |
| apps/web/src/components/WizardCaseList.test.tsx | 용도 배지 렌더링 테스트 추가 |
| apps/web/src/components/WizardBlueprint.tsx | WizardBlueprint가 useBlueprint 결과를 입력으로 받도록 단순화 |
| apps/web/src/components/ModelPicker.tsx | id/aria-invalid/aria-describedby 지원으로 검증 UX/접근성 보강 |
| apps/web/src/components/IntroTour.tsx | 사전 점검 설명(지시 주입 포함) 업데이트 |
| apps/web/src/components/ErrorNote.tsx | 항상 마운트되는 alert 영역 컴포넌트 추가 |
| apps/web/src/App.tsx | 읽기 전용 탭 배너 표시 추가 |
| apps/api/requirements.txt | API 의존성 버전 고정 |
| apps/api/README.md | 공유 키 프록시/저장 제한/상태 코드 의미 및 운영 변수 문서화 강화 |
| AGENTS.md | 공유 키 프록시/멀티탭/재전송/차단 전략 등 가드레일 최신화 |
| .github/workflows/deploy-api-fly.yml | API 배포 전 test_api.py 선행 실행 추가 |
| .github/workflows/ci.yml | CI에 API 테스트 잡 추가 |
Review details
- Files reviewed: 73/74 changed files
- Comments generated: 4
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Comment on lines
+24
to
+32
| const text = message ?? ""; | ||
| return ( | ||
| <Tag | ||
| id={id} | ||
| role="alert" | ||
| aria-live={live} | ||
| className={`error error-note${className ? " " + className : ""}`} | ||
| // 비어 있을 때는 여백도 주지 않는다 — 빈 alert 영역이 자리를 차지하면 안 된다 | ||
| style={text ? style : undefined} |
Comment on lines
194
to
+197
| return `당신은 인수인계 문서 개선 실험의 전략을 선택합니다. | ||
| 후보 문서를 아직 작성하지 말고, 이번 회차에 사용할 수정 전략 하나만 결정하세요. | ||
| 최근 공개 실험에서 반복 실패한 전략은 다시 선택할 수 없습니다. | ||
| 아래 참고 자료는 앞부분 발췌와 섹션 제목이며, 공개 질문은 질문만 실었습니다 — 전문과 기대 답은 문서 생성 단계에서 봅니다. |
Comment on lines
+493
to
+504
| function fallbackStrategy(blocked: readonly string[], rejectedKey: string): ExperimentStrategy { | ||
| const strategy = | ||
| HANDOVER_STRATEGIES.find((candidate) => !blocked.includes(candidate.key)) ?? | ||
| HANDOVER_STRATEGIES[0]; | ||
| return { | ||
| key: strategy.key, | ||
| label: strategy.label, | ||
| summary: | ||
| `차단된 전략(${rejectedKey})을 거듭 선택해 기본 전략(${strategy.key})으로 진행 — ` + | ||
| strategy.description, | ||
| }; | ||
| } |
Comment on lines
+103
to
+107
| constructor(key: string) { | ||
| super(`반복 실패한 수정 전략(${key})은 다시 선택할 수 없습니다.`); | ||
| this.name = "BlockedStrategyError"; | ||
| this.key = key; | ||
| } |
Owner
Author
|
To use Codex here, create a Codex account and connect to github. |
- Claude stop_reason·OpenRouter finish_reason·Ollama done_reason을 허용 목록으로 판정한다 — model_context_window_exceeded·content_filter·error 등은 텍스트가 있어도 오류 - StreamPlan.done으로 벤더별 완료 신호(response.completed·finishReason STOP·message_stop· finish_reason stop·done true)를 추적하고, 없이 닫힌 스트림은 부분 산출물로 오류 처리(재전송 없음) - 직접(BYO) 비스트리밍 호출의 시간 초과는 fetch·본문 읽기 어느 단계든 즉시 던진다 — maxAttempts가 남아도 벤더가 받아들였을 수 있는 요청을 다시 보내지 않는다 - 공유 키 경로는 네트워크 단절도 재시도하지 않는다 — 서버가 받아 벤더에 쓴 뒤 edge가 끊은 경우와 구분할 수 없고 관리자 키가 과금된다
프록시는 벤더 응답을 다 받은 뒤에야 첫 바이트를 보내므로 edge 기본 60초가 먼저 연결을 끊었다 — 벤더 쪽 생성·과금은 완주하고 산출물만 잃는다. idle_timeout을 읽기 한도 최댓값(65,536토큰 × 30ms ≈ 1,966초)과 브라우저 여유(+60초)보다 큰 2,100초로 두고, 출력 상한을 올릴 때 함께 올려야 함을 적는다.
비보안 컨텍스트(http://)·구형 브라우저에서는 모든 탭이 소유자가 되어 같은 일시정지 실행을 동시에 재개할 수 있었다(체크포인트 저장소에는 판 번호 비교가 없다). 탭 ID와 만료 시각(15초)을 적고 되읽어 같은 순간의 경합을 가리며 5초마다 갱신한다. 갱신 중 다른 탭의 임대가 보이면 스냅샷 충돌과 같은 경로로 읽기 전용으로 물러나고, 탭을 떠날 때 자기 임대를 지운다. 저장소조차 없으면 종전대로 진행.
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.
요약
7개 관점(계약·엔진·handover·모델 클라이언트·웹 페이지·API·문서/테스트) 리뷰에서 확정된 43건과, 그 수정에 대한 세 차례 리뷰·보정에서 나온 후속 지적을 모두 반영했습니다. 커밋은 영역별 6개입니다.
API
POST /exports가 인수인계 결과(feedbackMode,strategy)와 100점 도달 실행(ceiling)을 422로 거부하던 문제 수정. 클라이언트는 서버detail을 사용자에게 보여줍니다.httpx.AsyncClient로 전환(이벤트 루프 차단 제거). 상류 읽기 한도는 출력 상한에 비례하며HARNEST_PROXY_TIMEOUT이 바닥값입니다.HARNEST_EXPORT_RATE_LIMIT), DB 총량 상한(HARNEST_DB_MAX_BYTES, 초과 시 507), 신뢰 IP 헤더(HARNEST_TRUSTED_IP_HEADER, fly.toml에 설정), CORS 코드 기본값은localhost:5173만.엔진
LoopHandle.isActive(),CheckpointSaveError(저장 실패 구분), 라운드 0에서 채점·저장이 실패하면 원샷 산출물 재사용,keys/deleteExcept로 고아 체크포인트 정리, IndexedDB 열기 실패 재시도.모델 클라이언트
think제거, Claude fable·mythos 갈래 인식, 첨부 파일 크기 사전 검사와 한국어 오류.handover
case_answerability기준,100/(2×케이스 수)단계로 유도(가드 허용오차와 같은 산식).document/response구분 태그, 채점자 지시 주입 프로브 추가.웹
runController로 분리해 화면을 떠나도 루프·홀드아웃 채점이 이어지고 같은 runId에 엔진이 겹치지 않습니다./config허용 모델 목록 제한, 케이스 용도 배지를 compile 결과에서 표시.ErrorNote(role=alert), 이탈 경고, 합계 산식에 조정 항 표시.문서
검증
npm run typechecknpx vitest runnpm run buildapps/apipython3 test_api.py배포 전 확인
apps/api/README.md에 정리돼 있습니다. CORS 기본값이 바뀌었지만 운영 출처는fly.toml이 이미 지정합니다.thinkingLevel: "MEDIUM"수용 여부, 공유 키 경로의 실제 동작.