Skip to content

SKI-10: Query-SID runtime reproduction#32

Merged
pko89403 merged 6 commits into
mainfrom
agent/elated-sammet-50a514
Apr 23, 2026
Merged

SKI-10: Query-SID runtime reproduction#32
pko89403 merged 6 commits into
mainfrom
agent/elated-sammet-50a514

Conversation

@pko89403

Copy link
Copy Markdown
Owner

한 줄 요약

  • 이 PR은 compile-sid-index가 학습한 residual K-means quantizer를 런타임 artifact로 저장하고 recommend가 이를 다시 로드해 query를 item과 같은 SID 공간에 할당·노출하도록 바꿉니다. 이유는 현재 query는 FAISS 벡터 공간에서만 매칭되고 item과 같은 SID 좌표를 가지지 못해, query_sid를 downstream 의사결정에 쓸 수 없기 때문입니다.

배경 / 문제

  • 기존 상태: train_codebooks가 학습한 residual quantizer는 compile 시점에 item을 SID로 할당한 뒤 버려집니다. 런타임 query는 L2-정규화만 거쳐 FAISS에 쏘고, item SID와 같은 계층 좌표를 전혀 갖지 못합니다.
  • 문제: 결과적으로 RecommendationResponse는 item별 sid_string은 실어 보내지만 query 자체의 SID 좌표는 비어 있어, 향후 SID locality 기반의 검색 반경·그룹 confidence·rerank prior 작업을 얹을 축이 없습니다. 또한 SID 타입 레이어에 CompiledSIDItems 번들이 TrainedResidualCodebooks와 4개 필드가 중복돼 있었습니다.
  • 이번 PR의 목표: (1) quantizer를 sid_index 디렉터리 안에 1급 artifact(residual_codebooks.npz + residual_codebooks_manifest.json)로 저장, (2) recommend가 이를 같은 정규화 규칙으로 재사용해 taxonomy-aligned query를 SID path에 할당, (3) query_sidSemanticSearchResultRecommendationResponse → CLI → demo mock까지 관통시킵니다. 검색 점수·adaptive radius·rerank 정책은 건드리지 않습니다.

PR 대시보드

항목 내용
유형 feat
영향 범위 SID compiler · recommendation runtime · CLI · demo · docs · tests
동작 변경 있음 (추천 응답에 query_sid 추가, compile-sid-index 산출물에 codebook artifact 추가)
Breaking Change 있음 (기존 sid_index 디렉터리는 재컴파일 필요 — 아래 '남은 리스크' 참고)
관련 이슈 SKI-10
기준 브랜치 main

변경 묶음별 리뷰 가이드

