<!-- task=m-provider-resource-admission-ownership-alignment/11+08,13,15_reconnect_candidate_recovery plan=0 tag=REFACTOR -->

# Code Review Reference - REFACTOR

> **[IMPLEMENTING AGENT — READ FIRST] Filling in this file is the mandatory final step of implementation.**
> The task is NOT complete until every implementation-owned section below is filled in.
> Complete the `구현 체크리스트`; the final checklist item is mandatory before saving.
> Fill every implementation-owned section, keep active files in place, then end the implementation execution. The filled review-without-verdict state plus agent completion is the `review-ready` signal; do not create a handoff file/message, invoke code-review, or switch to the review role in place.
> If implementation is blocked by a selected Milestone `구현 잠금 > 결정 필요` item, fill `사용자 리뷰 요청` with linked evidence, keep the active pair in place, and end the implementation execution; that file state is the same `review-ready` signal. Only the distinct review-agent instance decides whether to write `USER_REVIEW.md`. Environment/secret/service blockers, generic scope changes, repeated failures, and evidence gaps that a follow-up agent can close are normal follow-up issues, not user-review blockers by themselves.
> Do not ask the user directly, present choices in chat, call `request_user_input`, report review readiness, or wait for another user instruction. The runtime immediately assigns a distinct review-agent instance; a new turn, resume, compaction, or role change of this implementing agent is not distinct.
> Finalization (`코드리뷰 결과`, log rename, `complete.log`, archive moves, follow-up pair creation, `코드리뷰 전용 체크리스트`) is distinct-review-agent-only, even after compaction/resume. The implementing agent must never perform it.
> `USER_REVIEW.md` and `complete.log` are the only overall loop terminal states. `review-ready`, `implementation-ready`, a verdict, an archive, or a WARN/FAIL pair is internal transitional state and must not trigger a user-facing question or intermediate report.
> Follow the ownership table at the bottom of this file for which sections you own.

## 개요

date=2026-07-21
task=m-provider-resource-admission-ownership-alignment/11+08,13,15_reconnect_candidate_recovery, plan=0, tag=REFACTOR

## Roadmap Targets

- Milestone: `agent-roadmap/phase/operational-observability-provider-management/milestones/provider-resource-admission-ownership-alignment.md`
- Milestone link: [Milestone 문서](agent-roadmap/phase/operational-observability-provider-management/milestones/provider-resource-admission-ownership-alignment.md)
- Task ids:
  - `reconnect-candidate-recovery`: accepted reconnect가 기존 waiter candidate를 복구하고 즉시 pump
- Completion mode: check-on-pass

## 이 파일을 읽는 리뷰 에이전트에게

> **[HARD ACTOR BOUNDARY]** 리뷰 에이전트는 구현 에이전트와 별도 agent instance여야 한다. 새 turn·resume·compaction·역할 전환으로 같은 agent를 재사용할 수 없다. product source/test를 수정하거나 현재·후속 plan을 구현하거나 구현 에이전트 소유 섹션을 채우지 않는다. WARN/FAIL 후속 pair를 만든 뒤 review 실행을 종료하면 archived current pair와 fresh pair가 runtime의 `implementation-ready` 신호가 된다. 별도 handoff 파일·사용자 메시지를 만들지 않는다.
> **[FOLLOW-UP MANDATE]** 미해결 Required는 별도 후속 지시가 없어도 반드시 FAIL과 정확히 하나의 next state를 만든다. 기본 next state는 follow-up pair이고, 유효한 Milestone-lock gate만 그 pair 대신 `USER_REVIEW.md`를 만든다. 유효한 gate는 Required/FAIL로 분류한다. Suggested는 WARN follow-up을 만들고, Nit-only는 모든 차원이 Pass일 때만 PASS할 수 있다. reviewer는 후속 pair까지만 materialize하고 직접 구현하지 않는다.

> **[REVIEW AGENT ONLY]** 08, 13, 15 predecessor와 구현 출력을 대조한 뒤 `code_review_cloud_G08_0.log`, `plan_cloud_G08_0.log`로 rename한다. PASS에서만 `complete.log`와 task directory archive를 수행한다.

## 구현 항목별 완료 여부

| 항목 | 완료 여부 |
|------|---------|
| REFACTOR-1 Accepted-connect authoritative lifecycle hook | [x] |
| REFACTOR-2 Generation activation and immediate global pump | [x] |

## 구현 체크리스트

