Files
waggle-os/docs/plans/WIKI-V2-AUDIT-2026-04-20.md
Oleg Maslov 0c3e2ead3b
Some checks failed
Installer Smoke / installer-smoke (push) Has been cancelled
moving
2026-09-02 10:10:29 +02:00

9.2 KiB

Wiki v2 Audit — 2026-04-20 (M-11..14)

Scope: Same audit-first pattern that cut M-33..48 from ~5 d to ~1 hr and M-07..10 from 24 hr to ~16 hr of real new code. Verify each sub-item against current source before committing to the 4-day backlog estimate.

Sub-item disposition

Item Spec Engine Route UI Verdict Build est.
M-11 Incremental post-harvest hook → recompile(changedFrameIds) WikiCompiler.compile({incremental: true}) — watermark-based, skips entity pages that no new frames mention POST /api/wiki/compile takes {mode: 'incremental'} WikiTab compile button 90% done — only the post-harvest auto-trigger hook is missing ~30 min
M-12 Obsidian Writer producing .md + YAML frontmatter + [[wikilinks]] 🟡 Page .markdown already has frontmatter + body; slugs exist; but no filesystem writer, no [[wikilink]] transform no export endpoint no UI trigger 25% done — page shape is right; needs writer + link transform + route + UI ~4-6 hr
M-13 Notion Adapter uses Notion API; map entity/concept/synthesis to Notion blocks nothing — notion-connector.ts in agent/src is READ-only (ingest), not write no export endpoint no UI trigger 0% done — genuinely new code; needs Notion API client, markdown-to-block converter, OAuth plumbing ~1 d
M-14 Health dashboard UI: coverage %, orphaned entities, stale pages, recent compile 🟡 Engine produces orphan_entity + missing_page + weak_confidence issues but NO stale_page check despite the type being defined; dataQualityScore covers quality but not coverage % GET /api/wiki/health 🟡 WikiTab renders score + totals + issues list, but no coverage %, no stale breakout, compile timestamp buried 70% done — backend misses stale_page check; UI needs coverage + stale polish ~2 hr

Total revised: ~2 d (vs. 4 d backlog estimate — 50% reduction).

