The ONNX crash
I wanted a simple reindex to populate See Also metadata on the garden entries. What I got was a JVM crash.
The engine wouldn’t start — or rather, it would start, but take six minutes instead of twenty-five seconds, then die with a SIGSEGV in ONNX Runtime’s thread pool. The crash stack pointed at pthread_mutex_lock inside EndParallelSectionInternal, which is deep inside the ONNX parallel kernel executor. Not the kind of thing you can fix by restarting.
Claude traced it to a timing issue. Quarkus @Scheduled(every = "6h") fires its first invocation immediately at startup, on a worker thread. The main thread is still loading the BGE-M3 ONNX model at that point. Both threads hit ONNX Runtime’s native thread pool concurrently, and the mutex handling on ARM64 doesn’t survive it.
The fix was one line: delayed = "60s" on the @Scheduled annotation. The first reconcile now waits until the model is fully loaded. The kind of bug where the symptom (slow startup, then crash) points you toward model loading issues, when the actual cause is a threading race you’d never suspect from the annotation name alone.
Manual reindex
With the engine crashing, I couldn’t call gardenReindex through MCP — Claude Code’s MCP client wouldn’t reconnect after the restart. We bypassed it entirely: curl DELETE against Qdrant’s REST API to drop the collection, then echo "" > cursor to reset the ingestion state. The engine picked it up on restart and re-embedded all 4900 entries from scratch.
That took about an hour. One entry at a time, one ONNX forward pass each. At ten times the corpus size this would take a day. I filed an issue against neural-text for batch inference — padding multiple texts into a single forward pass should give a 4-8x improvement.
Subagent-mediated retrieval
The other significant piece: garden search now runs through a dedicated garden-retriever subagent instead of dumping full entries into the main model’s context window. A Haiku agent calls gardenSearch, reads the entries, extracts the relevant passages, and returns a condensed summary. The main model gets fifty lines of distilled insight instead of three thousand lines of raw corpus.
The agent definition lives at ~/.claude/agents/garden-retriever.md — available across all projects. Seven skill files updated across five skills (work-start, java-dev, ts-dev, python-dev, code-review). Forage SEARCH left alone — when you explicitly ask to read a garden entry, you want the full thing.
Closing the backlog
Four issues closed this session. Epic #72 (gardenSearch quality) is down to two passive items: the shadow comparison harness collecting data, and the cleanup issue that fires when it concludes. No active implementation work left under that epic.