From 769cf01a99cac442c44d21a2fd7f604ecfa50039 Mon Sep 17 00:00:00 2001 From: g1nation Date: Thu, 6 Aug 2026 10:53:53 +0900 Subject: [PATCH] =?UTF-8?q?v2.2.322:=20=EB=84=A4=EC=9D=B4=EB=B2=84=20?= =?UTF-8?q?=ED=8A=B8=EB=A0=8C=EB=93=9C=20=E2=80=94=20=EA=B5=AC=EC=B2=B4?= =?UTF-8?q?=EC=A0=81=20=EB=AA=A8=EB=8D=B8=EB=AA=85=20=EC=A0=9C=EC=95=88=20?= =?UTF-8?q?+=20ratio=20=EB=9D=BC=EB=B2=A8=20=EB=AA=85=ED=99=95=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - /naver-shopping(keywords 후보), /naver-trend(discover) 프롬프트에 "카테고리명 반복 금지, 브랜드+모델명 위주 제안" 지시 추가 - ratio 는 CTR(%) 이 아니라 구간 내 최댓값=100 상대지수임을 표 헤더/ 디스클레이머에 명시(네이버 API 자체가 CTR 미제공) --- ...cde86955f34dda22a6e02b95c9adc0a456927.json | 2 +- ...c10d377a9fef641dd359504b8d53aecd0a4c3.json | 4 ++-- .../tests/engine/.astra/missions/wiki_on.json | 12 +++++----- ...b3d9d44f32b0e4cd024b2e055db3a0d34417e.json | 2 +- ...973124fb64ba505f767c53a783833bbc3fa6a.json | 2 +- ...0e6575e54853929e991e579e318f2f5a19030.json | 2 +- ...b73b3a5a01af5d82391ec29a25bd72b8239a5.json | 2 +- ...son => stress_conflict_1785981213570.json} | 22 +++++++++---------- PATCHNOTES.md | 7 ++++++ package.json | 2 +- src/features/naverTrend/handlers.ts | 4 ++-- src/features/naverTrend/intentParser.ts | 2 ++ 12 files changed, 36 insertions(+), 27 deletions(-) rename .astra/tests/stress/.astra/missions/{stress_conflict_1785979811195.json => stress_conflict_1785981213570.json} (75%) diff --git a/.astra/tests/engine/.astra/cache/7fa9e2c0ed212d5dbde1172e996cde86955f34dda22a6e02b95c9adc0a456927.json b/.astra/tests/engine/.astra/cache/7fa9e2c0ed212d5dbde1172e996cde86955f34dda22a6e02b95c9adc0a456927.json index 08abe79..db0e0a9 100644 --- a/.astra/tests/engine/.astra/cache/7fa9e2c0ed212d5dbde1172e996cde86955f34dda22a6e02b95c9adc0a456927.json +++ b/.astra/tests/engine/.astra/cache/7fa9e2c0ed212d5dbde1172e996cde86955f34dda22a6e02b95c9adc0a456927.json @@ -1,5 +1,5 @@ { "result": "직답 결과 — single-pass mock 응답입니다.", - "createdAt": 1785979804062, + "createdAt": 1785981204343, "modelVersion": "unknown" } \ No newline at end of file diff --git a/.astra/tests/engine/.astra/cache/8c208151bed9108b665cd93e98fc10d377a9fef641dd359504b8d53aecd0a4c3.json b/.astra/tests/engine/.astra/cache/8c208151bed9108b665cd93e98fc10d377a9fef641dd359504b8d53aecd0a4c3.json index 02f8d5f..1f901b1 100644 --- a/.astra/tests/engine/.astra/cache/8c208151bed9108b665cd93e98fc10d377a9fef641dd359504b8d53aecd0a4c3.json +++ b/.astra/tests/engine/.astra/cache/8c208151bed9108b665cd93e98fc10d377a9fef641dd359504b8d53aecd0a4c3.json @@ -1,5 +1,5 @@ { - "result": "---\nid: wiki_on\ndate: 2026-08-06T01:30:04.066Z\ntype: knowledge_artifact\nstandard: P-Reinforce v3.0\ntags: [automated, connect_ai, brain_sync]\n---\n\n## 📌 Brief Summary\n직답 결과 — single-pass mock 응답입니다.\n\n직답 결과 — single-pass mock 응답입니다.\n---\n## 🛡️ Reliability & Audit Summary\n> [!NOTE]\n> 이 문서는 ConnectAI의 **Intelligent Resilience** 엔진에 의해 검증 및 정제되었습니다.\n\n| Metric | Value | Status |\n| :--- | :--- | :--- |\n| **Conflict Risk** | `0/100` | ✅ Low |\n| **Fallbacks Used** | `0` | ✅ None |\n| **Auto Retries** | `0` | ✅ Stable |\n| **Deduplication** | `0` | Standard |\n| **Processing Time** | `0.0s` | ✅ Fast |\n\n### 🔍 Decision Audit Trail\n- **[DIRECT]** 답변 작성 중... (단일 호출 fast-path) (27ms)\n", - "createdAt": 1785979804069, + "result": "---\nid: wiki_on\ndate: 2026-08-06T01:53:24.345Z\ntype: knowledge_artifact\nstandard: P-Reinforce v3.0\ntags: [automated, connect_ai, brain_sync]\n---\n\n## 📌 Brief Summary\n직답 결과 — single-pass mock 응답입니다.\n\n직답 결과 — single-pass mock 응답입니다.\n---\n## 🛡️ Reliability & Audit Summary\n> [!NOTE]\n> 이 문서는 ConnectAI의 **Intelligent Resilience** 엔진에 의해 검증 및 정제되었습니다.\n\n| Metric | Value | Status |\n| :--- | :--- | :--- |\n| **Conflict Risk** | `0/100` | ✅ Low |\n| **Fallbacks Used** | `0` | ✅ None |\n| **Auto Retries** | `0` | ✅ Stable |\n| **Deduplication** | `0` | Standard |\n| **Processing Time** | `0.0s` | ✅ Fast |\n\n### 🔍 Decision Audit Trail\n- **[DIRECT]** 답변 작성 중... (단일 호출 fast-path) (34ms)\n", + "createdAt": 1785981204345, "modelVersion": "unknown" } \ No newline at end of file diff --git a/.astra/tests/engine/.astra/missions/wiki_on.json b/.astra/tests/engine/.astra/missions/wiki_on.json index 812410b..b3a1958 100644 --- a/.astra/tests/engine/.astra/missions/wiki_on.json +++ b/.astra/tests/engine/.astra/missions/wiki_on.json @@ -1,8 +1,8 @@ { "missionId": "wiki_on", "status": "completed", - "startTime": "2026-08-06T01:30:04.033Z", - "totalElapsedMs": 39, + "startTime": "2026-08-06T01:53:24.307Z", + "totalElapsedMs": 40, "results": { "direct": "직답 결과 — single-pass mock 응답입니다." }, @@ -12,16 +12,16 @@ { "from": "idle", "to": "direct", - "durationMs": 27, + "durationMs": 34, "message": "답변 작성 중... (단일 호출 fast-path)", - "ts": "2026-08-06T01:30:04.060Z" + "ts": "2026-08-06T01:53:24.341Z" }, { "from": "direct", "to": "completed", - "durationMs": 11, + "durationMs": 6, "message": "미션 완료", - "ts": "2026-08-06T01:30:04.071Z" + "ts": "2026-08-06T01:53:24.347Z" } ], "resilienceMetrics": { diff --git a/.astra/tests/stress/.astra/cache/21818066876cbf8515758bc351bb3d9d44f32b0e4cd024b2e055db3a0d34417e.json b/.astra/tests/stress/.astra/cache/21818066876cbf8515758bc351bb3d9d44f32b0e4cd024b2e055db3a0d34417e.json index b1ec87d..95d2577 100644 --- a/.astra/tests/stress/.astra/cache/21818066876cbf8515758bc351bb3d9d44f32b0e4cd024b2e055db3a0d34417e.json +++ b/.astra/tests/stress/.astra/cache/21818066876cbf8515758bc351bb3d9d44f32b0e4cd024b2e055db3a0d34417e.json @@ -1,5 +1,5 @@ { "result": "Final report with inconsistencies. This should be long enough to pass validation.", - "createdAt": 1785979811217, + "createdAt": 1785981213594, "modelVersion": "unknown" } \ No newline at end of file diff --git a/.astra/tests/stress/.astra/cache/4fc755e372f1dd80d6bffc7b2ef973124fb64ba505f767c53a783833bbc3fa6a.json b/.astra/tests/stress/.astra/cache/4fc755e372f1dd80d6bffc7b2ef973124fb64ba505f767c53a783833bbc3fa6a.json index 9d9f791..5a47b21 100644 --- a/.astra/tests/stress/.astra/cache/4fc755e372f1dd80d6bffc7b2ef973124fb64ba505f767c53a783833bbc3fa6a.json +++ b/.astra/tests/stress/.astra/cache/4fc755e372f1dd80d6bffc7b2ef973124fb64ba505f767c53a783833bbc3fa6a.json @@ -1,5 +1,5 @@ { "result": "Final report with inconsistencies. This should be long enough to pass validation.", - "createdAt": 1785979811215, + "createdAt": 1785981213593, "modelVersion": "unknown" } \ No newline at end of file diff --git a/.astra/tests/stress/.astra/cache/6e559207c4542d959700ff14f360e6575e54853929e991e579e318f2f5a19030.json b/.astra/tests/stress/.astra/cache/6e559207c4542d959700ff14f360e6575e54853929e991e579e318f2f5a19030.json index 62a1855..6794516 100644 --- a/.astra/tests/stress/.astra/cache/6e559207c4542d959700ff14f360e6575e54853929e991e579e318f2f5a19030.json +++ b/.astra/tests/stress/.astra/cache/6e559207c4542d959700ff14f360e6575e54853929e991e579e318f2f5a19030.json @@ -1,5 +1,5 @@ { "result": "[{\"heading\":\"본문\",\"scope\":\"전체 답변\"}]", - "createdAt": 1785979811209, + "createdAt": 1785981213590, "modelVersion": "unknown" } \ No newline at end of file diff --git a/.astra/tests/stress/.astra/cache/f65136cebc95448a7e93a45745cb73b3a5a01af5d82391ec29a25bd72b8239a5.json b/.astra/tests/stress/.astra/cache/f65136cebc95448a7e93a45745cb73b3a5a01af5d82391ec29a25bd72b8239a5.json index f84c82f..d247028 100644 --- a/.astra/tests/stress/.astra/cache/f65136cebc95448a7e93a45745cb73b3a5a01af5d82391ec29a25bd72b8239a5.json +++ b/.astra/tests/stress/.astra/cache/f65136cebc95448a7e93a45745cb73b3a5a01af5d82391ec29a25bd72b8239a5.json @@ -1,5 +1,5 @@ { "result": "[CONFLICT WARNING] 성능이 200% 증가했습니다. vs 그러나 동시에 50% 감소했습니다. 최적화와 성능 저하가 동시에 발견됨.", - "createdAt": 1785979811212, + "createdAt": 1785981213592, "modelVersion": "unknown" } \ No newline at end of file diff --git a/.astra/tests/stress/.astra/missions/stress_conflict_1785979811195.json b/.astra/tests/stress/.astra/missions/stress_conflict_1785981213570.json similarity index 75% rename from .astra/tests/stress/.astra/missions/stress_conflict_1785979811195.json rename to .astra/tests/stress/.astra/missions/stress_conflict_1785981213570.json index c88548d..6ddcb5b 100644 --- a/.astra/tests/stress/.astra/missions/stress_conflict_1785979811195.json +++ b/.astra/tests/stress/.astra/missions/stress_conflict_1785981213570.json @@ -1,8 +1,8 @@ { - "missionId": "stress_conflict_1785979811195", + "missionId": "stress_conflict_1785981213570", "status": "completed", - "startTime": "2026-08-06T01:30:11.195Z", - "totalElapsedMs": 23, + "startTime": "2026-08-06T01:53:33.570Z", + "totalElapsedMs": 25, "results": { "outline": "[{\"heading\":\"본문\",\"scope\":\"전체 답변\"}]", "section_0": "[CONFLICT WARNING] 성능이 200% 증가했습니다. vs 그러나 동시에 50% 감소했습니다. 최적화와 성능 저하가 동시에 발견됨.", @@ -14,30 +14,30 @@ { "from": "idle", "to": "outline", - "durationMs": 13, + "durationMs": 19, "message": "답변 구조 잡는 중...", - "ts": "2026-08-06T01:30:11.208Z" + "ts": "2026-08-06T01:53:33.589Z" }, { "from": "outline", "to": "section", - "durationMs": 3, + "durationMs": 2, "message": "본문 작성 중...", - "ts": "2026-08-06T01:30:11.211Z" + "ts": "2026-08-06T01:53:33.591Z" }, { "from": "section", "to": "polish", - "durationMs": 3, + "durationMs": 1, "message": "최종 다듬기 중...", - "ts": "2026-08-06T01:30:11.214Z" + "ts": "2026-08-06T01:53:33.592Z" }, { "from": "polish", "to": "completed", - "durationMs": 4, + "durationMs": 3, "message": "미션 완료", - "ts": "2026-08-06T01:30:11.218Z" + "ts": "2026-08-06T01:53:33.595Z" } ], "resilienceMetrics": { diff --git a/PATCHNOTES.md b/PATCHNOTES.md index 8ef13ae..679d2ef 100644 --- a/PATCHNOTES.md +++ b/PATCHNOTES.md @@ -1,5 +1,12 @@ # Astra Patch Notes +## v2.2.322 (2026-08-05) +### 🛍️ 네이버 트렌드 — 구체적 모델명 제안 + ratio 라벨 명확화 +사용자 피드백: 인기 키워드 결과에 "노트북"처럼 카테고리명만 반복돼 실제 쓸 정보가 없음(구체적 모델까지 알고 싶음) + "클릭률"까지 보고 싶음. +- **구체적 상품/모델명 우선 제안**: `/naver-shopping`(scope=keywords) · `/naver-trend`(discover) 양쪽 프롬프트에 "categories 에 이미 들어간 분야명·상위 카테고리명 반복 금지, '맥북 에어 M3'처럼 브랜드+모델명 위주 제안, 여러 브랜드 혼합" 지시 추가. +- **클릭률(CTR) 불가 — 라벨 명확화**: 네이버 데이터랩 API(쇼핑인사이트·검색어트렌드 둘 다) 는 실제 클릭수/노출수 기반 CTR(%) 을 제공하지 않고 "구간 내 최댓값=100" 상대 지수만 준다. 표 헤더를 "ratio(0~100, 상대지수)"로, 디스클레이머에 "CTR 아님 — API 자체가 미제공"을 명시해 오해 방지. +검증: tsc 무오류 + jest 1015 통과(회귀 없음) + esbuild 정상. + ## v2.2.321 (2026-08-05) ### 🛍️ `/naver-shopping` "분야 안의 인기 검색어" 질문이 쓸모없는 1행 표만 주던 문제 수정 실사례: `/naver-shopping 디지털/가전 인기 검색어` → "디지털/가전" 분야 자체의 클릭 비율 1행짜리 표만 나와 사용자가 "쓸 수 있는 데이터가 없다"고 피드백. 원인: 쇼핑인사이트 API는 "분야 자체"의 클릭 추이만 제공하고, 분야 *안*에서 어떤 상품/검색어가 인기인지는 애초에 이 API로 알 수 없다(그런 API가 없음) — intentParser 가 "인기 검색어"라는 표현도 그냥 분야명 비교(compare)로 잘못 처리했다. diff --git a/package.json b/package.json index 0e6e094..442ac8e 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "astra", "displayName": "Astra", "description": "The personal intelligence layer for Antigravity and VS Code. A private cognitive partner for deep project context, memory, and proactive strategic decision-making.", - "version": "2.2.321", + "version": "2.2.322", "publisher": "g1nation", "license": "MIT", "icon": "assets/icon.png", diff --git a/src/features/naverTrend/handlers.ts b/src/features/naverTrend/handlers.ts index f331a26..1e74270 100644 --- a/src/features/naverTrend/handlers.ts +++ b/src/features/naverTrend/handlers.ts @@ -24,7 +24,7 @@ import type { CommonFilters, TimeUnit } from './naverApi'; type Webview = Parameters[0]; -const DISCLAIMER = '⚠️ 이 순위는 네이버 전체 실시간 인기 순위가 아니라, 후보군 내에서 실제 네이버 데이터랩 API로 검증한 상대 비교치입니다.'; +const DISCLAIMER = '⚠️ 이 순위는 네이버 전체 실시간 인기 순위가 아니라, 후보군 내에서 실제 네이버 데이터랩 API로 검증한 상대 비교치입니다. "ratio"는 조회 구간 내 최댓값을 100으로 둔 상대 지수이며, 실제 클릭수·노출수 기반 클릭률(CTR, %)이 아닙니다 — 네이버 데이터랩 API 자체가 CTR을 제공하지 않습니다.'; function ymd(d: Date): string { return d.toISOString().slice(0, 10); @@ -50,7 +50,7 @@ function buildFilters(intent: { device?: 'pc' | 'mo'; gender?: 'm' | 'f'; ages?: function formatRankedTable(result: RankedResult, itemLabel: string): string { if (result.items.length === 0) return '_(결과 없음)_\n'; const lines: string[] = []; - lines.push(`| # | ${itemLabel} | 최근 ratio |`); + lines.push(`| # | ${itemLabel} | 최근 ratio(0~100, 상대지수) |`); lines.push('|---|---|---|'); result.items.forEach((it, i) => { const label = it.path && it.path !== it.name ? `${it.name} _(${it.path})_` : it.name; diff --git a/src/features/naverTrend/intentParser.ts b/src/features/naverTrend/intentParser.ts index b81a1dd..2072d8f 100644 --- a/src/features/naverTrend/intentParser.ts +++ b/src/features/naverTrend/intentParser.ts @@ -148,6 +148,7 @@ const SHOPPING_SYSTEM_PROMPT = `당신은 네이버 쇼핑인사이트(분야별 - "mode": scope="category"일 때 — 구체적인 분야명을 하나 이상 언급했으면 "compare", "요즘 뜨는 분야가 뭐야"처럼 분야 자체를 탐색하고 싶으면 "discover". scope="keywords"면 항상 "discover". - "categories": scope="category"·mode="compare"면 사용자가 언급한 분야명 그대로(정규화 말고 원문 그대로) 배열로. scope="category"·mode="discover"면 후보 분야를 최대 9개 제안(3개씩 순차 조회하므로 3의 배수 권장). scope="keywords"면 사용자가 언급한 분야명(보통 1개)만 넣기. - "keywords": scope="keywords"일 때만 사용 — 그 분야 맥락에 맞는 검색어/상품 후보를 당신의 지식으로 최대 10개 제안(개별 순위를 매기려면 키워드 1개=API 그룹 1개라 5개씩 순차 조회함을 감안). scope="category"면 빈 배열. + ⚠️ **구체적인 상품/모델명 위주로 제안하세요** — "노트북", "이어폰"처럼 categories 에 이미 들어간 분야명이나 그 상위 카테고리명 자체를 반복하지 말 것(정보 가치 없음). 대신 "맥북 에어 M3", "그램 17 2024", "갤럭시북4 프로" 처럼 실제 검색될 법한 브랜드+모델/제품라인명을 제안. 특정 브랜드로 편중되지 않게 여러 브랜드를 섞을 것. ${COMMON_FIELDS_PROMPT} ⚠️ 반드시 아래 JSON 형식 정확히 한 번: @@ -206,6 +207,7 @@ const SEARCH_TREND_SYSTEM_PROMPT = `당신은 네이버 검색어트렌드 API - "mode": 사용자가 구체적인 검색어를 하나 이상 언급했으면 "compare". "인기 검색어"/"요즘 뜨는 키워드"/"top N" 처럼 키워드를 직접 지목하지 않고 탐색을 원하면 "discover". - "keywords": mode="compare"면 사용자가 언급한 검색어를 그대로 배열로. mode="discover"면 질문 맥락(주제/카테고리/타겟)에 맞는 검색어 후보를 당신의 지식으로 최대 10개 제안(개별 순위를 매기려면 키워드 1개=API 그룹 1개라 5개씩 순차 조회함을 감안). + ⚠️ 질문이 특정 상품군(가전/패션/뷰티 등)을 가리키면 그 상위 카테고리명 자체를 반복하지 말고 **구체적인 상품/모델명**(브랜드+제품라인명, 예: "맥북 에어 M3", "다이슨 에어랩")을 우선 제안 — 일반 명사만 나열하면 사용자가 얻을 정보가 없다. 여러 브랜드를 섞을 것. ${COMMON_FIELDS_PROMPT} - "ages" 값은 검색어트렌드 전용 코드(1=0~12세,2=13~18세,3=19~24세,4=25~29세,5=30~34세,6=35~39세,7=40~44세,8=45~49세,9=50~54세,10=55~59세,11=60세이상)를 사용하세요 — 쇼핑인사이트의 10/20/30 대 코드와 다릅니다.