- [x] accepted current-owner registration만 `(node_id,generation)` connected lifecycle callback을 event fanout 전에 service로 전달한다.
- [x] queue resource가 configured provider identity를 새 generation available 상태로 복구하고 stale orphan marker를 안전하게 교체한다.
- [x] activation이 모든 pending provider-pool item을 live resolver로 재구성해 새 요청/config refresh/lease release 없이 global enqueue 순서로 즉시 pump한다.
- [x] full alternate candidate, reconnect candidate, stale/rejected connection, event fanout 포화와 race를 deterministic test로 검증한다.
- [x] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채우고 active pair를 유지한 채 구현 실행을 종료한다. 이 저장 상태가 runtime의 review-ready 신호이며 별도 handoff 파일·사용자 메시지를 만들지 않는다. 구현 에이전트는 code-review를 실행하거나 review 전용 작업을 수행하지 않는다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.

## 코드리뷰 전용 체크리스트

> **[REVIEW AGENT ONLY]** 이 체크리스트는 코드리뷰 에이전트만 사용한다. 구현 에이전트는 수정하거나 체크하지 않는다.

- [x] 08의 `agent-task/archive/2026/07/m-provider-resource-admission-ownership-alignment/08_disconnect_exclusion/complete.log`와 13/15의 matching active/archive `complete.log`에서 Roadmap Completion evidence를 확인한다.
- [x] accepted-only ordering, generation identity, live resolver rebuild와 global enqueue fairness를 실제 diff/test와 대조한다.
- [x] `코드리뷰 결과`에 `PASS`, `WARN`, `FAIL` 중 하나를 append하고 차원별 평가와 Required/Suggested/Nit를 일치시킨다.
- [x] active review를 `code_review_cloud_G08_0.log`, plan을 `plan_cloud_G08_0.log`로 rename한다.
- [x] `.gitignore` Agent-Ops block의 `agent-task/**/*.md`, `agent-task/**/*.log` unignore와 `agent-roadmap/current.md` ignore를 확인한다.
- [ ] PASS이면 complete-log template으로 `Roadmap Completion: reconnect-candidate-recovery`와 reconnect-only/race evidence를 기록하고 active `.md`를 남기지 않는다.
- [ ] PASS이면 task directory를 월별 archive로 이동하고 최종 `.log`에서 체크한다.
- [ ] PASS이면 runtime용 Milestone 완료 이벤트 메타데이터를 보고하고 roadmap/update-roadmap은 직접 호출하지 않는다.
- [ ] PASS split 이동 후 active parent에 sibling/file이 남아 있어 유지했는지 확인한다.
- [x] WARN/FAIL이고 user-review gate가 아니면 plan skill/fresh routing follow-up을 만들고 `complete.log`를 쓰지 않는다.
- [x] WARN/FAIL follow-up을 만든 뒤 review 실행을 종료한다. archived current pair와 fresh pair 및 reviewer 실행 종료가 runtime의 `implementation-ready` 신호다. 리뷰 에이전트는 후속 구현이나 별도 handoff artifact 생성을 수행하지 않으며 runtime이 별도 구현 에이전트 instance를 즉시 배정한다.
- [ ] USER_REVIEW이면 template으로 `USER_REVIEW.md`를 만들고 active pair와 `complete.log`를 남기지 않는다.
- [ ] USER_REVIEW의 해소 결정이 완료/PASS이면 문서를 해소 상태로 갱신하고 `complete.log` 작성 및 archive 이동을 수행한다.
- [ ] USER_REVIEW의 해소 결정이 새 구현을 요구하면 plan이 USER_REVIEW를 archive하고 fresh pair를 쓴 뒤 review 실행을 종료한다. 이 상태가 `implementation-ready`이며 runtime이 별도 구현-agent instance를 배정한다.

## 계획 대비 변경 사항

- 계획 그대로 REFACTOR-1 → REFACTOR-2 순서로 구현했다. 파일 write set은 계획 표와 동일하다.
- 계획의 REFACTOR-2 스니펫은 disconnect 경로(`model_queue_release.go:99-104,144-147`)의 `res.orphan=true`/`pumpAllLocked()`를 activation으로 "대체"하는 것처럼 보이나, 실제로는 disconnect 경로를 건드리지 않고 **역방향** connect 경로를 새로 추가했다. `resolveAndPumpAllLocked`는 predecessor 13이 이미 도입한 helper이므로 재사용했고, 계획이 미리 예고한 `activateNodeGenerationLocked` / `activateNode` 두 심볼을 신설해 `HandleNodeConnect`에서 호출한다. disconnect settlement 경로(`releaseNode`/`fenceNodeGenerationLocked`)는 08/13 계약이라 무변경이다.
- transport connect callback은 `bindDisconnectListener`의 handlerMu inline read 패턴과 대칭이 되도록 `notifyNodeConnected` helper 하나를 `connection_handlers.go`에 추가했다(server.go에는 field/setter/`HasNodeConnectHandler`만 둠). 계획 표에 있던 세 파일 범위와 동일하다.
- stale callback no-op 위치: 계획 REFACTOR-1은 "handler가 current Registry generation을 다시 확인"이라고 명시했고, 이를 서비스 계층 `HandleNodeConnect`의 `registry.IsCurrentOwnerGeneration` 재확인으로 구현했다. transport는 accepted(=RegisterIfAbsent true)에서만 callback을 부르고 rejected duplicate는 early-return으로 호출 자체를 하지 않는다.
- 검증 명령은 계획/스텁과 동일하게 실행했다. 추가로 `go test -count=1 ./...` 전체 회귀가 이번엔 전 패키지 PASS(exit 0)였다(predecessor 08/13 로그의 `apps/node/internal/adapters/cli` timing flake가 이번 실행에서는 재현되지 않음). mock e2e는 `IOP_E2E_BIND_TIMEOUT=60`(warm build)로 실행해 cold-start bind timeout을 회피했다 — 이는 08/13 complete.log가 기록한 것과 동일한 환경 사유이며 correctness와 무관하다.

## 주요 설계 결정

- **Accepted-only callback ordering**: `handleRegisterRequest`에서 `RegisterIfAbsent`가 true를 반환한 직후(= registry가 `entry.ConnectionGeneration`을 발급한 시점) `notifyNodeConnected(rec.ID, entry.ConnectionGeneration)`를 `emitNodeRegistered`(관측 event) **앞**에서 동기 호출한다. run-lifecycle/disconnect hook과 동일하게 event bus 포화가 correctness(resource activation)를 막지 못하게 한다. rejected duplicate는 `rejectDuplicateRegistration`으로 먼저 반환되므로 callback을 만들지 않는다.
- **Generation activation semantics**: `activateNodeGenerationLocked`는 해당 node의 기존 provider resource에 대해 `orphan=false`로 되돌리고 `generation`을 reconnect generation으로 **advance-only**(`newGen > res.generation`일 때만)한다. 이로써 (1) 새 generation candidate가 `generationEligible`(non-orphan → `g >= res.generation`)을 통과하고, (2) 남아 있는 old-generation stale candidate는 fence된다. old generation counter/lease는 되살리지 않는다(09 terminal item은 이미 큐에서 제거됨). resource가 아예 없으면 되살리지 않고 live resolver의 `resourceForCandidateLocked`가 store에서 재생성하게 둔다.
- **Pending item rebuild/pump**: `activateNode`는 activation 후 predecessor 13의 `resolveAndPumpAllLocked("", 0, false)`를 호출한다. disconnect context가 없으므로(excludeNodeID="") 아무 candidate도 purge하지 않고, resolver-item은 live registry(=reconnect entry 포함)로 재구성되며 orphan이 방금 해제됐으므로 orphan filter를 통과한다. 단일 global pump가 enqueue 순서대로 waiter를 dispatch한다 — 새 요청/config refresh/lease release 없이 reconnect만으로 pump가 트리거된다.
- **Stale/rejected 무활성화**: 서비스 `HandleNodeConnect`는 `generation==0`(untracked) 또는 `registry.IsCurrentOwnerGeneration(nodeID, generation)==false`(이미 superseded되었거나 disconnect로 사라진 generation)이면 no-op이다. registry check → queue lock 사이의 잔여 TOCTOU는 benign이다: dispatch는 live candidate까지 함께 요구하는데, 실제로 사라진 node는 resolver가 candidate를 내지 않으므로 잘못된 dispatch가 발생하지 않는다.
- **Evidence 위치**: reconnect-only correctness의 결정 evidence는 local transport+service integration test다(SDD Evidence Map/계획과 동일). mock e2e는 보조 full-cycle 생존 확인이며 reconnect 시나리오를 직접 구동하지 않는다.

