Back to catalog

wiki-ingest-qa

Quality assurance for automated wiki ingestion pipelines — wikilink verification, subagent timeout recovery, log consolidation. Companion to youtube-content and any bulk wiki creation workflow.

Category 📝 Note Taking

Wiki Ingestion QA

When to use

After any automated wiki page creation pipeline (youtube-content extraction, bulk concept creation, multi-subagent write operations). The youtube-content skill handles creation; this skill handles verification and recovery — the quality gate between "subagents ran" and "wiki is correct."

Trigger signals

  • Wiki paths have changed (2026-08-01 restructure)consume/ and produce/ replace the old flat structure. See references/wiki-consume-produce-architecture.md. Do NOT update skill paths until the restructure executes.
  • A delegate_task batch returns with any status=timeout
  • An anchor concept page links to 5+ other concept pages
  • Multiple subagents created pages and each prepended its own log.md entry
  • The user reports broken wikilinks or "these links don't work"
  • Bulk blog/personal-writing concept extraction (100+ posts across multiple topic clusters using parallel subagents) — see references/bulk-blog-concept-extraction.md for the full inventory→cluster→extract→QA pattern
  • Theme discovery and product ideation (going from 100-300 concept pages to cross-cutting themes, then to book/course/workshop ideas) — see references/theme-discovery-and-product-ideation.md for the concepts→themes→products pipeline
  • Single-cluster manual extraction (<120 posts, one topic cluster, no subagents) — see references/single-agent-manual-extraction.md for the simpler read→check-dup→extract→verify→finalize pattern (validated on 76 and 116 post clusters)
  • Subagent completed but wrote pages to wrong directory — check write_file resolved paths; subagents sometimes write to wiki/concepts/ instead of wiki/writing/concepts/ or vice versa
  • Subagent completed with HTTP model error (e.g., HTTP 401: Model X is not supported) — subagent may have read all posts but created zero pages; re-dispatch needed
  • Batch chat export extraction (ChatGPT/Claude conversation exports → wiki markdown) — see references/chat-export-batch-extraction.md for the manifest→batch→extract pipeline with dual corpus handling, plus the Phase 6 review & reorganize workflow (discard stale, move novel frameworks, synthesise into existing files, merge active execution references)
  • Podcast audio fallback (Pocket Casts episodes with no YouTube mirror) — see references/podcast-audio-fallback.md for RSS feed discovery, Whisper binary location, and highlights-only mode

Wikilink Verification (post-extraction)

After any bulk creation, verify that the anchor page's wikilinks resolve to actual files on disk. This is the single highest-signal quality check — broken wikilinks mean the subagent used wrong filenames.

For highlights pages specifically, see references/highlights-post-write-qa.md which covers timestamp drift, composite quote detection, wikilink reconciliation with sibling-created concept pages, and sibling log corruption cleanup.

Procedure

from hermes_tools import search_files
import re, os

WIKI = "/opt/data/wiki"
ANCHOR_PAGE = "concepts/four-s-curves-2017.md"   # the page with many outbound links

Read the anchor page and extract all [[wikilinks]]

with open(f"{WIKI}/{ANCHOR_PAGE}") as f: content = f.read() links = re.findall(r'\[\[([^\]]+)\]\]', content) concept_links = [l for l in links if l.startswith("concepts/")]

Check each one

broken = [] for link in concept_links: slug = link.split("/", 1)[1] result = search_files(pattern=slug, path=f"{WIKI}/concepts", target="files") if not result["total_count"]: broken.append(link) if broken: print(f"BROKEN WIKILINKS ({len(broken)}):") for b in broken: print(f" ✗ {b}") print("\nLikely matches on disk:") for b in broken: slug = b.split("/", 1)[1] # Try partial match result = search_files(pattern=slug[:20], path=f"{WIKI}/concepts", target="files") for f in result.get("files", []): print(f" → {f}")

Decision tree

Situation Action
0 broken links ✅ Pass — no action
1-2 broken with close matches Fix the wikilinks in the anchor page (patch)
3+ broken Offer the user a re-extraction — the subagent fundamentally misnamed things

Index.md Collision Detection (post-subagent)

When multiple subagents update index.md during the same ingestion (the entity, concepts, and highlights subagents each write their own entries), three failure modes commonly emerge:

1. Duplicate Entries

Each subagent may insert the same page independently. The entity subagent adds entities/timothy-keller to the Entities section, and the concepts subagent also adds it — resulting in two identical lines.

Detection: After all subagents finish, read index.md fully (not paginated). Count occurrences of each new page slug. Any slug appearing more than once is a duplicate. Fix: Use patch with the duplicate line pair as old_string and the single line as new_string.

2. Wrong Alphabetical Ordering

Subagents often insert entries at the top of a section (prepending) instead of the alphabetically-correct position. Example: a highlights page with slug your-plans-gods-plans-timothy-keller inserted before 10-year-futures-vs-whats-happening-now instead of after tony-fadell-lenny-podcast.

Detection: Scan each section (Entities, Concepts, Highlights) top-to-bottom. Entries should be alphabetical by the slug text inside [[...]] after the last slash. Any entry out of order is misplaced. Fix: Use patch to remove the misplaced entry from its wrong position, then patch again to insert it between the two correct neighboring entries.

3. Wrong Page Count

If three subagents each bump the count independently, the total may be too high — or one subagent bumps by its count while another already accounted for shared pages (e.g., the entity page counted by both entity and highlights subagents).

Detection: The header count (Total pages: N) should equal previous_total + count_of_files_actually_written_to_disk. Use search_files with the ingest date or slug pattern to count actual new files. Fix: Patch the header line with the recalculated count.

Procedure (run after all subagents complete)

1. Read index.md fully — no pagination, read the complete file in one call