변경 묶음 파일/디렉토리 무엇이 바뀌었나 리뷰 포인트 실행 없이 보는 법
SID 타입/quantizer 저장 src/sid_reco/sid/compiler.py, src/sid_reco/sid/indexing.py, src/sid_reco/sid/__init__.py CompiledSIDItems 번들을 ItemSID + QuerySID 두 구체 타입으로 분해. train_codebooks / build_item_sids / write_codebooks / load_codebooks로 명명 정리. write_sid_index_outputs가 codebook artifact까지 함께 저장하고 SIDIndexWriteSummary에 경로 2개 추가. load_codebooksallow_pickle=False + 사이블링 manifest 필드 전수 검증. 타입 경계가 "quantizer = 유일한 SID 공간 정의"라는 원칙을 지키는지, write/load 경로의 실패 모드가 명확한지 compiler.pyTrainedResidualCodebooks / write_codebooks / load_codebooks / build_query_sid 네 섹션만 대조
Runtime query-SID src/sid_reco/recommendation/semantic_search.py, src/sid_reco/recommendation/types.py, src/sid_reco/recommendation/pipeline.py, src/sid_reco/recommendation/__init__.py FAISS 열기 전에 codebook을 로드, 없으면 명확한 에러로 실패 (silent downgrade 금지). taxonomy-aligned query를 한 번 인코딩해 FAISS는 L2-정규화본을, build_query_sid는 raw 벡터를 쓴다(per-level 정규화 규칙을 compile과 동일 유지). SemanticCandidatesid_path: tuple[int,...] 추가(id_map의 sid_path/sid_string 일관성 검사), SemanticSearchResult/RecommendationResponsequery_sid 추가. FAISS용 정규화와 SID 할당용 원본 벡터가 분리되어 있는지, query-SID 계산이 compile 시 item 경로와 같은 코드를 지나가는지 semantic_search.search_semantic_candidatesraw_vector / query_matrix / build_query_sid 분기만 보면 충분
CLI src/sid_reco/cli.py compile-sid-index 결과 테이블에 Codebooks path 행 추가. recommend 결과 아래 Query SID: 한 줄 출력. 출력 라벨 일관성과 Rich 표 폭 cli.pycompile_sid_index 표 빌더와 recommend 출력 블록
Demo mock apps/demo/data/pipeline.js, apps/demo/src/components.jsx, apps/demo/tests/pipeline.test.cjs buildSid{sid_string, sid_path} 반환(mock-only 0..255 해시), buildQuerySid 추가(sketch 누락 시 any fallback), JSON preview에 query_sid + per-item sid_path 노출, FinalDelivery 카드가 sid_string 필드 사용. mock은 실제 Phase 1 artifact를 읽지 않는다는 계약 유지 여부, 해시 범위(0–255)와 fallback 경로 pipeline.jshashToken / buildSid / buildQuerySid 세 함수만 보면 계약을 전부 읽을 수 있음
Tests tests/test_sid_compiler.py, tests/test_sid_indexing.py, tests/test_semantic_search.py, tests/test_cli_compile_sid_index.py, tests/test_cli_recommend.py, tests/test_recommendation_pipeline.py, tests/test_confidence_mapping.py, tests/test_zero_shot_rerank.py codebook 저장/로드 round-trip, query-item SID 재현성(normalize on/off), FAISS-less semantic search의 query-SID 경로, malformed NPZ/tampered manifest 에러 경로, id_map.jsonl의 sid_path/sid_string 일관성 검사, CLI 출력 rows, demo query_sid shape/"any" fallback 테스트 추가. 기존 테스트들은 query_sid 필드에 맞춰 업데이트. 새 시나리오(반올림 에러·경로 불일치·사라진 manifest·query-SID 재현)가 실제 실패 모드를 커버하는지 각 테스트 파일의 신규 test 이름만 스캔
Docs/Graph SPEC.md, graphify-out/** SPEC을 SKI-10 런타임 재현용으로 재작성(가정 / 목표 / 비목표 / 계약 / 테스트 매트릭스). graph는 code_update 모드로 자동 리프레시. SPEC이 proper-over-expedient 원칙과 AGENTS.md 스키마(한국어 design 규칙 포함)와 일치하는지 SPEC.md의 목표/비목표/제공하는 계약 섹션

Before / After

Before

  • train_codebooks가 학습한 residual quantizer는 할당 직후 폐기되었고, sid_index/에는 item 좌표만 남아 있었음.
  • recommend는 taxonomy-aligned query 텍스트를 L2-정규화 해 FAISS로 쏘는 것이 끝이었고, query-SID는 존재하지 않았음.
  • SID 타입은 CompiledSIDItem/CompiledSIDItems로 양분돼 있었고, 번들 필드 4개(branching_factor/depth/embedding_dim/levels)가 TrainedResidualCodebooks와 중복.
  • apps/demo는 문자열 SID 하나만 노출.

After

  • compile-sid-indexsid_index_dir/ 안에 residual_codebooks.npz + residual_codebooks_manifest.json을 함께 저장하고, top-level manifest.json에 상대경로와 normalize_residuals를 실어 보냄.
  • recommend는 FAISS 열기 전 codebook을 로드(없으면 clear error로 실패). taxonomy-aligned query를 한 번 인코딩하고 FAISS에는 정규화본을, build_query_sid에는 raw 벡터를 사용 — per-level 정규화 규칙이 compile과 동일하게 유지됨.
  • SID 타입은 ItemSID / QuerySID 두 구체 타입으로 정리. CompiledSIDItemscompile_residual_kmeans 편의 래퍼는 삭제.
  • 모든 추천 응답(RecommendationResponse.query_sid), recommend CLI, demo mock 파이프라인 JSON preview에 query_sid가 노출됨. 모든 SemanticCandidate에는 id_map 검증을 거친 sid_path가 따라옴.

검증

항목 결과 근거
테스트 uv run pytest 148 passed (기존 flaky 2건 test_graphify_auto_refresh는 CI/pre-push ignore 룰에 동일하게 제외됨)
린트 uv run ruff check .
타입체크 uv run mypy src
Demo node --test apps/demo/tests/pipeline.test.cjs 22/22
Graph graphify-out/BUILD_INFO.json mode=code_update (source 변경만)

남은 리스크 / 후속 작업

  • 기존 sid_index 디렉터리는 residual_codebooks.npz / residual_codebooks_manifest.json이 없으므로 recommendFileNotFoundError로 실패함. 기본 경로 data/processed/foodcom/sid_index/.gitignore에 포함돼 있고, 사용자는 uv run sid-reco compile-sid-index로 재생성하면 됨 (에러 메시지에 동일 힌트 포함).
  • 검색 반경 조정, SID-group confidence, bootstrap rerank 정책 변경은 이번 범위에서 명시적으로 제외 — 별도 이슈.
  • apps/demo의 해시 기반 sid_path는 mock-only. 실제 Phase 1 codebook과 비교하면 안 됨 (코드/테스트/SPEC 모두에서 이 계약을 명시).
  • 주의할 점: load_codebooksallow_pickle=False로 읽고 사이블링 manifest의 모든 필드를 검증하므로, NPZ만 교체하거나 manifest만 바꿔도 즉시 실패함. 이는 의도된 fail-fast.
  • 리뷰 시 특히 볼 부분: (1) semantic_search.py의 raw vs normalized 벡터 분리, (2) compiler._validate_manifest_against_npz의 필드 집합, (3) indexing.write_sid_index_outputs의 시그니처 변경.

Codex and others added 6 commits April 23, 2026 10:37
SKI-10 Slice 1. Replace the CompiledSIDItem/CompiledSIDItems bundle
with ItemSID/QuerySID dataclasses (no base), rename quantizer APIs
(train_codebooks, build_item_sids, write_codebooks, load_codebooks),
and persist the trained residual quantizer alongside the SID index.

- residual_codebooks.npz + residual_codebooks_manifest.json written
  inside sid_index_dir with relative paths.
- manifest.json gains normalize_residuals, codebooks_path,
  codebooks_manifest_path (additive).
- SIDIndexWriteSummary exposes codebooks_path /
  codebooks_manifest_path.
- compile-sid-index CLI table shows `Codebooks path`.
- Load path validates NPZ vs sibling manifest; missing/mismatched
  artifacts raise FileNotFoundError / ValueError with a remediation
  hint pointing to `uv run sid-reco compile-sid-index`.
- Tests cover codebook round-trip, item-assignment reproducibility,
  malformed NPZ / tampered manifest, and CLI output rows.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
SKI-10 Slice 2. Add build_query_sid, which places a single runtime
query vector on the same residual-K-means coordinates that
build_item_sids produced at compile time.

- Shares _prepare_level_inputs / _assign_to_centroids with
  build_item_sids by wrapping the 1-D query vector into 1×D, so the
  per-level normalization policy recorded on the codebooks applies
  unchanged.
- QuerySID / build_query_sid are now exported from sid_reco.sid.
- Reproducibility test: for every row of a fixture matrix, the query
  and item paths match under both normalize_residuals=True and False.
- Same reproducibility holds after a write_codebooks / load_codebooks
  round-trip.
- Rejects 2-D, empty, and mismatched-dim query vectors with
  ValueError.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
SKI-10 Slice 3. Wire the query-SID computation into semantic retrieval
so that every recommendation response — library and CLI — carries the
query's coordinates alongside the items it ranks.

- semantic_search loads residual codebooks before opening FAISS and
  raises with a clear remediation hint when they are missing.
- The taxonomy-aligned query is encoded once; FAISS still uses the L2-
  normalized copy while build_query_sid consumes the raw vector so the
  per-level normalization matches compile time.
- SemanticCandidate now carries sid_path (tuple[int, ...]) preserved
  from id_map.jsonl; SemanticSearchResult and RecommendationResponse
  carry query_sid (QuerySID).
- `recommend` CLI prints a `Query SID:` line after the confidence
  summary.
- Tests assert query_sid reproducibility against fixture item
  embeddings, candidate sid_path preservation, and a missing-codebook
  FileNotFoundError path; regression assertions on recipe_ids and
  summaries remain intact.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- compiler.load_codebooks now loads with allow_pickle=False and
  checks codebooks_path in the manifest so a renamed or swapped
  .npz file is rejected before downstream SID assignment.
- semantic_search._load_id_map rejects id_map.jsonl lines whose
  sid_path and sid_string disagree, closing a silent-drift hole
  noticed during review of the query-SID runtime pipeline.
- test_cli_compile_sid_index pins Rich's COLUMNS so the
  "Codebooks path" cell is not truncated, and asserts the full
  path instead of a substring to exercise the new guarantee.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Mirror the runtime shape landed on the Python side so the demo
JSON preview and final-delivery view match the new contract:

- buildSid now returns {sid_string, sid_path} with a deterministic
  0..255 token hash per level (mock stand-in, never compared to a
  real Phase 1 codebook).
- buildQuerySid derives a QSID from the interest sketch using the
  same hash and falls back to "any" when a facet is missing.
- Confidence result carries query_sid through to the JSON preview
  alongside per-item sid_path, and the FinalDelivery card switches
  to the sid_string field.
- New tests cover query_sid shape, sid_path integer range, and
  the "any" fallback; existing sid-format test is tightened.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
code_update-level refresh after the compiler and semantic-search
hardening plus the demo query_sid alignment.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@pko89403 pko89403 merged commit 298f442 into main Apr 23, 2026
2 checks passed
@pko89403 pko89403 deleted the agent/elated-sammet-50a514 branch April 23, 2026 03:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant