<!-- task=m-agent-readable-repository-refactor/13_inventory_query plan=5 tag=REVIEW_REVIEW_REVIEW_REVIEW_REVIEW_IQRY -->

# Provider map focused regression assertion 보완 계획

## 이 파일을 읽는 구현 에이전트에게

구현과 검증을 마친 뒤 `CODE_REVIEW-local-G04.md`의 구현 에이전트 소유 섹션에 실제 변경 내용과 명령 출력을 채우고 active 파일을 그대로 둔 채 리뷰 준비 상태를 보고한다. 종결, 로그 아카이브, `complete.log` 작성은 code-review 전용이다. 선택된 Milestone의 `구현 잠금 > 결정 필요` 항목이 실제 구현을 막는 경우에만 review stub의 `사용자 리뷰 요청`에 연결 근거를 기록하고 멈춘다. 구현 중 사용자에게 직접 질문하거나 선택지를 제시하거나 `request_user_input`을 호출하거나 `USER_REVIEW.md`/로그/`complete.log`를 만들지 않는다. 환경·secret·서비스 차단, 일반 범위 변경, 후속 에이전트가 채울 수 있는 evidence 공백은 사용자 리뷰 요청이 아니다.

## 배경

다섯 번째 리뷰에서 provider collector 분리, package/binary 계약, readability와 전체 Go 회귀는 통과했다. 그러나 focused regression은 scalar/key+value case의 actual `match.Value`와 subtest 결과 정렬을 검증하지 않아 계획한 exact path/value/order 계약을 닫지 못했다. 테스트 assertion만 좁게 보완하고 동일 검증을 fresh 실행한다.

## 사용자 리뷰 요청 흐름

선택된 Milestone의 `구현 잠금 > 결정 필요`만 `agent-ops/skills/common/_templates/implementation-user-review-request-section.md` 형식으로 active review stub에 기록한다. 구현 중 직접 사용자 prompt는 금지하며, 요청 검증과 실제 `USER_REVIEW.md` 작성은 code-review가 담당한다.

## Roadmap Targets

- Milestone: `agent-roadmap/phase/automation-runtime-bridge/milestones/agent-readable-repository-refactor.md`
- Milestone link: [Milestone 문서](agent-roadmap/phase/automation-runtime-bridge/milestones/agent-readable-repository-refactor.md)
- Task ids:
  - `inventory-query`: env/model/node/provider selector로 canonical inventory의 bounded 결과를 얻는 결정적 query 경로
- Completion mode: check-on-pass

## Archive Evidence Snapshot

- Prior task: `agent-task/m-agent-readable-repository-refactor/13_inventory_query`
- Archived plan: `agent-task/m-agent-readable-repository-refactor/13_inventory_query/plan_local_G06_4.log`
- Archived review: `agent-task/m-agent-readable-repository-refactor/13_inventory_query/code_review_local_G06_4.log`
- Verdict: FAIL
- Required: 1 — focused provider map regression의 exact actual value 및 결과 정렬 assertion 누락
- Suggested: 0
- Nit: 0
- Affected files: `scripts/inventory-query/provider_query_test.go`, active review stub
- Verification evidence: targeted/package/full Go test, compiled canonical dev/dev-corp selector, binary 0/1/2/help, readability ratchet, gofmt와 `git diff --check`는 모두 PASS했다. 실패는 테스트 assertion 정적 대조에서 확인됐다.
- Roadmap carryover: `inventory-query`는 PASS 전까지 미완료다.
- Allowed narrow reread: 위 archived plan/review 두 파일만 추가 세부가 필요할 때 읽는다.

## 분석 결과

### 읽은 파일

- `agent-ops/rules/project/rules.md`
- `agent-ops/rules/common/rules-roadmap.md`
- `agent-ops/rules/common/rules-agent-spec.md`
- `agent-ops/rules/project/domain/testing/rules.md`
- `agent-ops/rules/project/domain/platform-common/rules.md`
- `agent-ops/skills/common/router.md`
- `agent-ops/skills/common/code-review/SKILL.md`
- `agent-ops/skills/common/plan/SKILL.md`
- `agent-ops/skills/common/_templates/implementation-user-review-request-section.md`
- `agent-test/local/rules.md`
- `agent-test/local/testing-smoke.md`
- `agent-test/local/platform-common-smoke.md`
- `agent-roadmap/current.md`
- `agent-roadmap/phase/automation-runtime-bridge/milestones/agent-readable-repository-refactor.md`
- `agent-spec/index.md`
- `agent-spec/runtime/provider-pool-config-refresh.md`
- `agent-contract/index.md`
- `agent-contract/inner/edge-config-runtime-refresh.md`
- `scripts/inventory-query/main.go`
- `scripts/inventory-query/provider_query.go`
- `scripts/inventory-query/main_test.go`
- `scripts/inventory-query/provider_query_test.go`
- `agent-task/m-agent-readable-repository-refactor/13_inventory_query/plan_local_G06_4.log`
- `agent-task/m-agent-readable-repository-refactor/13_inventory_query/code_review_local_G06_4.log`

