From b91b704c74ff764102e6d7d0322c7c955f7a8abb Mon Sep 17 00:00:00 2001 From: "yoyo-evolve[bot]" Date: Sat, 22 Aug 2026 12:04:41 +0000 Subject: [PATCH] yoyo: remove flat-directory fallback from getOnDiskSlugs (closes #902) - Delete fallback block that scanned wiki dir for .md files - Return [] when page-index is absent (silo is sole storage layer) - Remove unused imports: getStorage, FileEntry, wikiRelPath - Update lint-checks tests to expect [] without page-index - Seed page-index in lint, maintenance, and mcp tests that relied on fallback --- src/lib/__tests__/lint-checks.test.ts | 8 +++---- src/lib/__tests__/lint.test.ts | 29 +++++++++++++++++++++++++- src/lib/__tests__/maintenance.test.ts | 10 ++++++++- src/lib/__tests__/mcp.test.ts | 12 ++++++++++- src/lib/lint-checks.ts | 30 ++++++--------------------- 5 files changed, 58 insertions(+), 31 deletions(-) diff --git a/src/lib/__tests__/lint-checks.test.ts b/src/lib/__tests__/lint-checks.test.ts index 3d84639b..2f970266 100644 --- a/src/lib/__tests__/lint-checks.test.ts +++ b/src/lib/__tests__/lint-checks.test.ts @@ -84,7 +84,7 @@ describe("getOnDiskSlugs", () => { expect(slugs.sort()).toEqual(["alpha", "beta"]); }); - it("returns slugs from .md files excluding index.md and log.md (fallback)", async () => { + it("returns empty array when page-index is absent even if .md files exist", async () => { const wikiDir = process.env.WIKI_DIR!; await fs.writeFile(path.join(wikiDir, "alpha.md"), "# Alpha\n\nContent"); await fs.writeFile(path.join(wikiDir, "beta.md"), "# Beta\n\nContent"); @@ -92,7 +92,7 @@ describe("getOnDiskSlugs", () => { await fs.writeFile(path.join(wikiDir, "log.md"), "# Log\n\n- entry"); const slugs = await getOnDiskSlugs(); - expect(slugs.sort()).toEqual(["alpha", "beta"]); + expect(slugs).toEqual([]); }); it("returns empty array when directory does not exist", async () => { @@ -100,7 +100,7 @@ describe("getOnDiskSlugs", () => { expect(slugs).toEqual([]); }); - it("ignores non-.md files (fallback)", async () => { + it("returns empty array when page-index is absent regardless of file types on disk", async () => { const wikiDir = process.env.WIKI_DIR!; await fs.writeFile(path.join(wikiDir, "page.md"), "# Page\n\nContent"); await fs.writeFile(path.join(wikiDir, "readme.txt"), "Not a wiki page"); @@ -108,7 +108,7 @@ describe("getOnDiskSlugs", () => { await fs.writeFile(path.join(wikiDir, ".hidden"), "secret"); const slugs = await getOnDiskSlugs(); - expect(slugs).toEqual(["page"]); + expect(slugs).toEqual([]); }); it("returns empty array for an empty directory", async () => { diff --git a/src/lib/__tests__/lint.test.ts b/src/lib/__tests__/lint.test.ts index 64ba17d6..5eb05134 100644 --- a/src/lib/__tests__/lint.test.ts +++ b/src/lib/__tests__/lint.test.ts @@ -4,7 +4,7 @@ import os from "os"; import path from "path"; import { writeWikiPage, updateIndex, ensureDirectories, readLog } from "../wiki"; import type { IndexEntry } from "../types"; -import { _resetStorage } from "../storage"; +import { _resetStorage, getStorage } from "../storage"; // Mock the LLM module so lint never calls the real API vi.mock("../llm", () => ({ @@ -90,6 +90,9 @@ describe("lint", () => { { slug: "hello", title: "Hello", summary: "A greeting page" }, ]; await updateIndex(entries); + await getStorage().putIndex("pages", { + "hello": { slug: "hello", title: "Hello", summary: "A greeting page" }, + }); const result = await lint(); @@ -109,6 +112,9 @@ describe("lint", () => { ); // Create an empty index with no entries await updateIndex([]); + await getStorage().putIndex("pages", { + "orphan": { slug: "orphan", title: "Orphan", summary: "s" }, + }); const result = await lint(); const orphanIssues = result.issues.filter((i) => i.type === "orphan-page"); @@ -140,6 +146,9 @@ describe("lint", () => { { slug: "empty", title: "Empty Page", summary: "Barely anything here" }, ]; await updateIndex(entries); + await getStorage().putIndex("pages", { + "empty": { slug: "empty", title: "Empty Page", summary: "Barely anything here" }, + }); const result = await lint(); const emptyIssues = result.issues.filter((i) => i.type === "empty-page"); @@ -164,6 +173,10 @@ describe("lint", () => { { slug: "beta", title: "Beta Topic", summary: "Beta page" }, ]; await updateIndex(entries); + await getStorage().putIndex("pages", { + "alpha": { slug: "alpha", title: "Alpha", summary: "Alpha page" }, + "beta": { slug: "beta", title: "Beta Topic", summary: "Beta page" }, + }); const result = await lint(); const crossRefIssues = result.issues.filter( @@ -277,6 +290,10 @@ describe("lint", () => { { slug: "neural-network", title: "Neural Network", summary: "NN page" }, ]; await updateIndex(entries); + await getStorage().putIndex("pages", { + "intro": { slug: "intro", title: "Intro", summary: "Intro page" }, + "neural-network": { slug: "neural-network", title: "Neural Network", summary: "NN page" }, + }); const result = await lint(); const crossRefIssues = result.issues.filter( @@ -905,6 +922,10 @@ Every page must start with a level-1 heading. { slug: "transformer", title: "Transformer", summary: "Test" }, { slug: "bert", title: "BERT", summary: "Test" }, ]); + await getStorage().putIndex("pages", { + "transformer": { slug: "transformer", title: "Transformer", summary: "Test" }, + "bert": { slug: "bert", title: "BERT", summary: "Test" }, + }); const result = await lint(); const conceptIssues = result.issues.filter( @@ -989,6 +1010,9 @@ Every page must start with a level-1 heading. await updateIndex([ { slug: "linker", title: "Linker", summary: "Test" }, ]); + await getStorage().putIndex("pages", { + "linker": { slug: "linker", title: "Linker", summary: "Test" }, + }); const result = await lint(); const brokenLinkIssues = result.issues.filter( @@ -1069,6 +1093,9 @@ describe("lint with LintOptions", () => { { slug: "ghost", title: "Ghost", summary: "Does not exist on disk" }, ]; await updateIndex(entries); + await getStorage().putIndex("pages", { + "orphan-only": { slug: "orphan-only", title: "Orphan Only", summary: "s" }, + }); const result = await lint({ checks: ["orphan-page"] }); diff --git a/src/lib/__tests__/maintenance.test.ts b/src/lib/__tests__/maintenance.test.ts index 5b45ef73..535f512c 100644 --- a/src/lib/__tests__/maintenance.test.ts +++ b/src/lib/__tests__/maintenance.test.ts @@ -12,7 +12,7 @@ import { import { createThread, addComment } from "../talk"; import { scanForMaintenance, rebuildDerivedIndexes } from "../maintenance"; import { listCommonsPages } from "../commons"; -import { _resetStorage } from "../storage"; +import { _resetStorage, getStorage } from "../storage"; let tmpDir: string; const saved: Record = {}; @@ -241,6 +241,10 @@ describe("scanForMaintenance", () => { path.join(wikiDir, "orphan-page.md"), "# Orphan\n\nThis page exists on disk but is not in the index.", ); + await getStorage().putIndex("pages", { + "indexed-page": { slug: "indexed-page", title: "indexed-page", summary: "s" }, + "orphan-page": { slug: "orphan-page", title: "Orphan", summary: "s" }, + }); const tasks = await scanForMaintenance(); expect(tasks).toContainEqual({ kind: "maintain", @@ -334,6 +338,10 @@ describe("scanForMaintenance", () => { logOp: "ingest", crossRefSource: null, }); + await getStorage().putIndex("pages", { + "artificial-intelligence": { slug: "artificial-intelligence", title: "Artificial Intelligence", summary: "s" }, + "machine-learning": { slug: "machine-learning", title: "Machine Learning", summary: "s" }, + }); const tasks = await scanForMaintenance(); expect(tasks).toContainEqual({ kind: "maintain", diff --git a/src/lib/__tests__/mcp.test.ts b/src/lib/__tests__/mcp.test.ts index 6eafd7f7..46abb251 100644 --- a/src/lib/__tests__/mcp.test.ts +++ b/src/lib/__tests__/mcp.test.ts @@ -53,7 +53,7 @@ import { } from "../../mcp"; import { vaultIdFor, listVaults, getVault, createVault } from "../vault"; import { readWikiPageWithFrontmatter } from "../wiki"; -import { _resetStorage } from "../storage"; +import { _resetStorage, getStorage } from "../storage"; import { _resetConfigCache } from "../config"; import { parseFrontmatter } from "../frontmatter"; import { registerAgent } from "../agents"; @@ -2496,6 +2496,11 @@ describe("lint_wiki", () => { ); await writeIndex([]); // empty index + // Seed page-index so getOnDiskSlugs() sees the orphan page + await getStorage().putIndex("pages", { + "orphan-page": { slug: "orphan-page", title: "Orphan Page", summary: "s" }, + }); + const result = await handleLintWiki({ checks: ["orphan-page"] }); expect(result.issues.length).toBeGreaterThanOrEqual(1); const orphanIssues = result.issues.filter((i) => i.type === "orphan-page"); @@ -4782,6 +4787,11 @@ describe("maintenance_scan", () => { ); await writeIndex([]); // empty index → orphan-maint is an orphan + // Seed page-index so getOnDiskSlugs() sees the orphan page + await getStorage().putIndex("pages", { + "orphan-maint": { slug: "orphan-maint", title: "Orphan Maintenance", summary: "s" }, + }); + const result = await handleMaintenanceScan({}); expect(result).toHaveProperty("tasks"); expect(Array.isArray(result.tasks)).toBe(true); diff --git a/src/lib/lint-checks.ts b/src/lib/lint-checks.ts index dbd60d2a..8a69afa0 100644 --- a/src/lib/lint-checks.ts +++ b/src/lib/lint-checks.ts @@ -1,6 +1,4 @@ -import { getStorage } from "./storage"; -import type { FileEntry } from "./storage"; -import { readWikiPage, readWikiPageWithFrontmatter, listWikiPages, wikiRelPath } from "./wiki"; +import { readWikiPage, readWikiPageWithFrontmatter, listWikiPages } from "./wiki"; import { hasLLMKey, callLLM } from "./llm"; import { loadPageConventions } from "./schema"; import { extractWikiLinks } from "./links"; @@ -38,35 +36,19 @@ export const INFRASTRUCTURE_FILES = new Set(["index.md", "log.md"]); /** * Get all content page slugs known to the system. * - * Primary path: read from the `_idx:pages` page-index (O(1) KV read), which - * aligns lint with the silo-primary read path used by `readWikiPage` / - * `listWikiPages`. - * - * Fallback (page-index not yet seeded): list `.md` files from the flat wiki - * directory, excluding infrastructure files. This preserves correct orphan / - * stale-index detection before the first `rebuildPageIndex()` run. - * + * Reads from the `_idx:pages` page-index (O(1) KV read), which aligns lint + * with the silo-primary read path used by `readWikiPage` / `listWikiPages`. + * Returns `[]` when the page-index is absent or unreadable. */ export async function getOnDiskSlugs(): Promise { try { const idx = await getPageIndex(); if (idx) return Object.keys(idx); } catch (err) { - logger.warn("lint", "page-index read failed; falling back to listFiles", err); - } - - // Fallback: list flat wiki directory - let entries: FileEntry[]; - try { - entries = await getStorage().listFiles(wikiRelPath("")); - } catch (err) { - logger.warn("lint", "listFiles wiki directory failed:", err); - return []; + logger.warn("lint", "page-index read failed", err); } - return entries - .filter((e) => e.name.endsWith(".md") && !INFRASTRUCTURE_FILES.has(e.name)) - .map((e) => e.name.replace(/\.md$/, "")); + return []; } /**