Skip to content

Content indexer — orchestration, diff, upsert/delete#16

Merged
hendrikebbers merged 3 commits into
mainfrom
feat/008-content-indexer
Jul 12, 2026
Merged

Content indexer — orchestration, diff, upsert/delete#16
hendrikebbers merged 3 commits into
mainfrom
feat/008-content-indexer

Conversation

@herbie-bot

Copy link
Copy Markdown
Collaborator

Summary

ContentIndexer orchestrates the ingestion pipeline for one source through the ContentSourceStrategy seam: Discover → Diff → Fetch → Extract → Index. It diffs discovered lastmod against the state read from the index, fetches only new/changed items, batch-upserts, and deletes documents that 404 or vanished from discovery. Idempotent by stable id, fault-tolerant per page. streamAllDocuments provides a lazy full stream for the bootstrap step (009). This is the reusable engine for specs 009/010.

Spec

  • docs/specs/008-content-indexer/{design,behaviors,steps}.md

Changes

  • ContentIndexer (indexSource + streamAllDocuments), IndexReport
  • ContentIndexStore seam (+ StoredDocument) and MeilisearchContentIndexStore (paged multiSearch, batched addDocuments+waitForTask, deleteDocument)

Deviations (documented in steps.md)

  • BatchWriter is package-private in spring-services, so upsert uses MeilisearchClient.addDocuments batched with waitForTask.
  • Added a ContentIndexStore seam (not in the original design) so orchestration is unit-testable without a live Meilisearch.

Test coverage

  • 10 orchestration scenarios via an in-memory store + test-double strategy (new/unchanged/changed/304/vanished/404/idempotent/skip/dedupe/stream) + parseHits parsing. 90 tests total; spec-review and quality-review clean.

Closes #15

🤖 Generated with Claude Code

- ContentIndexer (@component, gated on meilisearch.enabled): drives
  discover -> diff (lastmod vs stored) -> strategy.fetch -> batch upsert,
  deletes 404s and URLs vanished from discovery; idempotent by stable id,
  fault-tolerant (SKIP one, continue). streamAllDocuments for bootstrap.
- IndexReport(discovered, upserted, unchanged, deleted, skipped).
- ContentIndexStore seam (loadState/upsert/delete + StoredDocument) so the
  orchestration is unit-testable without a live Meilisearch.
- MeilisearchContentIndexStore: paged filtered multiSearch (testable
  parseHits, quote-escaped filter), batched addDocuments + waitForTask,
  deleteDocument. Upsert uses addDocuments because the library BatchWriter
  is package-private.
- Tests: ContentIndexerTest (in-memory store + stub strategy, all behaviors)
  + parseHits parsing. 90 tests green.
- steps.md; refresh CLAUDE.md.

Refs #15
@hendrikebbers hendrikebbers merged commit 9291705 into main Jul 12, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Content indexer — orchestration, diff, upsert/delete

2 participants