From e900e4073fb885439bca96c4b5f7aae955aa9aca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=8F=E5=94=AF?= Date: Mon, 12 Oct 2026 21:38:01 +0800 Subject: [PATCH] =?UTF-8?q?GA-P0-7=20(t=5Fdd64345a):=20=E9=80=80=E5=BD=B9?= =?UTF-8?q?=E8=A3=B8=E8=B7=AF=E7=94=B1=20/api/v1/feedback=20=E5=86=99?= =?UTF-8?q?=E7=82=B9=EF=BC=88=E6=9B=BE=E5=86=99=E6=97=A7=20not=5Fuseful=5F?= =?UTF-8?q?count=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - server.go: 删 mux.HandleFunc("/api/v1/feedback", api.Feedback) 注册 - core.go: 删 Feedback handler(按 useful 写 useful_count/not_useful_count) - 回归守卫 server_route_guard_test.go: 断言裸路由不注册 + 4 子路由在 - tests/integration_test.sh: 反馈改走 /api/v1/feedback/useful - README.md: 裸路由文档改为拆分后 4 子路由 AC2 证伪无调用方:grep 'api/v1/feedback"' 仅命中自身注册行(现已删)。 AC3 退废后 not_useful_count 仅剩 schema/struct 向后兼容声明、[DEPRECATED] IncrementNotUseful(无路由调用)、迁移工具读、注释。 --- README.md | 5 ++- go/internal/api/routes/core.go | 31 ++---------------- go/internal/api/server.go | 3 +- go/internal/api/server_route_guard_test.go | 37 ++++++++++++++++++++++ tests/integration_test.sh | 5 ++- 5 files changed, 48 insertions(+), 33 deletions(-) create mode 100644 go/internal/api/server_route_guard_test.go diff --git a/README.md b/README.md index 3f1dcb1..4408eae 100644 --- a/README.md +++ b/README.md @@ -426,7 +426,10 @@ python3 -c "from plugins.memory.zhiyi import HermesZhiYiMemoryProvider; \ | POST | `/api/v1/recall` | 语义检索(支持 mode=hybrid\|keyword\|semantic) | | POST | `/api/v1/batch-commit` | 批量提交 | | GET | `/api/v1/memories` | 列出记忆(分页) | -| POST | `/api/v1/feedback` | 反馈(useful / not-useful / deprecate) | +| POST | `/api/v1/feedback/useful` | 标记记忆有用(GA-P0-1 写 human_useful) | +| POST | `/api/v1/feedback/not-useful` | 标记记忆无用(写 human_not_useful_count) | +| POST | `/api/v1/feedback/deprecate` | 标记过时 | +| POST | `/api/v1/feedback/correct` | 提交修正 | ### 统计 diff --git a/go/internal/api/routes/core.go b/go/internal/api/routes/core.go index 3490e1c..08aec90 100644 --- a/go/internal/api/routes/core.go +++ b/go/internal/api/routes/core.go @@ -558,34 +558,9 @@ func (a *API) Recall(w http.ResponseWriter, r *http.Request) { } } -// POST /api/v1/feedback — 用户反馈记忆是否有用,同时更新 useful_count/not_useful_count -func (a *API) Feedback(w http.ResponseWriter, r *http.Request) { - var req struct { - MemoryID string `json:"memory_id"` - Useful bool `json:"useful"` - } - if err := json.NewDecoder(r.Body).Decode(&req); err != nil { - respondError(w, 400, "invalid body") - return - } - if req.MemoryID == "" { - respondError(w, 400, "memory_id required") - return - } - field := "useful_count" - val := map[string]interface{}{"$inc": 1} - if !req.Useful { - field = "not_useful_count" - } - err := a.LanceDB.Update("memories", req.MemoryID, map[string]any{ - field: val, - }) - if err != nil { - respondError(w, 500, "feedback update failed: "+err.Error()) - return - } - respond(w, 200, map[string]string{"status": "ok"}) -} +// GA-P0-7 (t_dd64345a):裸 POST /api/v1/feedback handler 已删除——它按 useful 布尔写 +// useful_count / not_useful_count(后者是 P0-1 拆分的旧混写列)。反馈统一走 +// feedback.go 的 /api/v1/feedback/{useful,not-useful,deprecate,correct}(写 human_not_useful_count)。 // POST /api/v1/recall/debug — recall 诊断端点(优化),返回各阶段耗时和状态 func (a *API) RecallDebug(w http.ResponseWriter, r *http.Request) { diff --git a/go/internal/api/server.go b/go/internal/api/server.go index 85ad19f..90a5233 100644 --- a/go/internal/api/server.go +++ b/go/internal/api/server.go @@ -382,7 +382,8 @@ func NewServer() http.Handler { }) mux.HandleFunc("/api/v1/recall", api.Recall) mux.HandleFunc("/api/v1/recall/debug", api.RecallDebug) - mux.HandleFunc("/api/v1/feedback", api.Feedback) + // GA-P0-7 (t_dd64345a):裸 /api/v1/feedback 已退役——其 handler 曾写旧字段 not_useful_count。 + // 反馈统一走 /api/v1/feedback/{useful,not-useful,deprecate,correct}(feedback.go,写拆分后新字段)。 mux.HandleFunc("/api/v1/bootstrap", api.Bootstrap) mux.HandleFunc("/api/v1/stats", api.Stats) mux.HandleFunc("/api/v1/batch-commit", api.BatchCommit) diff --git a/go/internal/api/server_route_guard_test.go b/go/internal/api/server_route_guard_test.go new file mode 100644 index 0000000..8c3bfdc --- /dev/null +++ b/go/internal/api/server_route_guard_test.go @@ -0,0 +1,37 @@ +package api + +import ( + "os" + "strings" + "testing" +) + +// GA-P0-7 (t_dd64345a):回归守卫 —— 裸路由 /api/v1/feedback 已退役。 +// 它的 handler(core.go Feedback,已删)曾按 useful 布尔写旧字段 not_useful_count +// (P0-1 t_718d8707 已拆分为 human_not_useful_count / dedup_downweight_count)。 +// 谁若重新注册这个裸路由(旧字段随之复活),本测试必须红。 +func TestNoBareFeedbackRoute(t *testing.T) { + src, err := os.ReadFile("server.go") + if err != nil { + t.Fatalf("read server.go: %v", err) + } + s := string(src) + + // 裸路由注册必须不存在(精确匹配 server.go:385 的旧行)。 + bare := `mux.HandleFunc("/api/v1/feedback", api.Feedback)` + if strings.Contains(s, bare) { + t.Fatalf("裸 /api/v1/feedback 路由被重新注册——其 handler 写旧字段 not_useful_count(GA-P0-1);请改用 /api/v1/feedback/{useful,not-useful,deprecate,correct}") + } + + // 新拆分后的子路由必须在(反馈统一走它们,写 human_not_useful_count 等新字段)。 + for _, sub := range []string{ + `"/api/v1/feedback/useful"`, + `"/api/v1/feedback/not-useful"`, + `"/api/v1/feedback/deprecate"`, + `"/api/v1/feedback/correct"`, + } { + if !strings.Contains(s, sub) { + t.Fatalf("期望子路由 %s 已注册,但 server.go 中缺失", sub) + } + } +} \ No newline at end of file diff --git a/tests/integration_test.sh b/tests/integration_test.sh index a877ea9..fe19c8b 100755 --- a/tests/integration_test.sh +++ b/tests/integration_test.sh @@ -221,9 +221,8 @@ test_commit_recall_feedback() { if [[ -n "$memory_id" ]]; then log_info "步骤3: 反馈 (feedback)" local feedback_resp - feedback_resp=$(api_post "/api/v1/feedback" "{ - \"memory_id\": \"${memory_id}\", - \"useful\": true + feedback_resp=$(api_post "/api/v1/feedback/useful" "{ + \"memory_id\": \"${memory_id}\" }") log_info "feedback 响应: $feedback_resp"