## 사용자 리뷰 요청

_기본값은 `없음`이다. 구현 중 새 결정이 필요해 보여도 직접 질문하거나 선택지를 제시하거나 `request_user_input`을 호출하지 않는다. 이 섹션은 선택된 Milestone `구현 잠금 > 결정 필요` 항목이 실구현을 차단할 때만 채운다. 채운 뒤 구현 에이전트는 code-review를 실행하거나 역할을 바꾸지 않고 active pair를 유지한 채 구현 실행을 종료한다. 이 저장 상태가 runtime의 `review-ready` 신호이므로 별도 handoff 파일·사용자 메시지를 만들지 않는다. runtime은 사용자에게 묻지 않고 별도 review 에이전트 instance를 즉시 배정하며, review 에이전트가 `USER_REVIEW.md`를 실제로 만들기 전에는 terminal 상태가 아니다. 외부 환경/secret/서비스 준비, 검증 증거 공백, 반복 실패, 일반 범위 조정은 사용자 리뷰 요청이 아니며 blocker evidence·결정적 해제 조건·재검증 명령을 `검증 결과`나 `계획 대비 변경 사항`에 기록한 뒤 code-review의 일반 follow-up plan으로 처리한다._

- 상태: 없음
- 사유 유형: 없음
- 연결 대상: 없음
- 결정 필요: 없음
- 차단 근거: 없음
- 실행한 검증/명령: 없음
- 자동 후속 불가 이유: 없음
- 재개 조건: 없음

## 리뷰어를 위한 체크포인트

- accepted current owner만 connect callback을 만들고 duplicate reject/stale callback은 activation과 event를 만들지 않는가.
- callback은 관측 event fanout과 독립적으로 먼저 완료되며 event bus 포화가 correctness를 막지 않는가.
- reconnect generation이 orphan resource를 교체하되 old generation counter/lease를 되살리지 않는가.
- pending item이 live resolver로 재구성되고 새 외부 trigger 없이 global enqueue 순서로 즉시 dispatch되는가.

## 검증 결과

아래 각 명령의 실제 stdout/stderr를 붙인다. 명령 변경은 `계획 대비 변경 사항`에 이유를 기록한다.

### 중간 검증

`go test -count=1 ./apps/edge/internal/transport ./apps/edge/internal/bootstrap`

`go test -race -count=1 ./apps/edge/internal/service -run 'Reconnect|CandidateRecovery|NodeConnect'`

```text
$ go test -count=1 ./apps/edge/internal/transport ./apps/edge/internal/bootstrap
ok  	iop/apps/edge/internal/transport	4.377s
ok  	iop/apps/edge/internal/bootstrap	0.280s

$ go test -race -count=1 ./apps/edge/internal/service -run 'Reconnect|CandidateRecovery|NodeConnect'
ok  	iop/apps/edge/internal/service	1.036s
```

신규 통과 test: `TestAcceptedReconnectActivatesCandidateAndPumpsWaiter`, `TestReconnectRebuildsDisconnectedCandidateUniverse`, `TestReconnectConnectHookActivatesResourceGenerationInSnapshot`(service), `TestAcceptedConnectHookRunsBeforeEventPerGeneration`(transport). 기존 `TestProviderSnapshotReconnectRestoresCapacityAndAdmission`도 회귀 통과.

### gofmt

`gofmt -d apps/edge/internal/transport/server.go apps/edge/internal/transport/connection_handlers.go apps/edge/internal/transport/integration_test.go apps/edge/internal/bootstrap/runtime.go apps/edge/internal/service/service.go apps/edge/internal/service/model_queue_types.go apps/edge/internal/service/model_queue_release.go apps/edge/internal/service/service_internal_test.go apps/edge/internal/service/queue_dispatch_test.go apps/edge/internal/service/status_provider_test.go`

```text
$ gofmt -d <10 files>
(출력 없음 — clean)
```

### 대상 package와 race

`go test -count=1 ./apps/edge/internal/transport ./apps/edge/internal/bootstrap`

`go test -count=1 ./apps/edge/internal/service -run 'Reconnect|CandidateRecovery|NodeConnect'`

`go test -race -count=1 ./apps/edge/internal/transport ./apps/edge/internal/service`