### SDD 기준

Milestone은 `SDD: 불필요`다. 외부 API/proto/config schema나 runtime 책임 경계를 바꾸지 않고 동일 package 안의 테스트 assertion만 보완하는 동작 보존형 후속 작업이다.

### 테스트 환경 규칙

`test_env=local`이다. `agent-test/local/rules.md`, `agent-test/local/testing-smoke.md`, `agent-test/local/platform-common-smoke.md`를 읽었다. 현재 checkout에서 fresh focused/package/full Go test, compiled canonical selector와 0/1/2/help, worktree readability ratchet, `git diff --check`를 적용한다. 외부 provider/runtime, Docker, endpoint, secret은 필요하지 않고 binary/cache/JSON evidence는 `/tmp`에만 둔다.

### 테스트 커버리지 공백

- `TestQueryProviderMatchesMapEntries`는 네 독립 subtest와 expected path, path uniqueness를 검증한다.
- Scalar와 key+value case는 expected actual `match.Value`를 비교하지 않아 잘못된 반환값을 잡지 못한다.
- Focused subtest 결과가 path 오름차순인지 확인하지 않아 계획한 order regression을 잡지 못한다.

### 심볼 참조

외부 rename/remove는 없다. 변경 대상은 `providerMapEntryCase`, `assertProviderEntryMatch`와 package-local test helper뿐이며 참조는 `scripts/inventory-query/provider_query_test.go` 안에 한정된다.

### 분할 판단

split decision policy를 재평가했다. 하나의 focused test table과 assertion helper를 함께 고치는 단일 테스트 책임이고 별도 API, call-site, 도메인, 검증 환경 경계가 없다. 분할하면 같은 test file과 동일 검증을 중복하므로 기존 `13_inventory_query` 단일 follow-up이 안전하다.

### 범위 결정 근거

Production collector, CLI/API/config/schema, inventory fixture, deploy skill, agent-spec, agent-contract, roadmap, readability baseline/threshold/allowlist는 수정하지 않는다. 변경 범위는 `scripts/inventory-query/provider_query_test.go`와 active review evidence에 한정한다.

### 빌드 등급

`local-G04`. 단일 Go test file의 명시적 assertion 보완이며 focused/package/full test와 결정적 audit 명령으로 완전히 판정할 수 있다.

## 구현 체크리스트

- [ ] `TestQueryProviderMatchesMapEntries`의 각 case에서 expected entry actual value와 반환 path 정렬을 검증해 exact path/value/order/dedupe 회귀 계약을 충족한다.
- [ ] fresh focused/package/full Go test, canonical compiled binary 계약, worktree readability audit와 diff 검증을 exact 명령으로 실행한다.
- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.

### [REVIEW_REVIEW_REVIEW_REVIEW_REVIEW_IQRY-1] Exact provider map assertion 보완

#### 문제

`scripts/inventory-query/provider_query_test.go:81`의 `assertProviderEntryMatch`는 `wantID`/`wantProv`가 있는 entity 일부 필드만 확인한다. Scalar와 key+value case는 `m.Value`가 무엇이든 expected path만 있으면 통과하고, 반환 path의 오름차순도 확인하지 않아 계획한 exact actual value/order regression이 비어 있다.

#### 해결 방법

각 `providerMapEntryCase`에 expected actual value를 명시하고 expected path의 `match.Value` 전체를 `reflect.DeepEqual` 또는 동등한 exact 비교로 검증한다. 같은 assertion 흐름에서 모든 반환 path가 오름차순인지 확인하고 기존 path uniqueness 검증을 유지한다.

Before (`scripts/inventory-query/provider_query_test.go:8`):

```go
type providerMapEntryCase struct {
	name     string
	entries  map[string]interface{}
	selector string
	wantPath string
	wantID   string
	wantProv string
}
```

After:

```go
type providerMapEntryCase struct {
	name      string
	entries   map[string]interface{}
	selector  string
	wantPath  string
	wantValue interface{}
}

if !reflect.DeepEqual(got.Value, tc.wantValue) {
	t.Errorf("value at %s = %#v, want %#v", tc.wantPath, got.Value, tc.wantValue)
}
assertMatchPathsSorted(t, matches)
```

#### 수정 파일 및 체크리스트

