From cdecfe662d55ee1ff9cd3cad25ad23fe33183c6e Mon Sep 17 00:00:00 2001 From: Claude Lin & Lay Date: Tue, 13 Oct 2026 00:36:49 +0900 Subject: [PATCH 1/2] docs(search): say when to pass the repo filter MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add one sentence to the repo parameter description, README table and requirements doc: pass repo whenever the question is about a known repository, and leave it unset only for cross-repository questions. #275 の開発試験で、repo 指定が別プロジェクト資料の混入を防いだため、いつ使うかを毎回読まれる説明文に置く。既定値と検索挙動は変えない。 Refs #277 Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01GYtSBq9rYuBcTNmr473APb --- README.md | 2 +- docs/0-requirements.md | 2 +- src/search-contract.ts | 4 +++- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 7f6b74c..7fbcb5b 100644 --- a/README.md +++ b/README.md @@ -129,7 +129,7 @@ Bot-authored comments (`sender.login` ending in `[bot]`) and comments shorter th | Name | Type | Description | |------|------|-------------| | `query` | string (optional) | Natural-language query. Omit or empty = scan mode. | -| `repo` | string | Filter by repository — full slug (`owner/repo`), exact match. A bare repository name matches nothing; search mode reports that as `"repo"` in the response's `filters_unmatched`. | +| `repo` | string | Filter by repository — full slug (`owner/repo`), exact match. A bare repository name matches nothing; search mode reports that as `"repo"` in the response's `filters_unmatched`. Pass it whenever the question is about a known repository — without it, a near-duplicate from another repository can rank first; leave it unset only when the question spans repositories. | | `path_prefix` | string | Filter docs by repository-relative directory prefix. Requires `type: "doc"`, a trailing `/`, and at most 64 UTF-8 bytes. | | `state` | `"open"` \| `"closed"` \| `"all"` | Filter by state (default `all`). | | `labels` | string[] | Filter by label names (AND). | diff --git a/docs/0-requirements.md b/docs/0-requirements.md index 64cd50b..9a58ecc 100644 --- a/docs/0-requirements.md +++ b/docs/0-requirements.md @@ -525,7 +525,7 @@ Returns: - `same_entity` on results that absorbed other rows of the same entity (see Entity Aggregation); `top_k` counts entities, not rows - top-level metadata: `fusion`, `dense_candidates`, `sparse_candidates`, `rerank_requested`, `rerank_applied`, `filters_unmatched` -**Unmatched filters (`filters_unmatched`).** `repo` takes the full slug (`owner/repo`) and matches exactly — on the dense side as a Vectorize metadata `$eq`, on the sparse side as `d.repo = ?`. `path_prefix` selects doc rows whose repository-relative path begins with the named directory prefix. A bare repository name or a path prefix that selects no doc row therefore produces a response shaped exactly like a genuine zero-hit search. `filters_unmatched` separates the two: it is always present in search mode, `[]` means every applied filter selected a non-empty population (so `count: 0` really is "no hits"), and a listed name means that filter's population is empty — the value is wrong, not the query. +**Unmatched filters (`filters_unmatched`).** `repo` takes the full slug (`owner/repo`) and matches exactly — on the dense side as a Vectorize metadata `$eq`, on the sparse side as `d.repo = ?`. `path_prefix` selects doc rows whose repository-relative path begins with the named directory prefix. A bare repository name or a path prefix that selects no doc row therefore produces a response shaped exactly like a genuine zero-hit search. `filters_unmatched` separates the two: it is always present in search mode, `[]` means every applied filter selected a non-empty population (so `count: 0` really is "no hits"), and a listed name means that filter's population is empty — the value is wrong, not the query. The tool description tells the caller when to pass `repo`: whenever the question is about a known repository, since without it a near-duplicate from another repository can rank first, and to leave it unset only when the question spans repositories. The default stays unfiltered so cross-repository questions keep working. The distinction is worth a field because agentic multi-step search inverts the cost of a silent zero. In a single search a zero is a dead end the caller inspects; in a search loop it is a normal intermediate result ("nothing down this angle") that the caller consumes and moves past, so the mis-specified filter never surfaces and one query out of the budget is spent on a false negative. diff --git a/src/search-contract.ts b/src/search-contract.ts index de6d15c..8911ec0 100644 --- a/src/search-contract.ts +++ b/src/search-contract.ts @@ -15,7 +15,9 @@ export const searchInputSchema = z.object({ .describe( "Filter by repository — full slug (owner/repo), exact match. " + "A bare repository name (\"my-repo\") matches nothing and yields an empty result set; " + - "search mode flags that case as \"repo\" in the response's filters_unmatched.", + "search mode flags that case as \"repo\" in the response's filters_unmatched. " + + "Pass it whenever the question is about a known repository: without it, a near-duplicate from another repository can rank first. " + + "Leave it unset only when the question spans repositories.", ), path_prefix: z .string().max(256) From 5e1d73ecdb3ebe9623bd35ebac53690af68519dc Mon Sep 17 00:00:00 2001 From: Claude Lin & Lay Date: Tue, 13 Oct 2026 00:38:25 +0900 Subject: [PATCH 2/2] build(search): regenerate bridge search schema MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Regenerate mcp-server/server/search-schema.json from the updated repo parameter description so the schema drift check matches. ブリッジ側のスキーマを生成し直し、説明文の変更を反映した。 Refs #277 Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01GYtSBq9rYuBcTNmr473APb --- mcp-server/server/search-schema.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mcp-server/server/search-schema.json b/mcp-server/server/search-schema.json index b0e212e..f3103cf 100644 --- a/mcp-server/server/search-schema.json +++ b/mcp-server/server/search-schema.json @@ -9,7 +9,7 @@ "maxLength": 4096 }, "repo": { - "description": "Filter by repository — full slug (owner/repo), exact match. A bare repository name (\"my-repo\") matches nothing and yields an empty result set; search mode flags that case as \"repo\" in the response's filters_unmatched.", + "description": "Filter by repository — full slug (owner/repo), exact match. A bare repository name (\"my-repo\") matches nothing and yields an empty result set; search mode flags that case as \"repo\" in the response's filters_unmatched. Pass it whenever the question is about a known repository: without it, a near-duplicate from another repository can rank first. Leave it unset only when the question spans repositories.", "type": "string", "maxLength": 256 },