2. Check for duplicates — scan for repeated wikilinks; fix with patch

3. Check alphabetical order — scan each section; fix misplaced entries

4. Verify page count — count on-disk pages and reconcile with header

5. Re-read index.md after all patches to confirm final state

Subagent Timeout Recovery

When a delegate_task batch returns status=timeout for any child (especially the concepts subagent), it means partial completion: some pages were created but index.md was not updated. Treat this as recoverable, not a failure.

Recovery procedure

Step 1 — Audit what exists:
from hermes_tools import search_files
import os

Find all concept pages sourcing from this transcript slug

result = search_files( path=f"{WIKI}/concepts", pattern="TRANSCRIPT_SLUG", # e.g., "10-year-futures-vs-whats-happening-now" target="content", output_mode="files_only" ) existing = sorted([os.path.basename(f).replace(".md", "") for f in result["files"]]) print(f"Found {len(existing)} existing concept pages")
Step 2 — Integrate into index.md:

The subagent created pages but didn't update index.md. Add entries manually using execute_code:

  • Read current index.md lines
  • Insert new entries alphabetically under ## Concepts
  • Bump the total page count header
  • Write back
Step 3 — Re-dispatch for remaining:

Create a targeted subagent with explicit lists:

ALREADY CREATED (do NOT recreate):
- concepts/page1.md
- concepts/page2.md
...

CREATE THESE:
1. concepts/missing-concept-1.md — description
2. concepts/missing-concept-2.md — description
Step 4 — Finalize:

After re-dispatch, run wikilink verification + log consolidation on the complete set.

Log Consolidation

When 3 subagents each write their own log.md entry, the result is a fragmented log. The parent MUST consolidate.

Procedure

After all subagents complete (including any re-dispatched ones):

1. Read log.md to find the separate entries (they'll be at the top, most recent)

2. Delete the individual subagent entries

3. Prepend ONE unified entry:

## [YYYY-MM-DD] ingest | [Video Title]
- Cost: $Z.ZZ (starting: $A.AA → ending: $B.BB)
- Created: [list all pages by category: entity, highlights, concepts...]
- Updated: index.md (+N pages)

Use patch with old_string matching the first fragmented entry and new_string being the full consolidated block.

Pitfalls

  • Do NOT trust subagent log entries on their own. Each subagent writes its entry in isolation and may claim different page counts, different titles, or duplicate entries. Always consolidate.
  • Sibling subagents produce duplicate and misordered index.md entries. When entity, concepts, and highlights subagents all update index.md independently: (a) they can insert the same page twice, (b) they often prepend entries at the top of a section instead of inserting alphabetically, (c) the total page count is usually wrong. Always run the Index.md Collision Detection checklist above after subagents finish.
  • Subagent timeout ≠ total failure. The subagent likely created 50-80% of pages before timing out. Integrate those partial results — don't delete and restart from scratch.
  • Subagent path discipline is unreliable. Subagents sometimes write to the wrong base directory (e.g., wiki/concepts/ instead of wiki/writing/concepts/). After every batch, run search_files across BOTH wiki roots to catch misplaced pages. Fix with a simple mv from the wrong directory to the correct one. This pattern bit us on the Finance cluster — 15 pages went to the root wiki's concepts/ instead of writing/concepts/.
  • Chat export batch extraction — See references/chat-export-batch-extraction.md for the full manifest→batch→extract pipeline. Key: always dispatch with conversation UUIDs, not titles; regenerate manifests before each batch; handle dual corpus (ChatGPT + Claude) formats.
  • Model errors on subagents ≠ total failure. If a subagent finishes with HTTP 401: Model <name> is not supported or similar provider error, it may have read all posts but created zero pages. Re-dispatch that single cluster with tighter scope. This happened on the Writing cluster (30 posts) — re-dispatch with explicit duplicate-avoidance instructions worked.
  • Batch size sweet spot for subagents: ≤150 posts. At 600s timeout: 130-150 posts complete fully and return results. At 189+ posts, subagents reliably time out but still produce 60-80% of expected output (recoverable). Split clusters above 150 posts before dispatching.
  • execute_code tool has different read_file semantics. Inside execute_code, from hermes_tools import read_file returns a dict with keys like status/message/content_returned, NOT a plain content key. The outer read_file tool is different from the inner Python SDK. When batch-reading files from execute_code, prefer terminal('cat <path>') for reliability — it doesn't deduplicate and the output format is predictable.
  • Subagent output summaries are truncated by the delegation system. When a subagent reports creating many pages, its summary is capped to ~3000 chars to protect the parent's context window. Read the full file at /opt/data/cache/delegation/subagent-summary-<N>-<timestamp>.txt for the complete list.
  • Cost estimates are best-case. The youtube-content skill estimates $0.05-0.10 for <30min videos, but a subagent timeout + re-dispatch can push that to $0.80+. Budget ~2x the estimate for safety.
  • Wikilinks are the canary. If anchor-page wikilinks are broken, the entire extraction is suspect. This one check catches 80% of quality issues.
  • Long transcripts (>1,500 lines) are timeout-prone for the concepts subagent. Consider splitting concepts into two batches proactively (first 10, remaining N) to avoid the 600s timeout.
  • Sibling subagents can write corrupted log entries. When multiple subagents share a video slug, one may write an entry with the wrong title (another video's title), wrong source URL, or mismatched content. After all subagents complete, run search_files(pattern='<slug>', path='WIKI_PATH/log.md') and delete any corrupted entries — the highlights agent's entry is authoritative.
  • read_file deduplicates within a session. Re-reading the same file path returns status: unchanged with no content. When batch-processing a file list inside execute_code, use from hermes_tools import read_file inside the Python loop — this bypasses session-level dedup and returns full content. The outer read_file tool is affected; the Python SDK function is not.