Skip to content

Commit 6cc55f3

Browse files
fix: reset watermarks and all table hashes on admin reset-hashes (#49)
The previous implementation only reset body_hash in the issues table. Without clearing watermarks (ETag + since), the poller skips repos with no detected changes, so existing issues/releases/docs were never re-embedded after a metadata index rebuild. - src/store.ts: rename resetBodyHashes -> resetForReEmbed; also reset release body_hash, delete all docs rows (blob_sha reset), and delete all three watermark namespaces (issues, releases:{repo}, docs:{repo}) so the poller re-fetches from scratch on next cron run; return structured summary {issueHashesReset, releaseHashesReset, docsDeleted, watermarksDeleted} instead of a single count - src/index.ts: update comment to describe full reset scope - docs/0-requirements.md: update Admin API section with full reset description and structured response schema watermark を削除しないと ETag/since によるスキップが残り、既存 issue/release/doc が 再 embedding されないバグを修正。releases/docs のハッシュ・行も合わせてリセットする。 Refs #47 Co-authored-by: liplus-lin-lay <liplus-lin-lay@users.noreply.github.com> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent f7472dc commit 6cc55f3

3 files changed

Lines changed: 69 additions & 16 deletions

File tree

‎docs/0-requirements.md‎

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -197,14 +197,29 @@ Flow:
197197

198198
#### `POST /admin/reset-hashes?repo=owner/repo`
199199

200-
指定リポジトリの全 issue/PR の bodyHash を空文字にリセットする。
201-
次回 cron 実行時にハッシュ不一致を検出して全件再 embedding が行われる。
200+
指定リポジトリの全データを re-embedding 対象にリセットする。次回 cron 実行時に全件が再取得・再 embedding される。
201+
202+
リセット対象:
203+
- `issues` テーブルの `body_hash` を空文字にリセット(ポーラーがハッシュ不一致を検出して再 embedding)
204+
- `releases` テーブルの `body_hash` を空文字にリセット(同上)
205+
- `docs` テーブルの全行を削除(ポーラーが全ファイルを再取得・再 embedding)
206+
- `watermarks` テーブルから当該リポジトリの全エントリを削除(issues 用 `{repo}`、releases 用 `releases:{repo}`、docs 用 `docs:{repo}`)
207+
- watermark 削除により、ETag / `since` パラメータによるスキップが無効化され、ポーラーが全件を再取得する
202208

203209
認証: `GITHUB_TOKEN` ヘッダーの値が Worker の `GITHUB_TOKEN` シークレットと一致すること。
204210

205211
用途: Vectorize メタデータインデックス作成後の既存ベクトル再 upsert トリガー。
206212

207-
レスポンス: `{ "repo": "owner/repo", "reset": N }` (N = リセットされた行数)
213+
レスポンス:
214+
```json
215+
{
216+
"repo": "owner/repo",
217+
"issueHashesReset": N,
218+
"releaseHashesReset": M,
219+
"docsDeleted": K,
220+
"watermarksDeleted": W
221+
}
222+
```
208223

209224
### 5. Authentication
210225

@@ -237,7 +252,7 @@ wrangler vectorize create-metadata-index github-rag-issues --type string --prope
237252
```
238253

239254
インデックス作成後、既存ベクトルを再 upsert する必要がある。
240-
admin エンドポイント(`POST /admin/reset-hashes?repo=owner/repo`、`GITHUB_TOKEN` ヘッダー認証)で bodyHash をリセットすると、次回 cron 実行時に全件が再 embedding される。
255+
admin エンドポイント(`POST /admin/reset-hashes?repo=owner/repo`、`GITHUB_TOKEN` ヘッダー認証)で bodyHash・watermark をリセットすると、次回 cron 実行時に全件が再取得・再 embedding される。
241256

242257
参照: https://developers.cloudflare.com/vectorize/reference/metadata-filtering/
243258

‎src/index.ts‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
* Routes (defaultHandler, no OAuth token required):
1313
* GET /oauth/authorize -- Start GitHub OAuth flow
1414
* GET /oauth/callback -- GitHub OAuth callback
15-
* POST /admin/reset-hashes?repo=owner/repo -- Reset bodyHashes to trigger re-embedding (requires GITHUB_TOKEN header)
15+
* POST /admin/reset-hashes?repo=owner/repo -- Reset hashes and watermarks to trigger full re-embedding (requires GITHUB_TOKEN header)
1616
*
1717
* Durable Objects:
1818
* RagMcpAgent -- MCP server (tools: search_issues, get_issue_context, list_recent_activity)
@@ -56,8 +56,9 @@ const innerHandler: ExportedHandler<Env> = {
5656
async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise<Response> {
5757
const url = new URL(request.url);
5858

59-
// -- Admin: reset body hashes to trigger re-embedding on next cron --
59+
// -- Admin: reset hashes and watermarks to trigger full re-embedding on next cron --
6060
// POST /admin/reset-hashes?repo=owner/repo
61+
// Resets: issue body_hash, release body_hash, docs (deleted), and all watermarks for the repo.
6162
// Requires GITHUB_TOKEN header for authentication.
6263
if (request.method === "POST" && url.pathname === "/admin/reset-hashes") {
6364
const authHeader = request.headers.get("GITHUB_TOKEN");

‎src/store.ts‎

Lines changed: 47 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -421,19 +421,56 @@ export class IssueStore implements DurableObject {
421421
);
422422
}
423423

424-
// ---- Hash reset for re-sync ----
424+
// ---- Full re-embed reset ----
425425

426426
/**
427-
* Reset all bodyHashes for a given repo so that the next poll
428-
* will regenerate embeddings for every issue.
429-
* Returns the number of rows affected.
427+
* Reset all state that controls re-embedding so that the next poll
428+
* will regenerate embeddings for every issue, release, and doc in the repo.
429+
*
430+
* Resets:
431+
* - body_hash in issues table (cleared to '' so poller detects change)
432+
* - body_hash in releases table (cleared to '' so poller detects change)
433+
* - blob_sha in docs table (deleted rows so poller re-fetches all files)
434+
* - Watermark entries for issues, releases, and docs (deleted so poller
435+
* re-fetches from the beginning, bypassing ETag / since skipping)
436+
*
437+
* Returns a summary object with counts of what was reset.
430438
*/
431-
resetBodyHashes(repo: string): number {
432-
const cursor = this.sql.exec(
439+
resetForReEmbed(repo: string): {
440+
issueHashesReset: number;
441+
releaseHashesReset: number;
442+
docsDeleted: number;
443+
watermarksDeleted: number;
444+
} {
445+
const issuesCursor = this.sql.exec(
433446
`UPDATE issues SET body_hash = '' WHERE repo = ? AND body_hash != ''`,
434447
repo,
435448
);
436-
return cursor.rowsWritten;
449+
450+
const releasesCursor = this.sql.exec(
451+
`UPDATE releases SET body_hash = '' WHERE repo = ? AND body_hash != ''`,
452+
repo,
453+
);
454+
455+
const docsCursor = this.sql.exec(
456+
`DELETE FROM docs WHERE repo = ?`,
457+
repo,
458+
);
459+
460+
// Delete all three watermark namespaces: issues (repo), releases (releases:{repo}), docs (docs:{repo})
461+
const watermarksCursor = this.sql.exec(
462+
`DELETE FROM watermarks WHERE repo IN (?, ?, ?)`,
463+
repo,
464+
`releases:${repo}`,
465+
`docs:${repo}`,
466+
);
467+
468+
return {
469+
issueHashesReset: issuesCursor.rowsWritten,
470+
releaseHashesReset: releasesCursor.rowsWritten,
471+
docsDeleted: docsCursor.rowsWritten,
472+
watermarksDeleted: watermarksCursor.rowsWritten,
473+
};
437474
}
438475

439476
// ---- Watermark management ----
@@ -578,12 +615,12 @@ export class IssueStore implements DurableObject {
578615
return Response.json(items);
579616
}
580617

581-
// POST /reset-hashes?repo=... — reset all bodyHashes for a repo to force re-embedding
618+
// POST /reset-hashes?repo=... — reset all hashes and watermarks for a repo to force re-embedding
582619
if (request.method === "POST" && path === "/reset-hashes") {
583620
const repo = url.searchParams.get("repo");
584621
if (!repo) return new Response("missing repo", { status: 400 });
585-
const count = this.resetBodyHashes(repo);
586-
return Response.json({ repo, reset: count });
622+
const summary = this.resetForReEmbed(repo);
623+
return Response.json({ repo, ...summary });
587624
}
588625

589626
// GET /watermark?repo=... — get poll watermark

0 commit comments

Comments
 (0)