* One-shot upgrade heal for callers that open the graph WITHOUT syncing — * concretely the prompt hook, whose MEDIUM tier reads the segment * vocabulary: a database migrated from before the vocab table existed * starts with it empty, and the only other backfill lives inside `sync()`, * w
()
| 1425 | * holds the index lock — that process's own sync heals it). |
| 1426 | */ |
| 1427 | async healSegmentVocabIfEmpty(): Promise<boolean> { |
| 1428 | const empty = (() => { |
| 1429 | try { return this.queries.isNameSegmentVocabEmpty(); } catch { return false; } |
| 1430 | })(); |
| 1431 | if (!empty) return true; |
| 1432 | if (this.queries.getNodeAndEdgeCount().nodes === 0) return false; |
| 1433 | return this.indexMutex.withLock(async () => { |
| 1434 | try { |
| 1435 | this.fileLock.acquire(); |
| 1436 | } catch { |
| 1437 | return false; // an index/sync is running — it backfills the vocab itself |
| 1438 | } |
| 1439 | try { |
| 1440 | if (!this.queries.isNameSegmentVocabEmpty()) return true; // raced: healed meanwhile |
| 1441 | await this.rebuildNameSegmentVocab(); |
| 1442 | return true; |
| 1443 | } finally { |
| 1444 | this.fileLock.release(); |
| 1445 | } |
| 1446 | }); |
| 1447 | } |
| 1448 | |
| 1449 | /** |
| 1450 | * Rebuild the segment vocabulary from the current graph, batched and |
no test coverage detected