Skip to content

journal index doesn't cover voice notes — the 'run journal index to index later' recovery hint is a dead end - #122

Merged
ericmann merged 2 commits into
mainfrom
agent/issue-118
Jul 2, 2026
Merged

ericmann merged 2 commits into
mainfrom
agent/issue-118

Conversation

@claude

@claude claude Bot commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

🤖 Agent-Generated PR

Closes #118
Agent Used: Claude Code
Complexity: medium


Summary

journal index never scanned the voice-note landing zone (log.landing.dir, default logs/), so when land-time indexing failed (e.g. Ollama down) the printed recovery hint — "run journal index to index later" — was a dead end: the note stayed on disk, unindexed, forever. journal index now scans that landing zone and indexes voice notes the same way the land-time path does.

Implementation Notes

  • Added index.WalkVoice(root, logRel, since) in internal/index/walk.go, sharing the existing directory-walk logic with WalkTranscripts via a new private walkLandingDir helper (dedup, not new abstraction — the two walks were already structurally identical). Voice notes only ever land as .md (see internal/log.Filename), so WalkVoice matches .md only.
  • runIndex (cmd/index.go) now walks the voice landing zone after the notes/transcripts passes and indexes each file via internal/log.IndexVoice (the same helper journal log calls at land time), reusing the indexer's stable content-hash diffing — unchanged voice notes are a no-op on re-index, and --rebuild re-embeds them like everything else.
  • noteExcludes now also excludes the voice landing zone from the plain-note walk, mirroring the existing transcripts exclusion. Without this, the voice-note .md file would also get picked up by the regular note walk and re-chunked (by heading) as source=note — a second, differently-chunked copy of the same content living alongside the correct source=voice chunks. Unfiltered journal search already matches every source (Sources: nil = any), so voice notes remain fully searchable without that duplicate.
  • Scope: this only changes the non-watch journal index command, per the issue and acceptance criteria. journal index --watch doesn't drive voice notes through IndexVoice either before or after this change; a landed-while-watching voice note is picked up by the next plain journal index run. Extending live --watch coverage to voice notes is a separate concern and out of scope here.
  • No changes to chunking or the land-time indexing path (out of scope per the issue).

Changes

  • internal/index/walk.go — new WalkVoice (voice landing zone walk), refactored shared logic into walkLandingDir.
  • cmd/index.go — runIndex indexes voice notes via IndexVoice; noteExcludes excludes the voice landing zone from the plain-note walk.
  • cmd/index_test.go — new tests (below).
  • CHANGELOG.md — entry under the in-progress 3.0.2 section.

Testing

Automated:

  • Unit tests added/updated
  • All existing tests pass (go test ./..., go vet ./..., gofmt -l . clean)

New tests in cmd/index_test.go:

  • TestRunIndexRecoversUnindexedVoiceNote — reproduces the issue: force land-time index failure, then run journal index and confirm the note becomes searchable via --source voice; also asserts the plain-note walk scanned 0 files (voice note not double-indexed as source=note).
  • TestRunIndexVoiceNoopReindex — re-running journal index on an already-indexed, unchanged voice note makes zero additional embed calls.
  • TestRunIndexRebuildReembedsVoiceNotes — journal index --rebuild re-embeds voice notes and they remain searchable via --source voice.

Manual testing performed:

  • Ran the full suite locally (go test ./...), go vet ./..., and gofmt -l . — all clean.

Review Checklist

Correctness

  • Code actually solves the issue
  • Acceptance criteria are met
  • Edge cases handled

Code Quality

  • Follows existing codebase patterns
  • Follows project coding standards
  • Naming conventions consistent
  • No unnecessary complexity
  • Comments where needed (but code is self-documenting)

Security

  • Input validation present (n/a — no new external input)
  • No exposed secrets or credentials
  • Data properly sanitized/escaped (n/a)
  • Authentication/authorization checks where needed (n/a)

Performance

  • No obvious N+1 queries
  • Reasonable algorithmic complexity
  • Caching used where appropriate (n/a)
  • No blocking operations in request lifecycle (n/a — CLI command)

Tests

  • Tests actually test behavior (not just coverage)
  • Edge cases covered
  • Failure modes tested

Reviewer Notes

The decision to exclude the voice landing zone from the plain-note walk (so voice notes aren't double-indexed under both source=note and source=voice) is a small scope expansion beyond the letter of the issue, but is necessary for correctness — without it, journal index would silently create a second, wrong-shaped copy of every voice note's content. Flagging this explicitly for review.

Voice notes landed via `journal log` are indexed at land time via
Indexer.IndexVoice; when that fails (e.g. Ollama down) the note is left on
disk with the hint "run `journal index` to index later" — but `journal
index` never scanned the voice-note landing zone, so the hint was a dead
end and the note stayed permanently unindexed.

`journal index` now walks `log.landing.dir` (default `logs/`) with a new
index.WalkVoice, indexing each file through the same IndexVoice chunking
(source=voice) and stable-hash change detection the land-time path uses,
so re-running on unchanged voice notes is a no-op and --rebuild covers
them too. The landing zone is also excluded from the plain-note walk
(mirroring the existing transcripts exclusion) so a voice note isn't
double-indexed as a regular note.

Closes #118

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@claude claude Bot added the agent-generated PR was created by an AI agent label Jul 2, 2026
@ericmann
ericmann merged commit b61197e into main Jul 2, 2026
@ericmann
ericmann deleted the agent/issue-118 branch July 2, 2026 19:41
@claude

claude Bot commented Jul 2, 2026

Copy link
Copy Markdown
Contributor Author

Retro: no durable lesson (merged clean / one-off).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agent-generated PR was created by an AI agent

Projects

None yet

Development

Successfully merging this pull request may close these issues.

journal index doesn't cover voice notes — the 'run journal index to index later' recovery hint is a dead end

1 participant