Просмотр исходного кода

fix(plugin): 0.8.4 —— 不存在的词曾导致检索返回整个语料库

next 生产环境读端复测(20 项)时发现,是本项目最该防的那类静默错误:

    wikipali search --lemma zzzznotaword
    → ⚠ 已把词根「zzzznotaword」展开为 1 个词形:
    → 命中 496522 段

查无此词时,/v2/case 不是返回空 rows,而是返回**一个 case 为空的候选行**。
客户端把它当成命中,拼出空的 key 发给 search,服务端将空 key 当作「不限」,
于是整个语料库都成了「检索结果」。模型会拿这 49 万段当相关材料分析。

三处修:
- fetch_forms 过滤掉 case 为空的候选,0 词形等同于没找到;
- resolve_key 拒绝发出空 key;
- count 对查无此词显示「(语料中未见)」。

另修 404 提示:原文一律建议「切到最新版试试 wikipali endpoint next」,但在
next 上取未部署的 tipitaka-content 时也这么说,等于让人原地打转。改为列出三种
可能,并点明「已经在最新版站点上仍 404」意味着什么。

复测结论:next 上读端 20 项全过,含 ai-model-token 部署后新可用的 related
(无关联返回空集而非 500)与 books(tags 扩展)。tipitaka-content 在 next 上
仍未部署,chapter --fetch 会明确报 404,--via chapter-content 可正常回退。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
visuddhinanda 1 неделя назад
Родитель
Сommit
0baed1f332

+ 1 - 1
plugins/wikipali/.claude-plugin/plugin.json

@@ -1,7 +1,7 @@
 {
   "name": "wikipali",
   "description": "WikiPali 巴利三藏平台的客户端:检索与阅读语料做研究(词形展开、全文检索、出处分布、按坐标取原文与译本),以及以 AI 模型身份写入句子。",
-  "version": "0.8.3",
+  "version": "0.8.4",
   "author": {
     "name": "visuddhinanda",
     "url": "https://github.com/visuddhinanda"

+ 7 - 1
plugins/wikipali/lib/cmd_read.py

@@ -72,11 +72,14 @@ def emit(args, payload, render):
 
 
 def fetch_forms(client, word):
+    """展开词形。**0 个词形的候选等同于没找到**——服务端对查无此词会返回一个
+    case 为空的行,若把它当成命中,后续 search 会拿到空 key 而返回整个语料库。"""
     try:
         data = client.call('GET', f'v2/case/{word}', timeout=READ_TIMEOUT)
     except ApiError as exc:
         raise explain_api_error(exc, f'展开词形 {word}')
-    return (data or {}).get('rows') or []
+    rows = (data or {}).get('rows') or []
+    return [r for r in rows if r.get('case')]
 
 
 def cmd_forms(args):
@@ -159,10 +162,13 @@ def resolve_key(client, args):
         if not rows:
             raise WpError(f'「{args.lemma}」展不出任何词形。')
         key = forms_arg(rows[0])
+        if not key:
+            raise WpError(f'「{args.lemma}」展不出任何词形,无法检索。')
         note(f'⚠ 已把词根「{args.lemma}」展开为 {len(key.split(","))} 个词形:{key}')
         return key
     key = ','.join(part.strip() for item in args.forms for part in item.split(',') if part.strip())
     if not key:
+        # 空 key 会被服务端当成「不限」,返回整个语料库——决不能发出去
         raise WpError('没有给出词形。用 --lemma <词根> 自动展开,或直接给逗号分隔的词形。')
     return key
 

+ 4 - 3
plugins/wikipali/lib/errors.py

@@ -26,9 +26,10 @@ def explain_api_error(exc, what):
         return WpError(f"{what}:403 无权限(不是 channel 的 owner/协作者,或不是模型 owner 本人)。")
     if exc.status == 404:
         return WpError(
-            f"{what}:404。若这是较新的端点,可能是当前站点跑的是稳定版代码、端点尚未上线;\n"
-            "  可切到最新版试试:wikipali endpoint next\n"
-            "  否则才是资源真的不存在。"
+            f"{what}:404。三种可能,别只当成「资源不存在」:\n"
+            "  1. 该端点尚未部署到当前站点——各站代码版本不同,用 wikipali endpoint 换一个再试;\n"
+            "  2. **已经在最新版站点上仍 404**,说明它还没部署到任何站点,或本就没有这个端点;\n"
+            "  3. 才是资源真的不存在。"
         )
     if exc.status == 409:
         return WpError(f"{what}:409 同名记录已存在。")