```text
$ go test -count=1 ./apps/edge/internal/transport ./apps/edge/internal/bootstrap
ok  	iop/apps/edge/internal/transport	4.390s
ok  	iop/apps/edge/internal/bootstrap	0.343s

$ go test -count=1 ./apps/edge/internal/service -run 'Reconnect|CandidateRecovery|NodeConnect'
ok  	iop/apps/edge/internal/service	0.010s

$ go test -race -count=1 ./apps/edge/internal/transport ./apps/edge/internal/service
ok  	iop/apps/edge/internal/transport	5.386s
ok  	iop/apps/edge/internal/service	6.911s
```

race warning 0.

### 전체와 보조 smoke

`go test -count=1 ./apps/edge/...`

`go test -count=1 ./...`

`IOP_E2E_PROFILE=mock ./scripts/e2e-smoke.sh`

```text
$ go test -count=1 ./apps/edge/...
ok  	iop/apps/edge/cmd/edge	0.130s
ok  	iop/apps/edge/internal/bootstrap	0.343s
ok  	iop/apps/edge/internal/configrefresh	0.053s
ok  	iop/apps/edge/internal/controlplane	4.467s
ok  	iop/apps/edge/internal/edgecmd	0.047s
ok  	iop/apps/edge/internal/edgevalidate	0.013s
ok  	iop/apps/edge/internal/events	0.006s
ok  	iop/apps/edge/internal/input	0.015s
ok  	iop/apps/edge/internal/input/a2a	0.011s
ok  	iop/apps/edge/internal/node	0.011s
ok  	iop/apps/edge/internal/openai	6.752s
ok  	iop/apps/edge/internal/opsconsole	0.007s
ok  	iop/apps/edge/internal/service	5.860s
ok  	iop/apps/edge/internal/transport	4.390s

$ go test -count=1 ./...
(전 패키지 PASS; exit 0. FAIL/비-ok 라인 없음. 08/13 로그의 apps/node/internal/adapters/cli timing flake는 이번 실행에서 재현되지 않음.)

$ IOP_E2E_PROFILE=mock IOP_E2E_BIND_TIMEOUT=60 ./scripts/e2e-smoke.sh
[e2e] Auxiliary smoke test PASSED.
[e2e] Completion still requires scripts/dev/edge.sh + scripts/dev/node.sh user-flow verification.
```

- 보조 smoke full-cycle 관측: startup/register(node_id=test-node) → capabilities → transport_status → foreground run ×3(각 run `start` → `[node-message]` payload → `complete detail="idle-timeout"`) → session_list → terminate-session → authoritative disconnected event 1회. `IOP_E2E_BIND_TIMEOUT=60`(warm build)로 cold-start bind timeout을 회피했다(08/13 complete.log와 동일한 환경 사유, correctness 무관).
- reconnect-only full-cycle evidence: mock smoke는 reconnect 시나리오를 직접 구동하지 않는다. reconnect-candidate-recovery의 결정 evidence는 deterministic local integration test다 — `TestReconnectRebuildsDisconnectedCandidateUniverse`(full-alternate 포화 + node 재연결 → live resolver로 candidate universe 재구성 → 외부 trigger 없이 dispatch, snapshot 수렴/idempotence 확인), `TestAcceptedReconnectActivatesCandidateAndPumpsWaiter`(외부 trigger 없음 + stale-generation no-op), `TestAcceptedConnectHookRunsBeforeEventPerGeneration`(accepted/reconnect 각 generation당 callback 1회, rejected duplicate 0회, callback→event ordering), `TestReconnectConnectHookActivatesResourceGenerationInSnapshot`(activation generation advance + snapshot 수렴). race 검증은 위 `-race` 실행 포함.

---

> **[IMPLEMENTING AGENT — BEFORE SAVING]** completion table, checklist, 변경 사항, 설계 결정, 검증 stdout/stderr를 모두 채우고 active 파일을 유지한 채 구현 실행을 종료한다. 이 파일 상태와 실행 종료가 runtime의 `review-ready` 신호이므로 별도 handoff 파일·사용자 메시지를 만들지 않는다. code-review 실행, 역할 전환, 판정, review 전용 섹션 수정, archive/terminal/follow-up 처리는 금지한다.

## 섹션 소유권

| Section | Owner | Note |
|---------|-------|------|
| Header/개요/Roadmap Targets/checkpoints | Fixed | 수정 금지 |
| 구현 표/체크리스트/변경/설계/검증 | Implementing agent | 실제 내용 필수 |
| 리뷰 체크리스트/결과 | Review agent | 구현 에이전트 수정 금지 |
| 사용자 리뷰 요청 | Implementing agent | Milestone 잠금 결정만 |