- [ ] `scripts/inventory-query/provider_query_test.go` — 네 case의 expected actual value와 정렬 assertion 추가, 기존 path uniqueness 유지.

#### 테스트 작성

기존 `TestQueryProviderMatchesMapEntries`를 강화한다. 새 test name은 만들지 않고 scalar, entity `id`, entity `provider`, key+value dedupe case가 expected entry path/value와 전체 path 정렬을 독립 fixture에서 검증하게 한다.

#### 중간 검증

```bash
gofmt -d scripts/inventory-query/provider_query_test.go
GOCACHE=/tmp/iop-inventory-query-assertion-gocache go test -count=1 ./scripts/inventory-query -run '^TestQueryProviderMatchesMapEntries$'
python3 scripts/readability_audit.py --check --input-mode worktree --output /tmp/iop-inventory-readability-assertion.json
```

gofmt가 무출력이고 focused test와 readability audit이 exit 0이어야 한다.

## 수정 파일 요약

| 파일 | 항목 |
|------|------|
| `scripts/inventory-query/provider_query_test.go` | REVIEW_REVIEW_REVIEW_REVIEW_REVIEW_IQRY-1 |
| `CODE_REVIEW-local-G04.md` | 구현 및 actual verification evidence |

## 최종 검증

```bash
export GOCACHE=/tmp/iop-inventory-query-assertion-gocache
mkdir -p "$GOCACHE"
set -o pipefail
gofmt -d scripts/inventory-query/main.go scripts/inventory-query/provider_query.go scripts/inventory-query/main_test.go scripts/inventory-query/provider_query_test.go
go test ./scripts/inventory-query -list '^TestQueryProviderMatchesMapEntries$' | grep -qx 'TestQueryProviderMatchesMapEntries'
go test -count=1 ./scripts/inventory-query -run '^TestQueryProviderMatchesMapEntries$'
go test -count=1 ./scripts/inventory-query
go build -o /tmp/iop-inventory-query-assertion ./scripts/inventory-query
/tmp/iop-inventory-query-assertion --env dev --provider gx10-vllm > /tmp/iop-inventory-assertion-dev-provider.json
/tmp/iop-inventory-query-assertion --env dev-corp --provider corp-dgx-spark-01-ornith > /tmp/iop-inventory-assertion-corp-provider.json
python3 - <<'PY'
import json

with open("/tmp/iop-inventory-assertion-dev-provider.json", encoding="utf-8") as handle:
    dev = json.load(handle)
with open("/tmp/iop-inventory-assertion-corp-provider.json", encoding="utf-8") as handle:
    corp = json.load(handle)

dev_paths = {item["path"]: item["value"] for item in dev["matches"]}
corp_paths = {item["path"]: item["value"] for item in corp["matches"]}
assert isinstance(dev_paths["model.active_edge_model_group.providers.gx10-vllm"], dict)
assert isinstance(dev_paths["nodes[1].provider"], dict)
assert corp_paths["model.aliases.ornith:35b.providers[0]"] == "corp-dgx-spark-01-ornith"
assert isinstance(corp_paths["nodes[0].provider"], dict)
PY
set +e
/tmp/iop-inventory-query-assertion --help >/tmp/iop-inventory-assertion-help.out 2>/tmp/iop-inventory-assertion-help.err
help_rc=$?
/tmp/iop-inventory-query-assertion --env dev --node definitely-not-a-node >/tmp/iop-inventory-assertion-zero.out 2>/tmp/iop-inventory-assertion-zero.err
zero_rc=$?
/tmp/iop-inventory-query-assertion --env unsupported >/tmp/iop-inventory-assertion-error.out 2>/tmp/iop-inventory-assertion-error.err
error_rc=$?
set -e
test "$help_rc" -eq 0
test "$zero_rc" -eq 1
test "$error_rc" -eq 2
test -s /tmp/iop-inventory-assertion-help.out
test ! -s /tmp/iop-inventory-assertion-help.err
test ! -s /tmp/iop-inventory-assertion-zero.out
test ! -s /tmp/iop-inventory-assertion-error.out
python3 scripts/readability_audit.py --check --input-mode worktree --output /tmp/iop-inventory-readability-assertion-final.json
go test -count=1 ./... | tee /tmp/iop-inventory-assertion-go-test-all.out
git diff --check
```

모든 명령은 exit 0, gofmt/diff-check는 무출력이어야 한다. Readability audit은 baseline/threshold/allowlist 변경 없이 새 위반 0건이어야 하고 Go test는 `-count=1` fresh 실행을 사용한다.

모든 코드 변경 완료 후 반드시 `CODE_REVIEW-*-G??.md`의 구현 에이전트 소유 섹션을 채운다. 이 파일 작성이 구현의 마지막 단계다.
