Skip to content

fix(index): publish honest HNSW verification (successor to #180) - #197

Closed
PeterGuy326 wants to merge 2 commits into
mainfrom
codex/fix-pr-180
Closed

PeterGuy326 wants to merge 2 commits into
mainfrom
codex/fix-pr-180

Conversation

@PeterGuy326

@PeterGuy326 PeterGuy326 commented Sep 10, 2026

Copy link
Copy Markdown
Collaborator

Refs #173.

Scope after platform review

Index foundation only: migration 0025 cosine HNSW on embeddings_text / embeddings_visual / embeddings_face, fail-closed verification, and honest docs. Shipping text search still uses DISTINCT ON and does not claim planner use.

Per #197 (comment) (xiaocui-big / 平台组): index DDL quality is mergeable; text planner HOLD is correct and must not be weakened to go green. Planner integration stays on #173 (keep that issue open).

Rebase

Rebased onto main at 884b54d (#109). The lexical commit was already on main via #194 and was skipped. Remaining commits:

Head: 95af9fe8b8436006b30faf2366e890a374969ce7

Not in this PR

Fresh CI on this exact head is required after the rebase. CODEOWNER approval is still required; last pusher is waterbro-8 so that account will not self-approve.

@sun-970

sun-970 commented Sep 11, 2026

Copy link
Copy Markdown
Contributor

Review Summary

Thanks for the thorough and honest verification work — the counterexample evidence and explicit documentation of the text planner limitation are genuinely valuable.

A few issues found:

1. Migration number references are wrong (Bug)

The HNSW indexes live in migration 0025, but two comments say "migration 0024":

  • server/internal/db/migrations/0001_init.sql line 109: -- HNSW index on embedding column is in migration 0024. → should be 0025
  • server/internal/face/face.go line 14: // The HNSW index (migration 0024) → should be 0025

The PR description itself says "#183 owns 0024" and this PR is 0025, so these are clearly typos.

2. Broken link to MIGRATION_SEQUENCE.md

docs/VALIDATION_HNSW.md links to [cumulative migration sequence](MIGRATION_SEQUENCE.md), but that file is not created in this PR. If it lives in another PR/branch, please note that; otherwise this will be a 404.

3. set -euo pipefail conflicts with pass/fail accumulation in verify script

scripts/verify_hnsw_indexes.sh uses set -e but also has a pass/fail counter pattern. With set -e, any unexpected failure (e.g. a psql error) will exit immediately rather than accumulating failures. The final [[ "$fail" -eq 0 ]] check becomes unreachable when a mid-script command fails.

Consider either:

  • Removing set -e and relying on the explicit final check, or
  • Wrapping the loop body in || true to prevent early exit

4. HNSW build parameters undocumented

All three indexes use pgvector defaults (m=16, ef_construction=64) without comment. For the 768-d text embeddings, it would help future maintainers to note why defaults are acceptable or when to revisit them (e.g., "defaults are fine up to ~100k rows; beyond that, increase ef_construction to 128+").

Minor / Nits

  • The verify script embeds $CORPUS_USER directly into SQL strings. The UUID regex guard makes this safe in practice, but worth a -- comment noting the validation precondition.
  • Consider CREATE INDEX CONCURRENTLY for the HNSW indexes if these tables are expected to have data at migration time — a regular CREATE INDEX takes an exclusive lock. If the convention is to build indexes on empty tables or offline, a comment would clarify.

What looks good

  • The validation doc is exemplary — clearly states what PASS means, what FAIL means, and what is NOT VERIFIED.
  • The counterexample design (101 near chunks from one file vs. ef_search=40 budget) is a concrete and reproducible way to demonstrate the deduplication underfill problem.
  • Migration up/down is clean and symmetric.
  • The assert_plan function using EXPLAIN (ANALYZE, BUFFERS) (which actually executes) is much stronger than plain EXPLAIN.

@waterbro-8 waterbro-8 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code review(draft,给作者的修改清单,非批准)

先说我为什么信这份:它最有价值的地方不是加了三个索引,而是它自己把没达成的验收标准写清楚了,并且拒绝为了变绿而放宽标准。这个下面单独说。

一、动已应用的迁移 0001 / 0019 —— 查过了,是安全的

这是看到 diff 的第一反应(改已应用迁移通常是红线)。逐一核过:

  • 0001_init.sql 那处:删掉两行 -- HNSW index will be added by worker... 注释,换成一行注释。
  • 0019_versioned_index_generations.sql 那处:同样只是把"将来要怎么做"的注释,改成"已经在哪做了"。
  • 整个 diff 里新增的 DDL 只有 0025 里的三个 CREATE INDEX。0001 / 0019 的 hunk 内不含任何 CREATE / ALTER
  • 另外确认 main 上没有迁移的校验和/完整性测试(verify.sh 只用 goose validate 和版本号断言,不比对文件内容哈希),所以改注释不会触发"迁移被篡改"的判定。

结论:是安全的注释更新,不是改历史 schema。

二、docs/VALIDATION_HNSW.md 里那段"剩余验收边界",我认为是这份 PR 最好的部分

它明说:加了索引不等于#173 达成。现行的 text 查询是"先按 file 做 DISTINCT ON、再全局 top-k",这个形状 planner 用不上 HNSW。于是它给出了:

  • 一个可回滚的反例(2000 文件合成语料,把某个文件的 101 个近邻 chunk 与其余 1999 个分开,默认 ef_search=40):shipping 查询返回 10 个文件,索引化的 anti-join 只返回 1 个——因为 HNSW 扫出 40 个候选 chunk,其中 39 个在 per-file 去重时被吃掉。
  • 一个独立的精确距离反例,证明固定的过采样倍数救不了:某个文件占掉 81 个最近 chunk 时,8*k=80 个候选全被它吃掉,去重后只剩 1 个文件。
  • 明确写出"未改动基线不等于豁免"(an unchanged baseline is not a waiver),并且没有调弱任何 planner 设置或验收标准。

这段的价值在于:它把一个"看起来加个索引就完事"的改动,如实降级成"索引已就绪、但 shipping 查询尚未受益"。请保持这个姿态,不要为了让 verify_hnsw_indexes.sh 变绿而删掉它。

顺带一个我需要点明的结论:这条 PR 落地后 #173 仍然不该被关掉——索引在,但 shipping text 路由不走它,验收标准未达成。这跟你的文档一致,我只是把它说得更明确一点,免得合并时被当成"#173 已完成"。

三、必须改的一条:三处注释写的是 0024,实际是 0025

HNSW 索引在 0025_ann_hnsw_indexes.sql0024 是 #194 的 lexical search 迁移(你自己的 VALIDATION_HNSW.md 第 22 行就写对了:"Migration 0024 belongs to #183 and 0026 to #185")。但三处代码/迁移注释指错了地方:

位置 现在写的 应为
server/internal/db/migrations/0001_init.sql(替换后的那行注释) migration 0024 migration 0025
server/internal/db/migrations/0019_...sql are in migration 0024 are in migration 0025
server/internal/face/face.go(包注释) The HNSW index (migration 0024) is available... migration 0025

这不是排版问题:0024 在部署序列里排在 0025 之前,而注释说"HNSW 在 0024",将来有人按部署顺序排查"为什么 0024 之后还没有 HNSW 索引"就会误判。而且它和同一份 PR 里的文档自相矛盾。三处各改一个数字。

四、其余几点(非阻塞)

  • scripts/verify_hnsw_indexes.sh 的设计是对的:只读、强制库名以 _test 结尾、校验索引的 amname='hnsw'indisvalidvector_cosine_ops、并且要求语料里真有非 NULL 向量(rows -gt 0)——否则空表建索引也会"通过",那就什么都没证明。用 EXPLAIN (ANALYZE, BUFFERS) 而不是只 EXPLAIN,能让读路径真的执行、向量/模式错误藏不住。没有 SET enable_seqscan = off,这点很诚实。
  • text 那条探针刻意复刻了 runTextANN 的形状(DISTINCT ON (f.id) 在前),不是拿一个 ORDER BY distance LIMIT 糊弄过去——这跟文档里"简单探针证明不了这条查询用了索引"的说法是一致的。
  • face 索引没有 shipping 查询,文档也这么写了(当前聚类是 Go 里的 O(n))。所以它的证据只是"DDL 合法 + 表里有数据",不是"脸检索变快了"。我不认为这是问题,但请保持文档里这句,别让人误会。
  • EXPECTED_MIGRATION_HEAD 25 与新增 0025 一致。注意这条分支还带着 #194 的 0024(VALIDATION_HNSW.md 说部署顺序 #194#197#195),所以 25 是建立在这条链完整的前提上的——如果 #194 没先落地,这里的 25 就不成立

五、我没有声称验证的事

我没在本机跑 PostgreSQL + pgvector,文档里那些 planner/反例结论我没有复现,我核对的是它们是否与代码一致、以及是否有"为变绿而放宽标准"的痕迹——没有。合并前请以真实 MEM_TEST_DB 上的结果为准。

(本次为独立评审:我不是本 PR 作者,也不是其 head 的推送者。draft 状态下我不投批准票,以上清单改完后我再来复评。)

sun-970 pushed a commit to sun-970/mem that referenced this pull request Sep 17, 2026
…ytefolk#197)

Three comments referenced "migration 0024" for the HNSW index, but 0024
is the lexical search migration from bytefolk#194. The HNSW indexes live in 0025.
Fix the number in 0001_init.sql, 0019_versioned_index_generations.sql and
face.go.

@PeterGuy326 PeterGuy326 left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Current-head follow-up review at fdccb43:

The three previous blocking documentation errors are fixed: 0001_init.sql, 0019_versioned_index_generations.sql, and face.go now all point to migration 0025. The HNSW validation script remains fail-closed and syntactically valid; affected local Go tests passed.

The current CI failure is an infrastructure/image pull failure (minio/minio denied), not a failure in the HNSW code path. However, this PR is still Draft and the shipping text planner acceptance is explicitly unmet: the current DISTINCT ON query still does not use HNSW safely while preserving result semantics. Therefore this is not an approval or merge recommendation. Keep #173 open/HOLD, restore green exact-head CI, and resolve the text planner acceptance before requesting final approval.

@sun-970

sun-970 commented Sep 17, 2026

Copy link
Copy Markdown
Contributor

Review Summary

Status: Fix Required 🔧

Found one issue causing CI failure:

Problem

TestTextANNFileSemanticsPostgres fails with:

ERROR: inconsistent types deduced for parameter $1 (SQLSTATE 42P08)

The test SQL at line 61 uses $1::text to cast the UUID parameter to text for storage_key, but $1 is already used as a UUID in the first position. PostgreSQL cannot deduce a consistent type.

Fix

Created PR #218 with the fix: use separate parameters instead of casting.

-- Before:
VALUES($1,$2,'fixture', $3,0,'fixture',$4,$1::text,$5,$5)

-- After:  
VALUES($1,$2,'fixture',$3,0,'fixture',$4,$5,$6,$6)

Once #218 is merged into this branch, CI should pass. The HNSW migration and index creation logic itself looks correct.

waterbro-8 pushed a commit that referenced this pull request Sep 17, 2026
#218)

Refs #197

Fixes the failing PostgreSQL integration test in #197.

## Problem

`TestTextANNFileSemanticsPostgres` fails with:
```
ERROR: inconsistent types deduced for parameter $1 (SQLSTATE 42P08)
```

The test SQL uses `$1::text` to cast a UUID parameter to text for the
`storage_key` column, but `$1` is already used as a UUID in the first
position. PostgreSQL cannot deduce a consistent type for the parameter.

## Solution

Use separate parameters for the UUID and its text representation instead
of casting:
```sql
-- Before:
VALUES($1,$2,'fixture', $3,0,'fixture',$4,$1::text,$5,$5)

-- After:
VALUES($1,$2,'fixture',$3,0,'fixture',$4,$5,$6,$6)
```

Where `$5` is `id.String()` (the text representation) and `$6` is the
timestamp.

## Validation

- [x] Fix resolves the type deduction error
- [ ] CI passes on this PR
- [ ] Can be cherry-picked into #197

This is a minimal fix for the test infrastructure, not a change to the
HNSW migration or search logic.

Co-authored-by: liyuanyang <liyuanyang@users.noreply.github.com>
waterbro-8 pushed a commit that referenced this pull request Sep 17, 2026
)

## Linked draft successor — original #183 remains open

Refs #176.

## Current follow-up: `c0421168bd145077bf164f91c0d2b454a79760ef`

- Fixed the remaining exported MCP route enum: `tools/list` now includes
`lexical`. The in-process MCP regression reproduced the missing enum
before the fix and now verifies both schema and `tools/call` HTTP
forwarding. All 9 MCP tests pass on Linux; affected-package vet passes.
- Added a strict, populated PostgreSQL sequential-upgrade regression and
a DB-free embedded-migration continuity guard. Actual PostgreSQL 16.14 /
pgvector 0.8.2 advances 23 → 24, verifies lexical backfill and full
history, and accepts ordinary production startup afterward. No
`AllowMissing` option or migration renumbering.
- Cumulative source/base order is #194#197#195. #197 remains HOLD
for text-query planner acceptance; #195 remains HOLD behind it. See
`docs/MIGRATION_SEQUENCE.md` for deployment and existing-gap recovery
boundaries.
- Tests ran at `2f2e965b6794863d7f5a38a748262da4691beb35`; this final
head only corrects the documented verification command to
`scripts/verify.sh integration`. Fresh exact-head CI and independent
review remain required. The earlier evidence below is historical, not a
fresh-head approval.

Preserves @sun-970 / liyuanyang's complete authored chain through
`13ebe9efa6ba3c733199d374e8db3d107f598ca2` for #176. This draft makes
the bounded reviewed corrections accessible; it does not replace
independent review, CI, or human approval. Do not close #183 before a
replacement is verified and merged.

The original fork's Git-data write returned HTTP 404 and its repository
permissions report `push:false`. No ACL override was attempted. This
canonical branch preserves original commit identities and hashes. Added
blobs, trees, and commits were checked against local Git hashes; no
force update was used.

## Corrections

- `scripts/verify.sh`: expect migration 24, matching this branch's
lexical migration. The former expectation of 23 caused the PostgreSQL
validation failure.
- Refresh audited Web development dependencies, traceable to #192 commit
`11e02e21ef2c3dbd2dae26e4376872e54e78ecb5` via a separate `cherry-pick
-x` commit. Audit threshold unchanged.
- No additional search/ranking changes beyond original #183.

## Validation at head `3d885a8427e06fd7175011ef0188a06f32028a3f`

- PASS: migration to 24 on PostgreSQL 16.14 / pgvector 0.8.2 and
PostgreSQL 17.10 / pgvector 0.8.3.
- PASS: `TestLexicalSearchWithoutWorker`, five cases: lexical without
worker, text/auto fail closed, CJK trigram, path restriction. Go tests
cross-compiled for Linux and executed against real disposable PostgreSQL
with `GOMAXPROCS=2` and serial package builds.
- PASS: audited lockfile check; shared fix from #192 remains explicit,
not attributed to this feature.
- NOT CLAIMED: provider-backed vector retrieval or production benchmark
quality.
- REQUIRED: fresh CI on this exact head and independent review.
Original-head CI/review is not approval of this draft.

Original feature scope: model-free file-corpus lexical route, migration
0024, API/CLI/docs, managed-provider bypass. Scope excludes tokenizer,
generation lifecycle, and ranking redesign.
Base automatically changed from codex/fix-pr-183 to main September 17, 2026 16:10
@waterbro-8

Copy link
Copy Markdown
Collaborator

#218 (the 42P08 $1::text fixture fix) is squash-merged into this branch. Re-run CI on the new head.

I am not approving #197 yet: the PR still marks text-planner acceptance as HOLD, and this is in the #194#197#195 sequence. #194 is now on main. After CI is green on the post-#218 head, this still needs a CODEOWNER other than the author to approve the HNSW verification itself.

@waterbro-8

Copy link
Copy Markdown
Collaborator

#218 的 42P08 测试修复已 squash 进本分支。

本 PR 仍标 planner HOLD,且与 main 可能冲突。请 @PeterGuy326 在 CI 绿且 HOLD 解除后再找非作者 CODEOWNER 批,不要现在合。

@xiaocui-big

Copy link
Copy Markdown

平台组 Review(崔泽生,assigned by @冯浩然)

逐文件核过 diff,结论:索引基础部分质量过关,可以合;text planner HOLD 是正确的判断,不应为了变绿而放宽。

一、索引 DDL 与迁移——没有问题

  • 三个 CREATE INDEX ... USING hnsw (embedding vector_cosine_ops)search.go / relator.go<=> 的操作符类一致。
  • 0025 的 Down 顺序正确(先 face → visual → text),与 Up 对称。
  • 事务性 CREATE INDEX 会阻塞写入——文档里已写明需要维护窗口,没有假装 CONCURRENTLY。这是诚实的。
  • 0001 / 0019 的改动纯注释,waterbro-8 核过无校验和依赖,安全。
  • 三处 migration 0025 引用(0001、0019、face.go)已修正,与 VALIDATION_HNSW.md 自洽。
  • EXPECTED_MIGRATION_HEAD=25 与新增 0025 对齐。

二、text planner HOLD——同意,且补充一个可行方向

runTextANNDISTINCT ON (f.id) ORDER BY f.id, e.embedding <=> $1 形状,pgvector 的 HNSW 扫不出 per-file best chunk——这是 pgvector 本身没有 "nearest per group" 原语的限制,不是 SQL 重写能简单绕过的。VALIDATION_HNSW.md 里的两个反例(101 chunk 文件吃掉 39/40 候选、81 chunk 文件吃掉 80/80 候选)已经证明固定过采样倍数救不了,这个论证是完备的。

可行方向(供后续 issue 参考,不阻塞本 PR):

两阶段查询——Phase 1 用 HNSW 拿 K*OVERSAMPLE 候选 chunk,在 SQL 里 DISTINCT ON (file_id) 取每个 file 的最近 chunk;若去重后文件数 < K,以更大 OVERSAMPLE 重试(上限 1 次),仍不足则 fallback 到当前精确扫。伪代码:

WITH candidates AS (
  SELECT DISTINCT ON (e.file_id)
    e.file_id, e.embedding <=> $1::vector AS dist
  FROM embeddings_text e
  WHERE e.file_id IN (SELECT id FROM files WHERE user_id = $2 AND ...)
  ORDER BY e.file_id, e.embedding <=> $1::vector
  LIMIT $3  -- K * OVERSAMPLE
)
SELECT ... ORDER BY dist LIMIT $4  -- K

关键约束:

  • OVERSAMPLE 不能是固定常数(反例已证),需要动态重试 + 有界 fallback
  • Phase 1 的 file_id 过滤必须先缩小到 eligible set,否则 HNSW 候选仍会被 ineligible 文件吃掉
  • 需要真实语料(非合成)的 recall 对比才能验收

这个设计变更应独立成 issue,不在 #197 范围。

三、合并阻塞项

状态
waterbro-8 的 0024→0025 修正 ✅ 已修
#218 的 42P08 测试修复 ✅ 已 squash 进
CI 21/21 ✅ 全绿
与 main 的 merge conflict(behind 4 commits) ❌ 需 rebase
text planner HOLD ⏸️ 正确,不阻塞索引基础合并

建议:rebase 到 main 后即可合。text planner 集成拆成后续 issue(#173 保持 open 跟踪)。本 PR 合入后 #173 的"索引基础"子项完成,剩余"查询规划器集成"作为独立交付。

四、未声称验证的事

同 waterbro-8:我没有在本机跑 PostgreSQL + pgvector 复现反例。我核对的是 diff 与文档的一致性、以及是否有"为变绿而放宽标准"的痕迹——没有。

PeterGuy326 and others added 2 commits September 18, 2026 04:56
#218)

Refs #197

Fixes the failing PostgreSQL integration test in #197.

## Problem

`TestTextANNFileSemanticsPostgres` fails with:
```
ERROR: inconsistent types deduced for parameter $1 (SQLSTATE 42P08)
```

The test SQL uses `$1::text` to cast a UUID parameter to text for the
`storage_key` column, but `$1` is already used as a UUID in the first
position. PostgreSQL cannot deduce a consistent type for the parameter.

## Solution

Use separate parameters for the UUID and its text representation instead
of casting:
```sql
-- Before:
VALUES($1,$2,'fixture', $3,0,'fixture',$4,$1::text,$5,$5)

-- After:
VALUES($1,$2,'fixture',$3,0,'fixture',$4,$5,$6,$6)
```

Where `$5` is `id.String()` (the text representation) and `$6` is the
timestamp.

## Validation

- [x] Fix resolves the type deduction error
- [ ] CI passes on this PR
- [ ] Can be cherry-picked into #197

This is a minimal fix for the test infrastructure, not a change to the
HNSW migration or search logic.

Co-authored-by: liyuanyang <liyuanyang@users.noreply.github.com>
@waterbro-8

Copy link
Copy Markdown
Collaborator

Rebase 完成(按平台组结论)

对照 https://github.com/bytefolk/mem/pull/197#issuecomment-5724905145:索引基础可以合;text planner HOLD 保持;#173 不关。

已做

没有改 runTextANN,没有把 DISTINCT ON 改成“为了用上 HNSW”的不安全重写。

还不能合的原因

状态
与 main 冲突 ✅ 已 rebase
本 head 的 CI ⏳ 刚 push,等 verify
CODEOWNER 正式 Approve ❌ 仍 REVIEW_REQUIRED。平台组评论是结论,不是 GitHub Approve。xiaocui-big 不在 CODEOWNERS。
自批/自合 不做。本账号是最后一次 push,且是 CODEOWNER,不能给自己的 last-push 当批准。

@PeterGuy326@Bindy-lbb 在本 head 上 Approve。CI 绿且 Approve 后即可 squash 合。合入后 #173 保持 open,只把“索引基础”记完成,planner 集成另跟。

重叠 PR:#219 也含 0025 + text continuation。#197 合入前不要合 #219;合入后 #219 需要丢掉重复 DDL,只留 planner(且平台组要求真实语料 recall,不是合成 fixture)。

@waterbro-8

Copy link
Copy Markdown
Collaborator

崔泽生平台组 review:索引基础可合,text planner HOLD 应保留,不要为变绿放宽。同意。

本 PR 与 main 冲突,rebase 需要作者 @PeterGuy326。合入后 #173 仍应保持 open(shipping text 还不走 HNSW)。

#219 是另一条「改查询形状」的后续,不替代本 PR 的索引 DDL;按崔泽生的边界,#197 先合索引,planner 另开。

@waterbro-8

Copy link
Copy Markdown
Collaborator

Rebase 后 CI(本 head 95af9fe

verify / security 已全部完成,21/21 pass。含:

完整列表:https://github.com/bytefolk/mem/actions/runs/35308941782https://github.com/bytefolk/mem/actions/runs/35308941834

mergeable=MERGEABLE,但仍 REVIEW_REQUIRED / BLOCKED。已请 @Bindy-lbb review(作者 PeterGuy326 不能被 request)。waterbro-8 不会自批自合。

Approve 之后即可 squash 合。#173 保持 open。

@waterbro-8
waterbro-8 enabled auto-merge (squash) September 18, 2026 05:05
waterbro-8 added a commit that referenced this pull request Sep 18, 2026
## Summary

Completes the work [#213](#213) left
undone against [#173](#173).

- Migration **0025** (0024 is already lexical from #194) adds cosine
HNSW indexes on `embeddings_text` (768), `embeddings_visual` (512), and
`embeddings_face` (512) with `vector_cosine_ops`.
- Shipping **text** search no longer uses `DISTINCT ON (f.id) ORDER BY
f.id, distance` as the primary plan. That shape cannot use HNSW. It now
walks `ORDER BY embedding <=> $1 LIMIT n`, keeps the first sighting of
each file, excludes selected files, and **falls back** to the original
exact `DISTINCT ON` query if a bounded scan underfills (one file owning
many near chunks).
- Relator text neighbors use the same continuation/fallback.
- Visual already matched HNSW. Face clustering stays in-process; the
face index is DDL only.
- `index_generation_vectors` is not indexed (scope boundary).
- Transactional `CREATE INDEX` (not `CONCURRENTLY`): a failed concurrent
build leaves an `INVALID` index that `IF NOT EXISTS` will skip.
- Wrong dimensions fail at the `vector(N)` column. Recall is **not**
claimed; harness is [#175](#175).

Does not reopen #213. #197 remains the earlier HOLD attempt; this branch
is based on current `main` (schema 24) and takes 0025.

## Changes

- `server/internal/db/migrations/0025_ann_hnsw_indexes.sql`
- `server/internal/search/search.go` — text continuation + exact
fallback
- `server/internal/relator/relator.go` — same policy
- `TestHNSWMigrationPostgres` — populated 24→25→24→25, ingest, dimension
rejection, EXPLAIN
- `TestTextANNFileSemanticsPostgres` — 101-chunk file still returns 10
eligible files
- `scripts/verify_hnsw_indexes.sh` + `scripts/verify.sh` head 25
- `docs/VALIDATION_HNSW.md`, SPEC, CHANGELOG

## Validation ledger

| ID | Criterion | Command | Status |
| --- | --- | --- | --- |
| V1 | Server builds, unit contracts | `make test-server` | Pending CI
(sandbox has Go 1.22; module requires 1.25) |
| V2 | Worker | `make test-worker` | Not affected |
| V3 | Web | `make test-web` | Not affected |
| V4 | Race | `make test-race` | Pending CI |
| V5 | Fresh schema, rollback, PostgreSQL | `make test-integration` |
Pending CI — `EXPECTED_MIGRATION_HEAD=25`; `TestHNSWMigrationPostgres` +
`verify_hnsw_indexes.sh` |
| V6 | DB race | `make test-integration-race` | Pending CI |
| V7–V9 | Acceptance / MCP / visual quality | — | Not affected |
| V10 | Recall | `make test-recall` | Not measured. Recorded harness:
#175 |
| Text semantics | 101-chunk file still yields k files |
`TestTextANNFileSemanticsPostgres` | Pending CI |
| Planner | EXPLAIN uses HNSW for text cosine-order and visual |
`TestHNSWMigrationPostgres` + `scripts/verify_hnsw_indexes.sh` | Pending
CI. No `enable_seqscan=off`. |

Local sandbox could not run Docker or download Go 1.25, so EXPLAIN was
not executed here. CI `memory-validation.yml` / `verify.sh integration`
is the evidence path.

## Design notes

- Defaults `m=16`, `ef_construction=64`. No iterative-scan GUC.
- Empty `uuid[]` exclude lists are never sent as SQL NULL (`ANY(NULL)`
would drop all rows).
- Editing 0001/0019 is comment-only. Goose does not checksum like
Flyway.

Fixes #173

---------

Co-authored-by: waterbro-8 <318569545+waterbro-8@users.noreply.github.com>
@waterbro-8
waterbro-8 disabled auto-merge September 18, 2026 09:31
@waterbro-8

Copy link
Copy Markdown
Collaborator

关闭:索引基础已被 #219 取代。

#219 已于 2026-09-18 把 migration 0025 cosine HNSW 合进 main(含 text continuation/fallback)。本 PR 的 DDL 切片与 main 冲突且重复。平台组当时的「rebase 后合索引基础、planner HOLD」已被 #219 覆盖。

#173 继续 open 跟踪 planner 度量/真实语料;不要把本关闭当成 #173 完成。

后续:#195(HOLD behind 本 PR)改为相对 main 评估 0026/cursor 是否还独立有价值。

@waterbro-8 waterbro-8 closed this Sep 18, 2026
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.

4 participants