## 코드리뷰 결과

- 종합 판정: FAIL
- Legacy artifact 예외: 구현/리뷰 model identity marker는 이전 형식에 없어 사용자 명시 지시에 따라 판정 차단 사유로 삼지 않았다.

### 차원별 평가

| 차원 | 평가 | 근거 |
|---|---|---|
| Correctness | Fail | accepted reconnect가 RegisterResponse 전에 대기 요청을 dispatch할 수 있어 Node handler 미설치 시 첫 요청이 유실된다. |
| Completeness | Fail | S15의 실제 Edge-Node 재연결 handoff 순서를 검증하는 테스트가 없다. |
| Test coverage | Fail | transport hook 테스트와 service queue 테스트가 분리되어 있고, 실제 `DialEdge`/bootstrap 세션 준비 전 dispatch를 재현하지 못한다. |
| API contract | Fail | register handshake의 config 전달·Node handler 준비 경계보다 execution dispatch가 앞선다. |
| Code quality | Pass | lifecycle hook, generation fence, live resolver 재구성의 책임 분리는 일관된다. |
| Implementation deviation | Pass | 계획한 파일 범위와 accepted-only/generation-aware 방향은 유지됐다. |
| Verification trust | Fail | 대상·전체 Go 회귀와 mock smoke는 통과했지만 reconnect-ready handoff를 다루지 않으며, 실제 dev user-flow와 live provider preflight는 완료 근거가 아니다. |
| Spec conformance | Fail | S15의 accepted reconnect가 dispatch 가능한 live candidate를 복구해야 한다는 조건을 실제 Node readiness 전에 만족시키려 한다. |

### 발견된 문제

- Required — `apps/edge/internal/transport/connection_handlers.go:121`에서 `notifyNodeConnected`가 `RegisterResponse` 반환(`:124-129`) 전에 queue pump를 실행한다. 그러나 Node는 `apps/node/internal/transport/client.go:137-149`에서 그 응답을 받은 뒤에야 `newSession`을 만들고, `apps/node/internal/bootstrap/module.go:102-108`에서 config 적용과 handler 설치를 더 늦게 수행한다. 즉 reconnect로 깨운 waiter가 `RunRequest`/`ProviderTunnelRequest`를 즉시 send하면 Node 측 listener/handler가 없어 요청을 버리고, Edge는 send 성공을 dispatch로 기록해 terminal event와 lease release를 기다리게 된다. RegisterResponse/config 적용 뒤의 명시적 Node-ready handshake 또는 Edge-side ready gate를 도입해 pump가 dispatch 가능한 세션에서만 일어나게 하고, 실제 Node reconnect + queued waiter 통합 회귀(정상 실행·terminal·lease 0 회복)를 추가해야 한다.
- Required — 실제 `scripts/dev/edge.sh` + `scripts/dev/node.sh` user-flow 검증이 수행되지 않았고, 실행한 mock smoke도 스스로 보조 검증임을 명시한다. 위 ready gate를 구현한 뒤 재연결 waiter 시나리오를 포함한 full-cycle 결과를 남겨야 한다. `scripts/e2e-long-context-admission-smoke.sh --preflight`는 local endpoint 부재로 rc=3이었으므로, live provider 환경에서는 관련 scenario도 별도로 확인해야 한다.

### 검증 결과

- PASS — `gofmt -d` 대상 10개 파일, `git diff --check` 대상 범위.
- PASS — `go test -count=1 ./apps/edge/internal/transport ./apps/edge/internal/bootstrap`.
- PASS — `go test -race -count=1 ./apps/edge/internal/service -run 'Reconnect|CandidateRecovery|NodeConnect'`.
- PASS — `go test -count=1 ./apps/edge/...`, `go test -count=1 ./...`.
- PASS — `IOP_E2E_PROFILE=mock IOP_E2E_BIND_TIMEOUT=60 ./scripts/e2e-smoke.sh` (보조 smoke).
- BLOCKED — `./scripts/e2e-long-context-admission-smoke.sh --preflight` (local runner에서 provider/status endpoint 미도달, rc=3).

### 다음 단계

- FAIL: archived review findings를 입력으로 별도 Plan 모델이 ready handoff, 통합 회귀, full-cycle 검증을 포함한 후속 PLAN/CODE_REVIEW pair를 작성한다.