M-13 Notion is the single biggest remaining commitment and the only sub-item with no prior art. It also requires a design decision on OAuth surface (reuse notion-connector.ts's OAuth plumbing, or use a separate write-scope token?).

Detailed evidence

M-11 — Incremental recompilation

packages/wiki-compiler/src/compiler.ts:395-455 shows a fully working watermark-based incremental compile:

async compile(options?: { incremental?: boolean; concepts?: string[] }) {
  const incremental = options?.incremental ?? true;
  const watermark = this.state.getWatermark();

  for (const entity of entities) {
    if (incremental && watermark.lastFrameId > 0) {
      const existingPage = this.state.getPage(slugify(entity.name));
      if (existingPage) {
        const newFrames = this.state.getFramesSince(watermark.lastFrameId, 100);
        const mentionsEntity = newFrames.some(f =>
          f.content.toLowerCase().includes(entity.name.toLowerCase())
        );
        if (!mentionsEntity) { pagesUnchanged++; continue; }
      }
    }
    // ... compile entity page ...
  }
}

POST /api/wiki/compile at packages/server/src/local/routes/wiki.ts:45-68 already passes mode through. WikiTab calls it from a button.

Single remaining gap: the post-harvest route (packages/server/src/local/routes/harvest.ts commit handler) does NOT fire /api/wiki/compile after a successful import. The user currently has to click the compile button manually, so a just-harvested batch of frames doesn't show up in the wiki until they remember to do that.

Fix: After the cognify block in the commit route, trigger a best- effort incremental compile via direct function call (not HTTP — we're already inside the server). The compile is non-blocking for the response and should fail-soft if the synthesizer has no LLM.

M-12 — Obsidian adapter

The page shape is already right:

// packages/wiki-compiler/src/types.ts:25-34
export interface WikiPage {
  slug: string;
  frontmatter: WikiPageFrontmatter;  // YAML-serializable
  markdown: string;                    // already includes frontmatter
  contentHash: string;
}

But there's no packages/wiki-compiler/adapters/ directory. Pages live in the wiki_pages SQLite table (CompilationState.upsertPage) and get read by the server routes. There's nothing iterating them to disk.

What Obsidian needs:

  1. A writer that iterates state.getAllPages(), writes each ${slug}.md to a configured output directory.
  2. A transform pass on markdown body: convert internal links ([entity-name](/wiki/slug) form if any) to [[slug]] syntax.
  3. An index file (_index.md or similar) listing all pages by type.
  4. Preserve YAML frontmatter as-is (Obsidian reads it natively).
  5. A new route POST /api/wiki/export/obsidian { outDir }.
  6. A button in WikiTab.

Inspecting current markdown to see if internal links already exist:

grep -n '](/' packages/wiki-compiler/src/compiler.ts  # look for link emissions

(none) — current markdown uses entity names as headers, not internal links. So the wikilink transform step may be minimal (just wrap related-entity bullets into [[slug]]).

M-13 — Notion structured export

Zero prior art. packages/agent/src/connectors/notion-connector.ts exists but is strictly ingest-side (reads pages from Notion into memory).

What Notion needs:

  1. @notionhq/client npm dep — currently not present.
  2. Credential flow. Options:
    • Reuse agent's notion-connector OAuth (designed for read scope — may need broadened scope for writes).
    • Add a separate Notion write token in Vault (notion-write-token).
  3. Markdown → Notion blocks converter. The markdown shape is simple (H1/H2/H3, lists, paragraphs, tables) so this is ~150 LOC.
  4. Parent page ID configuration — Notion requires a parent page to create under. Onboarding question: "Which Notion page should I write your wiki to?"
  5. Iterate pages, create child pages, map page types to block color tags (entity=blue, concept=amber, synthesis=purple per existing WikiTab conventions).
  6. Handle re-runs: update existing pages (via page_id cache) rather than create duplicates. Needs a wiki_pages.notion_page_id column.
  7. A route + UI.

This is easily a full day and involves real external API coupling + user-level auth decisions. It's the right candidate to defer out of this audit-execute pass and get Marko's design input on before building.

M-14 — Health dashboard polish

Backend: WikiCompiler.compileHealth() at compiler.ts:295-391 produces:

  • missing_page issues (entity with >2 relations and no page)
  • weak_confidence issues (page with <2 sources)
  • orphan_entity issues (entity with no relations at all)
  • A data quality score 0-100 combining entity/frame/page presence + issue severity deductions

Not produced: stale_page issues — despite HealthIssueType listing them. Pages older than a threshold (e.g. 30 days since last compile while new frames exist) should trigger this.

Not produced: coverage % — pages ÷ entities above a min-relations threshold. Currently only shown as raw counts.

UI (WikiTab.tsx:264-305) renders the score, three stat cards (frames, entities, pages), and the issues list. What it doesn't show:

  • Coverage ratio (pages / compilable-entities).
  • Stale-page count (once the backend computes it).
  • Prominent "Last compiled Xm ago" timestamp (currently buried per-page in the list).

Fix:

  1. Add stale_page check in compileHealth() — compare page compiledAt vs current new frames mentioning the entity.
  2. Extend the stats row in the UI: add coverage % and stale count.
  3. Add a "Last compile: N time ago" chip next to the score.
  1. M-11 post-harvest hook (~30 min) — immediate demo value: harvest → wiki pages appear automatically. Tiny change, one try/catch block added to the harvest commit route.
  2. M-14 polish (~2 hr) — health.ts gets stale_page check; UI gets coverage + stale breakout. No new design needed.
  3. M-12 Obsidian writer (~4-6 hr) — new adapter file + route + WikiTab export button + round-trip tests. High value for Obsidian-using knowledge workers; Marko's target power user persona.
  4. M-13 Notiondefer to next session. Needs a spec call:
    • Reuse agent's OAuth or separate write-scope token?
    • Onboarding flow for parent-page selection?
    • wiki_pages.notion_page_id migration for re-run updates?

Why this order

  • M-11 unlocks M-12 and M-13 downstream — both of those become more valuable once pages are always current.
  • M-14 polish is mostly visible work; makes the "real wiki" case visible to demo viewers.
  • M-12 Obsidian is the biggest demo win for sophisticated users without any external API dependency; ship it before asking for a design decision on Notion.
  • M-13 Notion needs a synchronous Marko design input so it's a bad fit for autonomous execution.

Decision needed

My pick: execute 1→2→3 in this session, write a decision-needed memo for M-13 and defer it. This closes ~75% of the M-11..14 block in <1 d real work against a 4 d budget.


Author: Claude (audit per Marko's S2-locked M-07..10 → M-11..14 sequence)