Repository navigation
feat: S07 Server 실행 조율 통합 (1.74~1.87) — merge 보류 - #241
Merged
Merged
Conversation
- 과거 V0~V32 migration을 V1__product_baseline.sql 하나로 교체 (빈 DB 기준, baseline-on-migrate 해제) - chat_messages를 Note에 직접 연결(UUID)하고 ChatSession/thread ID/구형 AI stream·embedding 경로 제거 - ai_runs·ai_run_events·run_asset_dependencies·turn_attachments·verified_solutions·request usage ledger 추가 - request unique·Note별 Active Run partial unique·event seq/dedup unique·보상 최대 1회·stale/deadline 인덱스 - 불변 snapshot·run 상태 전이·append-only event·insert-only solution revision을 trigger로 강제 - Server/Brain role 경계 provisioning SQL(운영자 적용, Flyway 미실행) - local/test ddl-auto를 validate로 통일 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- 테스트마다 새 database를 만들어 Flyway baseline·재현 seed·Spring context(validate) 검증 - unique/partial unique(동시 접수 경합 포함)·FK/소유 경계·cascade·rollback·불변성·인덱스 사용 검사 - proovy_server ↔ brain_* role 접근 거부 검사 - CI는 DB 테스트 미구성 시 실패(PROOVY_REQUIRE_DB_TESTS) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- B1: 할당형 ID 엔티티(AiRun·ChatMessage·TurnAttachment·RunAssetDependency·VerifiedSolution· RequestUsageCharge·RequestUsageCompensation)에 AssignedIdEntity(Persistable) 적용. 새 인스턴스 save는 persist로 가서 중복 ID가 DataIntegrityViolationException으로 드러난다. - B2: NULL이면 통과하던 CHECK 수정 (USER user_input, COMPLETED assistant 본문, turn attachment media, clarification 짝, failure code/class 짝) - R1: 차감 row를 run의 (run_id, request_id, user_id)에 composite FK로 묶음 (ON DELETE SET NULL (run_id)) - R3: ai_run_events·usage ledger 직접 DELETE 거부 (상위 cascade만 허용) - R4: claims coverage는 문자열 direct|supporting만 허용 - R9: event seq는 last_event_seq로 배정된 값만, attempt는 run attempt 이하만 insert 허용 - R7/R8/R10: TODO·README·repository 계약 주석 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
[Feat] 신규 제품 DB baseline과 Note 중심 실행 모델 [1.74]
- RequestUsageService: chargeRequest / compensate / settle(Terminal) — 모두 MANDATORY로 호출자 transaction에 참여하고 독립 선commit이 없다. 잔액 row FOR UPDATE → ledger 순서로 잠근다. - 보상 복구 분배는 restored_* = charged_* (1.74 R2 인계). - UsageCompensationPolicy: disposition·failure_class·취소 시점/원인별 결정표. - 잔액 row가 없으면 REQUIRES_NEW 대신 같은 transaction에서 ON CONFLICT DO NOTHING으로 생성. - 차감/보상을 credit_history에 버킷별 SPEND/EARN으로 같은 transaction에서 기록. - 브라우저 임의 차감 POST /api/credits/use와 구형 기능별 비용표(/costs, /estimate, CreditCostService, useCredit/calculateCost)를 제거 (ADR 0015). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- proovy-brain 303a9e4의 browser-run-v1 fixture(+terminal-v2 browser schema)를 검증된 사본으로 복사하고 PIN.json(commit·consumer_version·manifest sha256)과 sha256 일치 테스트를 추가 (D9, token 없음) - com.proovy.domain.run.contract: 요청·상태·취소·대화 조회·frame DTO, 요청 판정기(RUN4001/4002), canonical JSON 요청 fingerprint, cursor 판정(RUN4003/4004), 공개 상태 투영, 계약 상수 - ErrorCode RUN4001~RUN4291, ApiResponse.failure(code, result) 추가형 변경 - 계약 DTO를 OpenAPI component schema로 등록(경로 없음, SwaggerConfig 변경 없음) - 소비 검사: 요청 valid/invalid·fingerprint·cursor·stream S1~S7·응답 왕복·오류 envelope·판정표를 Java로 재현하고 JSON Schema 2020-12(networknt, testImplementation)로 교차 검증 - 초안 문서는 인계용 안내(docs/contracts/browser-run-v1.md)로 대체 Closes #214 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- B1: 일일 리셋 스케줄러는 잔액 row를 FOR UPDATE로 읽고 리셋한다. 잠그지 않는 조회 (/balance·/history·회원 정보)는 CreditBalanceSnapshot으로 리셋값을 계산만 하고 row에 쓰지 않는다. - R2: 잠금 경로(lockAndRefresh)는 잠근 뒤 entityManager.refresh로 다시 읽어, 같은 tx에 먼저 로드된 stale 인스턴스로 차감하지 않는다. getOrCreateBalanceForUpdate도 같은 경로(같은 tx 생성)를 쓴다. - R4: 기간 요약에서 LLM_QUERY_COMPENSATION(EARN)을 적립이 아니라 지출 상계로 집계한다. - R5: 네이티브 초기 잔액 INSERT의 created/updated는 auditing과 같은 JVM 기본 시계를 쓴다. - 회귀 테스트: 리셋 스케줄러·잔액 조회를 잠금 보유 중인 차감과 겹쳐 charged 합 = 잔액 감소량, 먼저 로드된 balance가 있어도 두 차감이 모두 반영됨. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
[1.77] 요청별 사용량 선차감과 멱등 보상 정책
- OpenAPI component schema를 springdoc 설정 버전(기본 3.1)의 ModelConverters로 만들고, 직렬화된 3.1/3.0 문서에서 type·enum을 검사 - RunStatus·ConversationMessage·BrowserRunFrame 생성자에서 시각을 마이크로초로 절단 - AssistantMessageContent placeholder 주석 정정과 placeholder() factory, validator 값 집합을 enum에서 파생 - 반영하지 않은 권고(page 경계·cancelable 파생·wire 값 중복·판정표 production 재실행)는 인계 문서 후속 메모로 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…worktree-task-1.75
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
feat: 브라우저 run API 계약 browser-run-v1 pin·Java DTO 소비 검사·OpenAPI (#214)
- internal-run-v1 fixture(internal-run-fixtures-v2, Brain 303a9e4)를 검증된 mirror로 pin - com.proovy.domain.run.brain: snake_case wire DTO·Python과 같은 fingerprint·판정표·전용 mapper - com.proovy.global.infra.brain: bounded WebClient client(stream/status/cancel/cleanup), id-token(고정 audience)·shared-token 단일 인증, BrainFailureKind 오류 분류 - 공통 설정은 추가형: build.gradle google-auth 명시, application.yaml proovy.brain.* Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- BrainFailureKind.isSafeToResend()(연결 실패·capacity·429·credential), 429 → CAPACITY - credential 발급은 request-timeout으로 따로 제한, stream idle·응답 timeout은 exchange에만 - mapError 미분류 예외를 TRANSPORT_LOST로 감싸고 message·cause 버림 - deadline 이후 grace 안 전송(저장 terminal 회수) 의도를 문서·테스트로 고정 - withAssetAccess null = 유지, 필수 배열 JSON null 거부, deadline µs 절단 - AssetMime·HistoryRole과 1.75 enum 값 집합 일치 테스트, 후속 메모(Brain fingerprint 케이스·credential 비용) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
[Feat] Java Brain client·canonical fingerprint와 서비스 인증 [1.76]
- RunSnapshotFactory: ConversationRunRequest → InternalRunRequest. COMPLETED run 단위 공개 history를 Brain과 같은 추정으로 24,000 tokens 안에서 최신부터 고정하고, 남은 범위의 Verified Solution(status·revises)· Turn Attachment만 참조한다. Viewer Focus·corpus version·의존성·locale·budget·deadline을 접수 시점에 고정한다. - RunSnapshotCodec/Restorer: request_snapshot은 control·자격증명을 뺀 wire 문서다. 복원은 run 행의 attempt· fence·누적 usage와 이번 전달 access만 붙이고 fingerprint·deadline·식별자를 저장값과 대조한다. - 자산 사실 포트(RunAssetFacts)와 S09 전 기본 구현, 설정(proovy.run.snapshot.*), 인계 문서. - 테스트: history 경계·참조 범위·secret 비영속·fingerprint fixture 27개 왕복, Postgres 저장·복원·거부. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- com.proovy.domain.run.event: RunEventStore(Activity·Server·terminal append, findAfter·lastSeq), SourceActivities(activity-v1 검사·browser payload 변환), RunEventSignals(commit 후 알림) - run row FOR UPDATE + last_event_seq RETURNING으로 seq 배정, (run_id, source_event_id) dedup, attempt·fence·상태·Activity 순서(S6) 판정. schema 변경 없음 - activity-v1 fixture pin(PIN-activity-v1.json, 303a9e4)과 mirror 검사, BrainContractMirrorTest를 PIN-*.json 일반화 - 실제 Postgres에서 dedup·동시 append·rollback·stale fence·terminal 경합·알림·browser-run-v1 stream 재현 검사 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- terminal-v2·response-v1·publication-v1 fixture를 303a9e4에서 pin(PIN-*.json, 파일 sha256) - domain.run.terminal: Brain terminal-v2 구조 규칙(SafeMarkdown·page/block·배지·summary·artifact·disposition· source catalog·provenance)과 Server scope 규칙(run fence·dependency·user/Note·ACTIVE·version·page_count, 기존 solution 참조·정정 대상) 수락/거부 - 검증된 저장 입력: canonical response_pages·source snapshot·plain text·content hash·Verified Solution insert· 실패 입력·1.82 재확인 항목 - BrainContractMirrorTest가 PIN-*.json 소유 경로를 목록 밖 파일에서 제외(추가형) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- 결정 1(사용자): history 상한을 Brain bound_history와 같은 soft 상한으로 바꾼다. 최신 메시지 하나는 24,000을 넘어도 통째로 담고(그 답의 verified_solution_refs 유지), 나머지는 합 ≤ 24,000. wire 메시지당 50,000자는 hard. - R3: 정정 대상 Brain ID가 범위 안 다른 solution과 겹치면 revises만 싣지 않는다. - R4: 최신 100 turn 밖에 turn이 더 있으면 truncated=true. - R5: history 정렬을 run 생성 순(idx_ai_runs_note_created)으로. - R8: sha256은 HashUtils 재사용, 중복 kept 필터 제거, claims JSON parse 실패 로그. - 인계 문서: R2 Brain ID 전제, R6(1.79 Note 잠금·의존성 경합), R7(1.83 viewer URL·grant), 1.81 clarification COMPLETED, R9 이관처. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- 차단 1: native last_event_seq 증가 뒤 같은 영속성 context의 AiRun을 refresh해 옛 seq 되쓰기(monotonic trigger rollback)를 막고 Activity·JPA 접수 흐름 재현 Postgres 테스트 추가 - 차단 2: terminal source_event_id도 128자 초과 시 sha256 키로 저장, 형식 검사, 기존 키 재사용은 명시 오류 - 차단 3: RunEventSignals 구독 추가를 compute 원자 연산으로, 마지막 해제와의 경합 테스트 추가 - 권고: sha256: prefix 원래 ID 거부(키 공간 분리), inOrder 첫·마지막 row만 조회, kind orElseThrow를 계약 위반으로, 모든 경로 시각 µs 정규화, converter 재사용·미사용 메서드 제거, CATALOG↔사본 양방향 검사, BrainContractMirrorTest manifest 필수 유지(manifest 없는 pin은 명시 목록) - 인계 문서: AiRun refresh 계약, 1.76 failure-kind 처리는 1.83 소유, CANCELING 예외 문구 정정 인계 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
feat: 실행 입력·history·참조·정책의 불변 snapshot [1.78]
…worktree-task-1.81
…worktree-task-1.80
…RL 범위 (#219) - R1: enum·Literal은 strip하지 않고 원문 비교(Brain parity), 공백 enum probe 추가 - R2: S3 SigV2·X-Amz-Security-Token 흔적도 거부, javadoc 범위 정정 - R3: page_count 없는 PDF dependency는 ScopedAsset.of에서 거부 - R6: 저장 claim coverage·claim_id 손상은 IllegalStateException - R5·R7·R4: superseded 재표현 허용 정책, 순환 검사 범위, CR·content_version 철자 후속을 문서화 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
[Feat] fence 기반 Activity 수락과 영속 이벤트 seq/dedup [1.80]
…rorTest PIN 루프 일원화 (#219) - r181 B1/R8: 1.80의 PIN-*.json 루프와 MANIFESTLESS_PINS(명시 목록만 manifest null, 나머지 필수)를 유지하고 1.81 pin을 그 규칙에 맞췄다(PIN-response-v1·PIN-publication-v1에 "manifest": null, 목록에 추가) - TerminalContractMirrorTest: manifest 없는 pin은 명시적 null을 요구 - README: activity-v1·terminal-v2 절 병합 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
feat: terminal 공개 구조·출처 scope와 solution 수락 검증 [1.81]
- RunAdmissionService/Transaction: browser-run-v1 판정 순서(replay → RUN4092 → RUN4041 → RUN4221 → RUN4091 → RUN4291 → RUN4021)로 판정하고 Note·메시지·PENDING run·의존성·차감·binding·run.created를 한 transaction에 저장. unique 경합·lock 실패는 같은 body로 새 transaction 재시도 - V2 run_request_bindings: requestId → run, browser 요청 fingerprint 고정 - asset 단건·일괄 삭제: Note 잠금 후 run 의존 이력이 있으면 ASSET4092 - admission 판정표 fixture를 실제 Postgres에서 production 서비스로 검사, 동시성·rollback 테스트 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…DATE·content_version 재검사 (#220) - R1: 일괄 asset 삭제의 GCS 호출을 afterCommit으로 옮겨 Note 잠금 중 네트워크 대기 제거, 일괄 ASSET4092 테스트 - R2·R3: 접수 재시도를 원인 사슬 SQLState 23505·40001·40P01·55P03·08xxx로 한정(번역 안 된 PersistenceException 포함) - R4: Note·잔액 잠금 뒤 접수 시각을 읽는다 - R5: Note 잠금을 소유자 조건 FOR NO KEY UPDATE로(접수·삭제 guard) - R6: 의존성 재검사에서 content_version도 비교 - R7·R8·R9: 자동 제목 공백을 strip 집합으로 접기, Retry-After nanos 올림, requestId 사용 여부 EXISTS 조회 - 사용자 결정(Note 한도 우회 S14·ASSET4092 임시 수용·제목 담당 미정)과 1.75/S09 후속 메모를 run-admission.md에 기록 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
[Feat] 원자적 요청 접수·Note 생성과 중복/Active Run 방어 [1.79]
) - RunTerminalService: Brain terminal(stream·저장 회수)·Server 실패·deadline 만료를 한 transaction에서 확정 (Note→run→asset→solution→잔액 잠금, 조건부 전환 + last_event_seq 배정, 1.81 수락·재확인, 1.80 event, 1.77 보상) - 중복(DUPLICATE)·바뀐 결과(CONFLICTING_DUPLICATE)·STALE_FENCE·CANCELING·DEADLINE_PASSED·SCOPE_NOT_READY 판정 - 정정은 새 solution row + 대상 조건부 SUPERSEDED, source snapshot은 message JSON에만 - TerminalReplay: run.completed 최소 요약 + canonical message로 browser payload 복원 - V3: chat_messages.verification_summary, ai_runs.terminal_source_sha256 - SourceActivities.storedSourceEventId 공개(terminal 재전달 키 조회) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…empt·fence)·Server 실패 재시도 DUPLICATE·outer flush·deadline grace 문서 (#221) - B1: brainContentVersion = asset content sha256 (pin 303a9e4 Brain 구현, 사용자 결정). sha256 없는 asset은 SCOPE_NOT_READY - R1/R4: V3에 ai_runs.terminal_source_event_id 추가, DUPLICATE는 같은 source + {type, attempt, fence_token, payload} digest일 때만 - R2: 같은 code의 Server 실패(failByServer는 attempt·fence까지, expireDeadline은 timeout)는 DUPLICATE - R3: 바깥 transaction 참여 시 진입 때 EntityManager flush - R5: TerminalSettlement runStatus javadoc 정정, R6: 중복 참조 재확인 쿼리 제거·주석, R7: solution 참조 한 번 조회 - R8: V3 점유·후속 V4 명시 - 결정 2: internal-run-v1.md·BrainRunClient javadoc의 grace 서술 정정(문서만, 동작 변경 없음) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
[Feat] canonical 응답·solution·사용량의 terminal 원자적 확정 [1.82]
- BrowserRunController: POST /api/conversations(1.79 admit → seq 1부터), GET /api/ai-runs/{runId}/events
(Last-Event-ID header/lastEventId query, RUN4041→RUN4003→RUN4004), GET /api/ai-runs/{runId},
GET /api/conversations/{noteId}/messages. stream 전 거부는 Accept SSE여도 JSON.
- RunEventStream: 구독 먼저 → cursor 이후 DB catch-up → 신호마다 재조회 + 주기 catch-up(신호 유실 복구),
연결당 전송 하나·신호 병합(서버 queue 없음), heartbeat comment, 단절은 구독 해제만.
- RunFrameReader: run.completed를 canonical message로 hydration, available은 read-time.
대화 조회도 같은 함수(TerminalReplay.completedPayload)로 assistantResponse를 만든다.
- proovy.run.sse.* 설정, runSseScheduler(Executor 타입 bean 아님), SecurityConfig run SSE ASYNC dispatch 규칙.
- 테스트: RunEventStreamTest(단위 9), BrowserRunSsePostgresTest(실제 Postgres + 실제 HTTP SSE client 12).
- 문서: docs/contracts/browser-run-sse.md (wire·cursor 오류·구독 해제·인계).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- coordinator lease(V4 run_coordinator_leases) 보유자 하나만 PENDING run을 claim(SKIP LOCKED, attempt 0→1, 새 fence·lease) - 전역 슬롯 = min(로컬 semaphore, max − DB live lease 수), max ≤ Brain 인스턴스 × 인스턴스당 상한을 기동 시 검사 - worker는 transaction 없이 stream 소비, Activity는 RunEventStore, terminal은 RunTerminalService로 연결 - 같은 attempt·fence 재전달만(capacity·연결 실패 backoff, 단절은 status 수습), 횟수·deadline bounded - heartbeat·deadline sweep·runtime_cleanup_at 예약·종료 시 lease 만료, Micrometer 지표 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…종료 (#223) - R1: heartbeat도 drain과 같은 쓰기 소유권(draining)을 잡고, 전송 중이면 건너뛴다. 느린 연결은 pool thread 하나만 점유한다. 문서의 S14 한계(수신 멈춘 연결 threads개면 전체 전송 정지)를 정정. - R2: BrowserRunExceptionHandler 예상 밖 예외 → COMMON500 JSON(ERROR+stack), MVC 4xx는 상태 유지, 응답 commit 뒤는 기록만. - R3: 복원·조회 실패는 completeWithError + stack 로그(정상 종료로 보이지 않게). S08에 backoff 재접속 인계. - R4: start() 실패 시 close()로 구독·openStreams 되돌림. - R5: progress가 Note ACTIVE를 조인 — 삭제 중이면 열린 연결도 닫는다. 1.84 Note 삭제 cancel 흐름과의 관계 문서화. - R6: SseEmitterSink는 "already completed"만 단절(IOException)로 보고 나머지는 오류 경로로. - R7: SecurityConfig ASYNC 전역 전환은 후속 제안으로 문서화. R8: FAILED 상태는 run.failed 단건 조회, note_id 추가 조회는 메모. - 계약 후속(before/limit 의미·superseded 표시 필드)을 browser-run-v1 다음 consumer_version 인계로 문서화. - 테스트: 단위 +2(느린 연결 thread 하나·오류 종료), HTTP +2(Note DELETING 종료·stream 전 COMMON500 JSON). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
feat: POST/GET SSE durable replay·live 무유실 합류 [1.86]
…worktree-task-1.83
…ease 갱신 분리·sweep 격리·재전달 자격 재발급·일시 DB 오류 수습·종료 예산 (#222) - B1: worker pool 대기열을 semaphore가 상한을 지키는 LinkedBlockingQueue로, 거부 시 실패 대신 lease 만료(회수 대상) + 회귀 테스트 - R1: dispatch를 lock으로 직렬화 - R2: 전역 슬롯을 attempt>=1 비terminal run(lease 무관) 기준으로 계산 + 고아 run 슬롯 유지 테스트 - R3: coordinator lease 갱신 실패를 run heartbeat와 분리하고 leader=false - R4: deadline sweep run별 예외 격리 - R5: OBSOLETE lease 규칙 단일화와 1.84 인계 문구 정정 - R6: 재전달마다 RunAssetAccessProvider로 grant·read URL 재발급 - R7: stream 중 일시 DB 오류는 bounded status 수습으로 합류, LOCAL_ERROR 수용 범위 문서화 - R8: 종료 대기를 단일 예산(기본 8s)으로, coordinator lease를 worker 대기 전에 해제 - used_* 문구 정합(run-snapshot-v1·run-coordinator), 테스트 각본을 접수 전에 걸어 경합 제거 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…Exception 수습 (#222) - N1: dispatch가 lock을 기다리며 control thread(heartbeat·sweep)를 묶지 않도록 tryLock 실패 시 재실행만 표시하고 잡은 쪽이 한 번 더 돈다 - N2: transaction 시작 시 연결 획득 실패(CannotCreateTransactionException)도 bounded backoff 뒤 status 수습으로 합류, spy 테스트 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
[Feat] 브라우저 독립 coordinator와 전역 실행 슬롯 [1.83]
… 소실 실패 (#225) - RunCoordinator.recoverStale: leader가 lease 만료 RUNNING|RETRYING run(CANCELING 제외, deadline 전, 로컬 worker 없음)을 같은 attempt·fence로 인수하고 로컬 permit을 잡아 RECOVER worker를 띄운다 - RunExecution RECOVER/FINAL_CHECK: status 먼저 — 저장 terminal은 1.82 settle(StoredTerminal)로 새 실행 없이 확정, 같은 epoch executing은 같은 요청으로 OBSERVE, absent는 Brain 시작 증거가 없을 때만 첫 START - absent + Brain 시작 증거(받은 frame·저장된 attempt source event) = 실행 소실 → 재전송 없이 failByServer(PROVIDER_ERROR) (1.83 worker status 수습에도 적용) - 재전달 예산은 retry_count부터 이어서 세고, 인수 횟수는 V5 recovery_count(단조)로 누적 — max-recoveries 초과 시 status 한 번만 확인 후 실패 수습 - 관측: recoveries{result}·recoveries.finished{result}·execution_lost, payload 없는 로그 - 테스트: RunRecoveryPostgresTest(재시작 전후 terminal·실행 중·실행 소실·미시작·status 유실·조회 한도·인수 한도· 동시 인수·CANCELING·deadline·살아 있는 로컬 worker), 1.83 테스트 조정 - docs/contracts/run-coordinator.md stale 회수 절·1.87/S13 인계 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…meout 뒤 CANCELED, 반복 요청 제한 검증 (#224) - POST /api/ai-runs/{runId}/cancel (cancel/cases.json 판정 순서: body RUN4001 → 접근 RUN4041 → 상태) - RunCancelStore: Note → run 잠금, 조건부 PENDING→CANCELED(+보상)·RUNNING|RETRYING→CANCELING(+run.canceling) - RunCancelFinalizer: Brain cancel ack state로 정리 확인, absent는 lease 만료 뒤, cleanup-timeout 안전 확정, reserveRuntimeCleanup·RunCoordinator.release (coordinator 패키지 미수정, schema 변경 없음) - 실제 Postgres·HTTP·BrainRunClient·coordinator 테스트, docs/contracts/run-cancel.md Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… 실행 run 후보 제외, 거부 시 회수 종료 기록, 일시 DB 재전달 횟수 저장 (#225) - FINAL_CHECK: status 조회 1회, 다른 epoch executing도 실패, canceling·run.canceled는 1.84 소유로 두고 FINAL_CANCEL_PENDING 관측 - takeOver 뒤 coordinator가 멈추는 중이면 lease 즉시 만료·permit 반환(ABANDONED_STOPPING) - findStale에서 이 인스턴스의 실행 중 run을 SQL로 제외 - RECOVER launch 거부 시 recoveries.finished{STOPPED} - 호출자 없는 3인자 RunExecution 생성자 삭제 - 일시 DB 오류 재전달도 markRetrying으로 retry_count에 남김(DB 불가 시 메모리만) - 문서: 재부착의 재전달 예산 소모 결정, 반복 인수 규칙, 슬롯 over-commit 인계, 일시 DB 예외 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
feat: 내부 단절·stale 실행과 deadline의 bounded 결과 회수 [1.85]
…worktree-task-1.84
…복 요청 추가 상한 후속 태스크 명시 (#224) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…패 행 backoff, timeout 경과 시 Brain 미호출·남은 시간 상한, DB 시각 timeout, stop 시 inFlight 정리 (#224) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
[Feat] run 명시적 취소·CANCELED 확정·상태별 사용량과 반복 요청 제한 검증 [1.84]
- RunPathEndToEndPostgresTest: 빈 baseline에서 HTTP 접수→coordinator→BrainRunClient(loopback 가짜) →terminal transaction→POST SSE→GET replay 바이트 동일, 순사용량·row 수, 구형 테이블·route 없음 - LegacyExecutionPathGuardTest: ChatSession·thread ID·구형 stream/client·토큰 누적·기능별 사후 차감· 브라우저 임의 차감·구형 내부 token 진입점·Brain 경로의 사용자 identity 읽기 회귀 금지 - 구형 agent → Server 내부 API token filter(X-Internal-Token, /internal/**)와 internal.api 설정 제거 (대상 controller는 1.74에서 제거됨) - support/http: 실제 HTTP 브라우저 run client·SSE reader (단계 4와 공용) Refs #226 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- ServerBrainIntegrationTest: 같은 DB의 빈 제품 baseline(proovy_server)·Brain schema(bootstrap)·role 경계 위에서 실제 HTTP 접수→coordinator→BrainRunClient→proovy-brain testkit(7b8608e) 내부 API·graph→terminal transaction→SSE. 중복·같은 Note 충돌, 결과 분류별 순사용량, 브라우저 재접속·내부 SSE 유실·저장 후 유실, Server 재시작, Brain 저장 전 SIGKILL, RUNNING/PENDING 취소, deadline 경합·Brain fake clock, fingerprint·fixture sha256 일치, scope 밖 출처·변조 envelope(scripted) 거부, JWT 비전달·서비스 인증 거부·브라우저 비노출·역할별 DB 격리 - BrainTestkit: supervisor·control client. 미구성 시 "NOT EXECUTED" 이유로 skip, PROOVY_REQUIRE_BRAIN_IT=true면 실패 - scripts/brain-integration/run-local.sh: 격리 Postgres→testkit supervisor→Gradle→정리 (Server CI는 skip, 사용자 결정) - CI: real-Brain 연동 미실행을 warning으로 드러내는 step - docs/contracts/brain-integration.md: Verification 대응표, fake·scripted·미검증 구분, S08 외부 계약·S13 복구 경계 인계 - README: 연동 테스트 실행·CI skip 명시 Closes #226 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- 차단: run-local.sh가 `test --rerun`으로 항상 실제 실행하고, 이번 실행의 TEST-com.proovy.integration.brain.*.xml이 tests>0·skipped/failures/errors=0이 아니면 실패한다(UP-TO-DATE·skip을 통과로 위장하지 않음) - 정리: supervisor를 setsid로 띄워 /brain/stop 뒤 프로세스 그룹 전체 종료, 남은 child도 정리, readiness 루프 60s 초과 시 실패 - 테스트: coordinator 켠 두 클래스에 @DirtiesContext, hold 해제·SSE close를 finally로, 요청별 차감액으로 잔액 단언, 저장 전 소실 provider_error 단언, coordinator 재시작은 같은 JVM stop/start로 명시 - SseClient: reader 판독 오류를 test thread로 전달, 여러 data 줄을 SSE 규칙대로 결합 - JwtAuthenticationFilter의 /internal JWT 우회 제거(대상 endpoint 없음) + 회귀 검사, internal-run-v1.md 잔여 서술 정정 Refs #226 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
test: Server·Brain 로컬 실행 연동과 S07 경합 인수 [1.87]
5 of 6 tasks
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.
📌 관련 이슈
1.87). 이슈 [Feat] 신규 제품 DB baseline과 Note 중심 실행 모델 [1.74] #213#226은 통합 브랜치 merge 시 모두 닫았다.🏷️ PR 타입
📝 작업 내용
통합 브랜치
feat/s07-run-coordination(시작 92a7aae = 현재 dev)에 merge된 태스크 PR:각 PR은 별도 리뷰 세션 리뷰(차단 지적 0으로 종료)와 CI 통과 뒤 merge했다.
📸 스크린샷
scripts/brain-integration/run-local.sh로 Server 9173b1b + Brain 7b8608e에서 18/18, skip 0(리뷰어 재현 포함). 결과는 [Feat] Server·Brain 로컬 실행 연동과 S07 경합 인수 [1.87] #226·test: Server·Brain 로컬 실행 연동과 S07 경합 인수 [1.87] #240 참고.✅ 체크리스트
docs/contracts/*)📎 기타 참고사항
배포 전 필수 (merge 전에 결정 필요)
V1__product_baseline로 대체했다. 기존 prod DB에서는 baseline이 기동을 거부한다. 새 빈 DB 준비·연결 전환(또는 데이터 이전 계획)이 먼저다.deploy.yml은 이번 작업에서 바꾸지 않았다. 아직 미사용인PROOVY_AI_HOST·INTERNAL_API_TOKENsecret 주입이 남아 있다(S14 정리).후속(S07 범위 밖)
used_*사용량 카운터: Brain 사용량 반환 경로가 없어 별도 결정 필요before/limit, superseded("정정된 풀이") 표시 필드, U+0000 → RUN4001, viewerFocus.page 상한@VersionNULL asset 삭제가 조용히 무시됨(S13)🤖 Generated with Claude Code